--notify=true`
##### Utilizing the config flag
-The config flag can be used to specify the vultr-cli.yaml file path when it's outside the default location. If the file has the `api-key` defined, the CLI will use the vultr-cli.yaml config, otherwise it will default to reading the environment variable for the api key.
+The config flag can be used to specify the vultr-cli.yaml file path when it's outside the default location (default is $HOME/.vultr-cli.yaml). If the file has the `api-key` defined, the CLI will use the vultr-cli.yaml config, otherwise it will default to reading the environment variable for the api key.
`vultr-cli instance list --config /Users/myuser/vultr-cli.yaml`
### Example vultr-cli.yaml config file
+
+Currently the only available field that you can use with a config file is `api-key`. Your yaml file will have a single entry which would be:
+
`api-key: MYKEY`
+### CLI Autocompletion
+`vultr-cli completion` will return autocompletions, but this feature requires setup.
+
+Some guides:
+
+
+Bash:
+ $ source <(yourprogram completion bash)
+
+ To load completions for each session, execute once:
+ Linux:
+ $ yourprogram completion bash > /etc/bash_completion.d/yourprogram
+
+ macOS:
+ $ yourprogram completion bash > /usr/local/etc/bash_completion.d/yourprogram
+
+Zsh:
+ If shell completion is not already enabled in your environment,
+ you will need to enable it. You can execute the following once:
+
+ $ echo "autoload -U compinit; compinit" >> ~/.zshrc
+
+ To load completions for each session, execute once:
+ $ yourprogram completion zsh > "${fpath[1]}/_yourprogram"
+
+ You will need to start a new shell for this setup to take effect.
+
+fish:
+ $ yourprogram completion fish | source
+
+ To load completions for each session, execute once:
+ $ yourprogram completion fish > ~/.config/fish/completions/yourprogram.fish
+
+PowerShell:
+ PS> yourprogram completion powershell | Out-String | Invoke-Expression
+
+ To load completions for every new session, run:
+ PS> yourprogram completion powershell > yourprogram.ps1
+ and source this file from your PowerShell profile.
+
+
## Contributing
Feel free to send pull requests our way! Please see the [contributing guidelines](CONTRIBUTING.md).
diff --git a/cmd/account/account.go b/cmd/account/account.go
index 1564c6ee..f14322f4 100644
--- a/cmd/account/account.go
+++ b/cmd/account/account.go
@@ -1,28 +1,14 @@
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+// Package account provides the account functionality for the CLI
package account
import (
"context"
- "fmt"
- "os"
+ "errors"
"github.com/spf13/cobra"
- "github.com/spf13/viper"
- "github.com/vultr/govultr/v2"
- "github.com/vultr/vultr-cli/pkg/cli"
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+ "github.com/vultr/vultr-cli/v3/pkg/cli"
)
var (
@@ -33,34 +19,23 @@ var (
`
)
-// Interface for account
-type AccountInterface interface {
- Get() (*govultr.Account, error)
- validate(cmd *cobra.Command, args []string)
-}
-
-// Options for account
-type Options struct {
- Base *cli.Base
-}
-
-// NewAccountOptions returns Options struct
-func NewAccountOptions(base *cli.Base) *Options {
- return &Options{Base: base}
-}
-
// NewCmdAccount creates a cobra command for Account
func NewCmdAccount(base *cli.Base) *cobra.Command {
- o := NewAccountOptions(base)
+ o := &options{Base: base}
cmd := &cobra.Command{
Use: "account",
Short: "get account information",
Long: accountLong,
Example: accountExample,
+ PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+ if !o.Base.HasAuth {
+ return errors.New(utils.APIKeyError)
+ }
+ return nil
+ },
Run: func(cmd *cobra.Command, args []string) {
- o.validate(cmd, args)
- account, err := o.Get()
+ account, err := o.get()
o.Base.Printer.Display(&AccountPrinter{Account: account}, err)
},
@@ -69,17 +44,11 @@ func NewCmdAccount(base *cli.Base) *cobra.Command {
return cmd
}
-func (o *Options) validate(cmd *cobra.Command, args []string) {
- o.Base.Printer.Output = viper.GetString("output")
+type options struct {
+ Base *cli.Base
}
-// Get account information
-func (o *Options) Get() (*govultr.Account, error) {
- account, err := o.Base.Client.Account.Get(context.Background())
- if err != nil {
- fmt.Printf("Error getting account information : %v\n", err)
- os.Exit(1)
- }
-
- return account, nil
+func (o *options) get() (*govultr.Account, error) {
+ account, _, err := o.Base.Client.Account.Get(context.Background())
+ return account, err
}
diff --git a/cmd/account/account_test.go b/cmd/account/account_test.go
deleted file mode 100644
index 80118524..00000000
--- a/cmd/account/account_test.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package account
-
-import (
- "context"
- "reflect"
- "testing"
-
- "github.com/vultr/vultr-cli/pkg/cli"
-
- "github.com/vultr/govultr/v2"
-)
-
-type mockVultrAccount struct {
- client *govultr.Client
-}
-
-func (m mockVultrAccount) Get(ctx context.Context) (*govultr.Account, error) {
- return &govultr.Account{
- Balance: 10,
- PendingCharges: 100,
- Name: "John Smith",
- Email: "john@example.com",
- ACL: []string{"manage_users", "subscriptions", "billing"},
- }, nil
-}
-
-func TestNewAccountOptions(t *testing.T) {
- accountOption := NewAccountOptions(&cli.Base{Client: &govultr.Client{Account: mockVultrAccount{nil}}})
-
- ref := reflect.TypeOf(accountOption)
- if _, ok := ref.MethodByName("Get"); !ok {
- t.Errorf("Missing get function")
- }
-
- if _, ok := ref.MethodByName("validate"); ok {
- t.Errorf("validate isn't exported shouldn't be accessible")
- }
-
- aInterface := reflect.TypeOf(new(AccountInterface)).Elem()
- if !ref.Implements(aInterface) {
- t.Errorf("Options does not implement AccountInterface")
- }
-}
-
-func TestNewCmdAccount(t *testing.T) {
- cmd := NewCmdAccount(&cli.Base{Client: &govultr.Client{Account: mockVultrAccount{nil}}})
-
- if cmd.Short != "get account information" {
- t.Errorf("invalid short")
- }
-
- if cmd.Use != "account" {
- t.Errorf("invalid account")
- }
-
-}
-
-func TestOptions_Get(t *testing.T) {
- a := NewAccountOptions(&cli.Base{Client: &govultr.Client{Account: mockVultrAccount{nil}}})
-
- expectedAccount := &govultr.Account{
- Balance: 10,
- PendingCharges: 100,
- Name: "John Smith",
- Email: "john@example.com",
- ACL: []string{"manage_users", "subscriptions", "billing"},
- }
-
- account, _ := a.Get()
-
- if !reflect.DeepEqual(account, expectedAccount) {
- t.Errorf("OSOptions.list returned %v expected %v", account, expectedAccount)
- }
-
-}
diff --git a/cmd/account/printer.go b/cmd/account/printer.go
index adb0f0b9..3bc2774a 100644
--- a/cmd/account/printer.go
+++ b/cmd/account/printer.go
@@ -1,10 +1,11 @@
package account
import (
- "encoding/json"
+ "strconv"
- "github.com/go-yaml/yaml"
- "github.com/vultr/govultr/v2"
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
)
// AccountPrinter ...
@@ -13,35 +14,42 @@ type AccountPrinter struct {
}
// JSON ...
-func (s *AccountPrinter) JSON() []byte {
- prettyJSON, err := json.MarshalIndent(s, "", " ")
- if err != nil {
- panic("move this into byte")
- }
-
- return prettyJSON
+func (a *AccountPrinter) JSON() []byte {
+ return printer.MarshalObject(a, "json")
}
-// Yaml ...
-func (s *AccountPrinter) Yaml() []byte {
- yam, err := yaml.Marshal(s)
- if err != nil {
- panic("move this into byte")
- }
- return yam
+// YAML ...
+func (a *AccountPrinter) YAML() []byte {
+ return printer.MarshalObject(a, "yaml")
}
// Columns ...
-func (a *AccountPrinter) Columns() map[int][]interface{} {
- return map[int][]interface{}{0: {"BALANCE", "PENDING CHARGES", "LAST PAYMENT DATE", "LAST PAYMENT AMOUNT", "NAME", "EMAIL", "ACLS"}}
+func (a *AccountPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "BALANCE",
+ "PENDING CHARGES",
+ "LAST PAYMENT DATE",
+ "LAST PAYMENT AMOUNT",
+ "NAME",
+ "EMAIL",
+ "ACLS",
+ }}
}
// Data ...
-func (a *AccountPrinter) Data() map[int][]interface{} {
- return map[int][]interface{}{0: {a.Account.Balance, a.Account.PendingCharges, a.Account.LastPaymentDate, a.Account.LastPaymentAmount, a.Account.Name, a.Account.Email, a.Account.ACL}}
+func (a *AccountPrinter) Data() [][]string {
+ return [][]string{0: {
+ strconv.FormatFloat(float64(a.Account.Balance), 'f', utils.DecimalPrecision, 32),
+ strconv.FormatFloat(float64(a.Account.PendingCharges), 'f', utils.DecimalPrecision, 32),
+ a.Account.LastPaymentDate,
+ strconv.FormatFloat(float64(a.Account.LastPaymentAmount), 'f', utils.DecimalPrecision, 32),
+ a.Account.Name,
+ a.Account.Email,
+ printer.ArrayOfStringsToString(a.Account.ACL),
+ }}
}
// Paging ...
-func (a *AccountPrinter) Paging() map[int][]interface{} {
+func (a *AccountPrinter) Paging() [][]string {
return nil
}
diff --git a/cmd/applications/applications.go b/cmd/applications/applications.go
index 2529930f..38288e60 100644
--- a/cmd/applications/applications.go
+++ b/cmd/applications/applications.go
@@ -1,28 +1,15 @@
+// Package applications provides the application functionality for the CLI
package applications
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
import (
"context"
+ "fmt"
"github.com/spf13/cobra"
- "github.com/spf13/viper"
- "github.com/vultr/govultr/v2"
- "github.com/vultr/vultr-cli/cmd/printer"
- "github.com/vultr/vultr-cli/cmd/utils"
- "github.com/vultr/vultr-cli/pkg/cli"
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+ "github.com/vultr/vultr-cli/v3/pkg/cli"
)
var (
@@ -45,61 +32,60 @@ var (
`
)
-// Interface for regions
-type Interface interface {
- List() ([]govultr.Application, *govultr.Meta, error)
- validate(cmd *cobra.Command, args []string)
-}
-
-// Options for regions
-type Options struct {
- Base *cli.Base
- Printer *printer.Output
-}
-
-func NewApplicationOptions(base *cli.Base) *Options {
- return &Options{Base: base}
-}
-
// NewCmdApplications creates cobra command for applications
func NewCmdApplications(base *cli.Base) *cobra.Command {
- o := NewApplicationOptions(base)
+ o := &options{Base: base}
+
cmd := &cobra.Command{
Use: "apps",
- Aliases: []string{"a", "application", "applications", "app"},
Short: "display applications",
+ Aliases: []string{"a", "application", "applications", "app"},
Long: appLong,
Example: appExample,
+ PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+ utils.SetOptions(o.Base, cmd, args)
+ return nil
+ },
}
+ // List
list := &cobra.Command{
Use: "list",
- Aliases: []string{"l"},
Short: "list applications",
+ Aliases: []string{"l"},
Long: listLong,
Example: listExample,
- Run: func(cmd *cobra.Command, args []string) {
- o.validate(cmd, args)
- apps, meta, err := o.List()
- data := &printer.Applications{Applications: apps, Meta: meta}
- o.Printer.Display(data, err)
+ RunE: func(cmd *cobra.Command, args []string) error {
+ apps, meta, err := o.list()
+ if err != nil {
+ return fmt.Errorf("error retrieving application list : %v", err)
+ }
+
+ data := &ApplicationsPrinter{Applications: apps, Meta: meta}
+ o.Base.Printer.Display(data, err)
+
+ return nil
},
}
list.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
- list.Flags().IntP("per-page", "p", 100, "(optional) Number of items requested per page. Default is 100 and Max is 500.")
+ list.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ fmt.Sprintf("(optional) Number of items requested per page. Default is %d and Max is 500.", utils.PerPageDefault),
+ )
cmd.AddCommand(list)
return cmd
}
-func (o *Options) validate(cmd *cobra.Command, args []string) {
- o.Base.Printer.Output = viper.GetString("output")
- o.Base.Options = utils.GetPaging(cmd)
- o.Base.Args = args
+type options struct {
+ Base *cli.Base
+ Printer *printer.Output
}
-// List all applications
-func (o *Options) List() ([]govultr.Application, *govultr.Meta, error) {
- return o.Base.Client.Application.List(context.Background(), o.Base.Options)
+func (o *options) list() ([]govultr.Application, *govultr.Meta, error) {
+ list, meta, _, err := o.Base.Client.Application.List(context.Background(), o.Base.Options)
+ return list, meta, err
}
diff --git a/cmd/applications/applications_test.go b/cmd/applications/applications_test.go
deleted file mode 100644
index 3470c373..00000000
--- a/cmd/applications/applications_test.go
+++ /dev/null
@@ -1,91 +0,0 @@
-package applications
-
-import (
- "context"
- "reflect"
- "testing"
-
- "github.com/vultr/vultr-cli/pkg/cli"
-
- "github.com/vultr/govultr/v2"
-)
-
-type mockVultrApplications struct {
- client *govultr.Client
-}
-
-func (m mockVultrApplications) List(ctx context.Context, options *govultr.ListOptions) ([]govultr.Application, *govultr.Meta, error) {
- return []govultr.Application{
- {
- ID: 1,
- Name: "LEMP",
- ShortName: "LEMP",
- DeployName: "Lemp on CentOS 6",
- },
- }, &govultr.Meta{
- Total: 1,
- Links: nil,
- }, nil
-}
-
-func TestOptions_List(t *testing.T) {
- appOption := NewApplicationOptions(&cli.Base{Client: &govultr.Client{Application: mockVultrApplications{nil}}})
-
- expected := []govultr.Application{
- {
- ID: 1,
- Name: "LEMP",
- ShortName: "LEMP",
- DeployName: "Lemp on CentOS 6",
- },
- }
- expectedMeta := &govultr.Meta{
- Total: 1,
- Links: nil,
- }
-
- app, meta, _ := appOption.List()
-
- if !reflect.DeepEqual(expected, app) {
- t.Errorf("AppOptions.list returned %v expected %v", app, expected)
- }
-
- if !reflect.DeepEqual(expectedMeta, meta) {
- t.Errorf("AppOptions.list returned %v expected %v", meta, expectedMeta)
- }
-}
-
-func TestNewApplicationOptions(t *testing.T) {
- appOption := NewApplicationOptions(&cli.Base{Client: &govultr.Client{Application: mockVultrApplications{nil}}})
-
- ref := reflect.TypeOf(appOption)
- if _, ok := ref.MethodByName("List"); !ok {
- t.Errorf("Missing list function")
- }
-
- if _, ok := ref.MethodByName("validate"); ok {
- t.Errorf("validate isn't exported shouldn't be accessible")
- }
-
- pInterface := reflect.TypeOf(new(Interface)).Elem()
- if !ref.Implements(pInterface) {
- t.Errorf("Options does not implement Interface")
- }
-}
-
-func TestNewCmdApplications(t *testing.T) {
- cmd := NewCmdApplications(&cli.Base{Client: &govultr.Client{Application: mockVultrApplications{nil}}})
-
- if cmd.Short != "display applications" {
- t.Errorf("invalid short")
- }
-
- if cmd.Use != "apps" {
- t.Errorf("invalid apps")
- }
-
- alias := []string{"a", "application", "applications", "app"}
- if !reflect.DeepEqual(cmd.Aliases, alias) {
- t.Errorf("expected alias %v got %v", alias, cmd.Aliases)
- }
-}
diff --git a/cmd/applications/printer.go b/cmd/applications/printer.go
new file mode 100644
index 00000000..b24d8613
--- /dev/null
+++ b/cmd/applications/printer.go
@@ -0,0 +1,66 @@
+package applications
+
+import (
+ "strconv"
+
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+)
+
+// ApplicationsPrinter represents the plans data from the API
+type ApplicationsPrinter struct {
+ Applications []govultr.Application `json:"applications"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON provides the JSON formatted byte data
+func (a *ApplicationsPrinter) JSON() []byte {
+ return printer.MarshalObject(a, "json")
+}
+
+// YAML provides the YAML formatted byte data
+func (a *ApplicationsPrinter) YAML() []byte {
+ return printer.MarshalObject(a, "yaml")
+}
+
+// Columns provides the plan columns for the printer
+func (a *ApplicationsPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "NAME",
+ "SHORT NAME",
+ "DEPLOY NAME",
+ "TYPE",
+ "VENDOR",
+ "IMAGE ID",
+ }}
+}
+
+// Data provides the plan data for the printer
+func (a *ApplicationsPrinter) Data() [][]string {
+ var data [][]string
+
+ if len(a.Applications) == 0 {
+ data = append(data, []string{"---", "---", "---", "---", "---", "---", "---"})
+ return data
+ }
+
+ for i := range a.Applications {
+ data = append(data, []string{
+ strconv.Itoa(a.Applications[i].ID),
+ a.Applications[i].Name,
+ a.Applications[i].ShortName,
+ a.Applications[i].DeployName,
+ a.Applications[i].Type,
+ a.Applications[i].Vendor,
+ a.Applications[i].ImageID,
+ })
+ }
+
+ return data
+}
+
+// Paging validates and forms the paging data for output
+func (a *ApplicationsPrinter) Paging() [][]string {
+ return printer.NewPaging(a.Meta.Total, &a.Meta.Links.Next, &a.Meta.Links.Prev).Compose()
+}
diff --git a/cmd/backups.go b/cmd/backups.go
deleted file mode 100644
index c99c6576..00000000
--- a/cmd/backups.go
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cmd
-
-import (
- "context"
- "errors"
- "fmt"
- "os"
-
- "github.com/spf13/cobra"
- "github.com/vultr/vultr-cli/cmd/printer"
-)
-
-// Backups represents the application command
-func Backups() *cobra.Command {
- backupsCmd := &cobra.Command{
- Use: "backups",
- Aliases: []string{"a"},
- Short: "Display backups",
- }
-
- backupsCmd.AddCommand(backupsList, backupsGet)
-
- backupsList.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
- backupsList.Flags().IntP("per-page", "p", 100, "(optional) Number of items requested per page. Default is 100 and Max is 500.")
-
- return backupsCmd
-}
-
-var backupsList = &cobra.Command{
- Use: "list",
- Short: "list backups",
- Aliases: []string{"l"},
- Run: func(cmd *cobra.Command, args []string) {
- options := getPaging(cmd)
- backups, meta, err := client.Backup.List(context.TODO(), options)
- if err != nil {
- fmt.Printf("error getting backups : %v\n", err)
- os.Exit(1)
- }
-
- printer.Backups(backups, meta)
- },
-}
-
-var backupsGet = &cobra.Command{
- Use: "get",
- Short: "get backup",
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a backupID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- backup, err := client.Backup.Get(context.TODO(), args[0])
- if err != nil {
- fmt.Printf("error getting backup : %v\n", err)
- os.Exit(1)
- }
-
- printer.Backup(backup)
- },
-}
diff --git a/cmd/backups/backups.go b/cmd/backups/backups.go
new file mode 100644
index 00000000..8a476f5b
--- /dev/null
+++ b/cmd/backups/backups.go
@@ -0,0 +1,110 @@
+// Package backups provides access to the backups for the CLI
+package backups
+
+import (
+ "errors"
+ "fmt"
+ "os"
+
+ "github.com/spf13/cobra"
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+ "github.com/vultr/vultr-cli/v3/pkg/cli"
+)
+
+var (
+ backupsLong = ``
+ backupsExample = ``
+ listLong = ``
+ listExample = ``
+ getLong = ``
+ getExample = ``
+)
+
+// NewCmdBackups provides the backup command for the CLI
+func NewCmdBackups(base *cli.Base) *cobra.Command {
+ o := &options{Base: base}
+
+ cmd := &cobra.Command{
+ Use: "backups",
+ Aliases: []string{"backup", "b"},
+ Short: "user commands",
+ Long: backupsLong,
+ Example: backupsExample,
+ PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+ utils.SetOptions(o.Base, cmd, args)
+ if !o.Base.HasAuth {
+ return errors.New(utils.APIKeyError)
+ }
+ return nil
+ },
+ }
+
+ // List
+ list := &cobra.Command{
+ Use: "list",
+ Short: "list all backups",
+ Aliases: []string{"l"},
+ Long: listLong,
+ Example: listExample,
+ Run: func(cmd *cobra.Command, args []string) {
+ o.Base.Options = utils.GetPaging(cmd)
+ backups, meta, err := o.list()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving backups list : %v", err))
+ os.Exit(1)
+ }
+ data := &BackupsPrinter{Backups: backups, Meta: meta}
+ o.Base.Printer.Display(data, err)
+ },
+ }
+
+ list.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
+ list.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ fmt.Sprintf("(optional) Number of items requested per page. Default is %d and Max is 500.", utils.PerPageDefault),
+ )
+
+ // Get
+ get := &cobra.Command{
+ Use: "get",
+ Short: "get a backup",
+ Long: getLong,
+ Example: getExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a backup ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ backup, err := o.get()
+ if err != nil {
+ panic(fmt.Errorf("error retrieving backup : %v", err))
+ }
+
+ data := &BackupPrinter{Backup: backup}
+ o.Base.Printer.Display(data, err)
+ },
+ }
+
+ cmd.AddCommand(get, list)
+ return cmd
+}
+
+type options struct {
+ Base *cli.Base
+}
+
+func (b *options) list() ([]govultr.Backup, *govultr.Meta, error) {
+ backups, meta, _, err := b.Base.Client.Backup.List(b.Base.Context, b.Base.Options)
+ return backups, meta, err
+}
+
+func (b *options) get() (*govultr.Backup, error) {
+ backup, _, err := b.Base.Client.Backup.Get(b.Base.Context, b.Base.Args[0])
+ return backup, err
+}
diff --git a/cmd/backups/printer.go b/cmd/backups/printer.go
new file mode 100644
index 00000000..3d123252
--- /dev/null
+++ b/cmd/backups/printer.go
@@ -0,0 +1,99 @@
+package backups
+
+import (
+ "strconv"
+
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+)
+
+// BackupsPrinter ...
+type BackupsPrinter struct {
+ Backups []govultr.Backup `json:"backups"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (b *BackupsPrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BackupsPrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BackupsPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "DATE CREATED",
+ "DESCRIPTION",
+ "SIZE",
+ "STATUS",
+ }}
+}
+
+// Data ...
+func (b *BackupsPrinter) Data() [][]string {
+ data := [][]string{}
+ for i := range b.Backups {
+ data = append(data, []string{
+ b.Backups[i].ID,
+ b.Backups[i].DateCreated,
+ b.Backups[i].Description,
+ strconv.Itoa(b.Backups[i].Size),
+ b.Backups[i].Status,
+ })
+ }
+ return data
+}
+
+// Paging ...
+func (b *BackupsPrinter) Paging() [][]string {
+ return printer.NewPaging(b.Meta.Total, &b.Meta.Links.Next, &b.Meta.Links.Prev).Compose()
+}
+
+// ======================================
+
+// BackupPrinter ...
+type BackupPrinter struct {
+ Backup *govultr.Backup `json:"backup"`
+}
+
+// JSON ...
+func (b *BackupPrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BackupPrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BackupPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "DATE CREATED",
+ "DESCRIPTION",
+ "SIZE",
+ "STATUS",
+ }}
+}
+
+// Data ...
+func (b *BackupPrinter) Data() [][]string {
+ return [][]string{0: {
+ b.Backup.ID,
+ b.Backup.DateCreated,
+ b.Backup.Description,
+ strconv.Itoa(b.Backup.Size),
+ b.Backup.Status,
+ }}
+}
+
+// Paging ...
+func (b *BackupPrinter) Paging() [][]string {
+ return nil
+}
diff --git a/cmd/bareMetal.go b/cmd/bareMetal.go
deleted file mode 100644
index 1f5ddd27..00000000
--- a/cmd/bareMetal.go
+++ /dev/null
@@ -1,406 +0,0 @@
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cmd
-
-import (
- "context"
- "encoding/base64"
- "errors"
- "fmt"
- "os"
-
- "github.com/spf13/cobra"
- "github.com/vultr/govultr/v2"
- "github.com/vultr/vultr-cli/cmd/printer"
-)
-
-// BareMetal represents the baremetal commands
-func BareMetal() *cobra.Command {
- bareMetalCmd := &cobra.Command{
- Use: "bare-metal",
- Short: "bare-metal is used to access bare metal server commands",
- Aliases: []string{"bm"},
- }
-
- bareMetalCmd.AddCommand(
- BareMetalApp(),
- bareMetalBandwidth,
- bareMetalCreate,
- bareMetalDelete,
- bareMetalHalt,
- bareMetalStart,
- bareMetalGet,
- bareMetalGetVNCUrl,
- bareMetalListIPV4,
- bareMetalListIPV6,
- bareMetalList,
- BareMetalOS(),
- bareMetalReboot,
- bareMetalReinstall,
- BareMetalUserData(),
- )
-
- // create server
- bareMetalCreate.Flags().StringP("region", "r", "", "ID of the region where the server will be created.")
- bareMetalCreate.MarkFlagRequired("region")
- bareMetalCreate.Flags().StringP("plan", "p", "", "ID of the plan that the server will subscribe to.")
- bareMetalCreate.MarkFlagRequired("plan")
- bareMetalCreate.Flags().IntP("operatingSystems", "o", 0, "ID of the operating system that will be installed on the server.")
- bareMetalCreate.Flags().StringP("script", "s", "", "(optional) ID of the startup script that will run after the server is created.")
- bareMetalCreate.Flags().StringP("snapshot", "", "", "(optional) ID of the snapshot that the server will be restored from.")
- bareMetalCreate.Flags().StringP("ipv6", "i", "", "(optional) Whether IPv6 is enabled on the server. Possible values: 'yes', 'no'. Defaults to 'no'.")
- bareMetalCreate.Flags().StringP("label", "l", "", "(optional) The label to assign to the server.")
- bareMetalCreate.Flags().StringSliceP("ssh", "k", []string{}, "(optional) Comma separated list of SSH key IDs that will be added to the server.")
- bareMetalCreate.Flags().IntP("app", "a", 0, "(optional) ID of the application that will be installed on the server.")
- bareMetalCreate.Flags().StringP("userdata", "u", "", "(optional) A generic data store, which some provisioning tools and cloud operating systems use as a configuration file.")
- bareMetalCreate.Flags().StringP("notify", "n", "", "(optional) Whether an activation email will be sent when the server is ready. Possible values: 'yes', 'no'. Defaults to 'yes'.")
- bareMetalCreate.Flags().StringP("hostname", "m", "", "(optional) The hostname to assign to the server.")
- bareMetalCreate.Flags().StringP("tag", "t", "", "(optional) The tag to assign to the server.")
- bareMetalCreate.Flags().StringP("ripv4", "v", "", "(optional) IP address of the floating IP to use as the main IP of this server.")
-
- bareMetalList.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
- bareMetalList.Flags().IntP("per-page", "p", 100, "(optional) Number of items requested per page. Default is 100 and Max is 500.")
-
- bareMetalListIPV4.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
- bareMetalListIPV4.Flags().IntP("per-page", "p", 100, "(optional) Number of items requested per page. Default is 100 and Max is 500.")
-
- bareMetalListIPV6.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
- bareMetalListIPV6.Flags().IntP("per-page", "p", 100, "(optional) Number of items requested per page. Default is 100 and Max is 500.")
-
- return bareMetalCmd
-}
-
-var bareMetalCreate = &cobra.Command{
- Use: "create",
- Short: "create a bare metal server",
- Aliases: []string{"c"},
- Run: func(cmd *cobra.Command, args []string) {
- region, _ := cmd.Flags().GetString("region")
- plan, _ := cmd.Flags().GetString("plan")
- osID, _ := cmd.Flags().GetInt("operatingSystems")
- script, _ := cmd.Flags().GetString("script")
- snapshot, _ := cmd.Flags().GetString("snapshot")
- ipv6, _ := cmd.Flags().GetString("ipv6")
- label, _ := cmd.Flags().GetString("label")
- sshKeys, _ := cmd.Flags().GetStringSlice("ssh")
- app, _ := cmd.Flags().GetInt("app")
- userdata, _ := cmd.Flags().GetString("userdata")
- notify, _ := cmd.Flags().GetString("notify")
- hostname, _ := cmd.Flags().GetString("hostname")
- tag, _ := cmd.Flags().GetString("tag")
- ripv4, _ := cmd.Flags().GetString("ripv4")
-
- options := &govultr.BareMetalCreate{
- StartupScriptID: script,
- Plan: plan,
- SnapshotID: snapshot,
- Label: label,
- SSHKeyIDs: sshKeys,
- Hostname: hostname,
- Tag: tag,
- ReservedIPv4: ripv4,
- OsID: osID,
- Region: region,
- AppID: app,
- }
-
- if userdata != "" {
- options.UserData = base64.StdEncoding.EncodeToString([]byte(userdata))
- }
-
- if notify == "yes" {
- options.ActivationEmail = govultr.BoolToBoolPtr(true)
- }
-
- if ipv6 == "yes" {
- options.EnableIPv6 = govultr.BoolToBoolPtr(true)
- }
-
- osOptions := map[string]interface{}{"app_id": app, "snapshot_id": snapshot, "os_id": osID}
- osOption, err := optionCheckBM(osOptions)
-
- if err != nil {
- fmt.Printf("error creating bare metal server : %v\n", err)
- os.Exit(1)
- }
-
- // If no osOptions were selected and osID has a real value then set the osOptions to os_id
- if osOption == "" && osID == 0 {
- fmt.Printf("error creating bare metal server : an app, snapshot, or operatingSystems ID must be provided\n")
- os.Exit(1)
- }
-
- bm, err := client.BareMetalServer.Create(context.TODO(), options)
- if err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- printer.BareMetal(bm)
- },
-}
-
-var bareMetalDelete = &cobra.Command{
- Use: "delete ",
- Short: "Delete a bare metal server",
- Aliases: []string{"destroy"},
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a bareMetalID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- if err := client.BareMetalServer.Delete(context.TODO(), args[0]); err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("deleted bare metal server")
- },
-}
-
-var bareMetalList = &cobra.Command{
- Use: "list",
- Short: "List all bare metal servers.",
- Aliases: []string{"l"},
- Run: func(cmd *cobra.Command, args []string) {
- options := getPaging(cmd)
- list, meta, err := client.BareMetalServer.List(context.TODO(), options)
- if err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- printer.BareMetalList(list, meta)
- },
-}
-
-var bareMetalGet = &cobra.Command{
- Use: "get ",
- Short: "Get a bare metal server by ",
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a bareMetalID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- srv, err := client.BareMetalServer.Get(context.TODO(), args[0])
- if err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- printer.BareMetal(srv)
- },
-}
-
-var bareMetalGetVNCUrl = &cobra.Command{
- Use: "vnc ",
- Short: "Get a bare metal server's VNC url by ",
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a bareMetalID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- vnc, err := client.BareMetalServer.GetVNCUrl(context.TODO(), args[0])
- if err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- fmt.Println(vnc.URL)
- },
-}
-
-var bareMetalBandwidth = &cobra.Command{
- Use: "bandwidth ",
- Short: "Get a bare metal server's bandwidth usage",
- Aliases: []string{"b"},
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a bareMetalID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- bw, err := client.BareMetalServer.GetBandwidth(context.TODO(), args[0])
- if err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- printer.BareMetalBandwidth(bw)
- },
-}
-
-var bareMetalHalt = &cobra.Command{
- Use: "halt ",
- Short: "Halt a bare metal server.",
- Long: `Halt a bare metal server. This is a hard power off, meaning that the power to the machine is severed.
- The data on the machine will not be modified, and you will still be billed for the machine.`,
- Aliases: []string{"h"},
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a bareMetalID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- if err := client.BareMetalServer.Halt(context.TODO(), args[0]); err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("bare metal server halted.")
- },
-}
-
-var bareMetalStart = &cobra.Command{
- Use: "start ",
- Short: "Start a bare metal server.",
- Long: `Start a bare metal server.`,
- Aliases: []string{"h"},
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a bareMetalID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- if err := client.BareMetalServer.Start(context.TODO(), args[0]); err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("bare metal server started.")
- },
-}
-
-var bareMetalListIPV4 = &cobra.Command{
- Use: "ipv4 ",
- Short: "List the IPv4 information of a bare metal server.",
- Long: `List the IPv4 information of a bare metal server. IP information is only available for bare metal servers in the "active" state.`,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a bareMetalID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- options := getPaging(cmd)
- info, meta, err := client.BareMetalServer.ListIPv4s(context.TODO(), args[0], options)
- if err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- printer.BareMetalIPV4Info(info, meta)
- },
-}
-
-var bareMetalListIPV6 = &cobra.Command{
- Use: "ipv6 ",
- Short: "List the IPv6 information of a bare metal server.",
- Long: `List the IPv6 information of a bare metal server. IP information is only available for bare metal servers in the "active" state.`,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a bareMetalID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- options := getPaging(cmd)
- info, meta, err := client.BareMetalServer.ListIPv6s(context.TODO(), args[0], options)
- if err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- printer.BareMetalIPV6Info(info, meta)
- },
-}
-
-var bareMetalReboot = &cobra.Command{
- Use: "reboot ",
- Short: "Reboot a bare metal server. This is a hard reboot, which means that the server is powered off, then back on.",
- Aliases: []string{"r"},
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a bareMetalID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- if err := client.BareMetalServer.Reboot(context.TODO(), args[0]); err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("bare metal server rebooted.")
- },
-}
-
-var bareMetalReinstall = &cobra.Command{
- Use: "reinstall ",
- Short: "Reinstall the operating system on a bare metal server.",
- Long: `Reinstall the operating system on a bare metal server.
- All data will be permanently lost, but the IP address will remain the same. There is no going back from this call.`,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a bareMetalID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- if _, err := client.BareMetalServer.Reinstall(context.TODO(), args[0]); err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("bare metal server reinstalled.")
- },
-}
-
-func optionCheckBM(options map[string]interface{}) (string, error) {
- result := []string{}
-
- for k, v := range options {
- switch v.(type) {
- case int:
- if v != 0 {
- result = append(result, k)
- }
- case string:
- if v != "" {
- result = append(result, k)
- }
- }
- }
-
- if len(result) > 1 {
- return "", fmt.Errorf("Too many options have been selected : %v : please select one", result)
- }
-
- // Return back an empty slice so we can possibly add in osID
- if len(result) == 0 {
- return "", nil
- }
-
- return result[0], nil
-}
diff --git a/cmd/bareMetalApp.go b/cmd/bareMetalApp.go
deleted file mode 100644
index 0d23fcf0..00000000
--- a/cmd/bareMetalApp.go
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cmd
-
-import (
- "context"
- "errors"
- "fmt"
- "os"
- "strconv"
-
- "github.com/spf13/cobra"
- "github.com/vultr/govultr/v2"
- "github.com/vultr/vultr-cli/cmd/printer"
-)
-
-// BareMetalApp represents the baremetal app commands
-func BareMetalApp() *cobra.Command {
- bareMetalAppCmd := &cobra.Command{
- Use: "app",
- Short: "app is used to access bare metal server application commands",
- Aliases: []string{"a"},
- }
-
- bareMetalAppCmd.AddCommand(bareMetalAppChange, bareMetalAppChangeList)
-
- return bareMetalAppCmd
-}
-
-var bareMetalAppChange = &cobra.Command{
- Use: "change ",
- Short: "Change a bare metal server's application",
- Aliases: []string{"c"},
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 2 {
- return errors.New("please provide a bareMetalID and appID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- appID, _ := strconv.Atoi(args[1])
- options := &govultr.BareMetalUpdate{
- AppID: appID,
- }
-
- _, err := client.BareMetalServer.Update(context.TODO(), args[0], options)
- if err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("bare metal server's application changed")
- },
-}
-
-var bareMetalAppChangeList = &cobra.Command{
- Use: "list ",
- Short: "available apps a bare metal server can change to.",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an bareMetalID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- list, err := client.BareMetalServer.GetUpgrades(context.TODO(), id)
-
- if err != nil {
- fmt.Printf("error listing available applications : %v\n", err)
- os.Exit(1)
- }
-
- printer.AppList(list.Applications)
- },
-}
diff --git a/cmd/bareMetalOS.go b/cmd/bareMetalOS.go
deleted file mode 100644
index e945ff48..00000000
--- a/cmd/bareMetalOS.go
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cmd
-
-import (
- "context"
- "errors"
- "fmt"
- "os"
- "strconv"
-
- "github.com/spf13/cobra"
- "github.com/vultr/govultr/v2"
- "github.com/vultr/vultr-cli/cmd/printer"
-)
-
-// BareMetalOS represents the baremetal operating system commands
-func BareMetalOS() *cobra.Command {
- bareMetalOSCmd := &cobra.Command{
- Use: "operatingSystems",
- Short: "operatingSystems is used to access bare metal server operating system commands",
- Aliases: []string{"o"},
- }
-
- bareMetalOSCmd.AddCommand(bareMetalOSChange, bareMetalOSChangeList)
-
- return bareMetalOSCmd
-}
-
-var bareMetalOSChange = &cobra.Command{
- Use: "change ",
- Short: "Change a bare metal server's operating system",
- Aliases: []string{"c"},
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 2 {
- return errors.New("please provide a bareMetalID and osID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- osid, _ := strconv.Atoi(args[1])
- options := &govultr.BareMetalUpdate{
- OsID: osid,
- }
-
- if _, err := client.BareMetalServer.Update(context.TODO(), args[0], options); err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("bare metal server's operating system changed")
- },
-}
-
-var bareMetalOSChangeList = &cobra.Command{
- Use: "list ",
- Short: "available operating systems a bare metal server can change to.",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an bareMetalID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- list, err := client.BareMetalServer.GetUpgrades(context.TODO(), id)
-
- if err != nil {
- fmt.Printf("error listing available operatingSystems : %v\n", err)
- os.Exit(1)
- }
-
- printer.OsList(list.OS)
- },
-}
diff --git a/cmd/bareMetalUserData.go b/cmd/bareMetalUserData.go
deleted file mode 100644
index 9b38cada..00000000
--- a/cmd/bareMetalUserData.go
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cmd
-
-import (
- "context"
- "encoding/base64"
- "errors"
- "fmt"
- "io/ioutil"
- "os"
-
- "github.com/spf13/cobra"
- "github.com/vultr/govultr/v2"
- "github.com/vultr/vultr-cli/cmd/printer"
-)
-
-// BareMetalUserData represents the baremetal userdata commands
-func BareMetalUserData() *cobra.Command {
- bareMetalUserDataCmd := &cobra.Command{
- Use: "user-data",
- Short: "user-data is used to access bare metal server user-data commands",
- Aliases: []string{"u"},
- }
-
- bareMetalSetUserData.Flags().StringP("userdata", "d", "/dev/stdin", "file to read userdata from")
- bareMetalUserDataCmd.AddCommand(bareMetalGetUserData, bareMetalSetUserData)
-
- return bareMetalUserDataCmd
-}
-
-var bareMetalGetUserData = &cobra.Command{
- Use: "get ",
- Short: "Get the user-data of a bare metal server.",
- Aliases: []string{"g"},
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a bareMetalID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- u, err := client.BareMetalServer.GetUserData(context.Background(), args[0])
- if err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- printer.UserData(u)
- },
-}
-
-var bareMetalSetUserData = &cobra.Command{
- Use: "set ",
- Short: "Set the plain text user-data of a bare metal server.",
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a bareMetalID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- userData, _ := cmd.Flags().GetString("userdata")
-
- rawData, err := ioutil.ReadFile(userData)
- if err != nil {
- fmt.Printf("error reading user-data : %v\n", err)
- os.Exit(1)
- }
-
- options := &govultr.BareMetalUpdate{
- UserData: base64.StdEncoding.EncodeToString(rawData),
- }
-
- _, err = client.BareMetalServer.Update(context.TODO(), args[0], options)
- if err != nil {
- fmt.Printf("error setting user-data : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Set user-data for bare metal")
- },
-}
diff --git a/cmd/baremetal/baremetal.go b/cmd/baremetal/baremetal.go
new file mode 100644
index 00000000..13f01d22
--- /dev/null
+++ b/cmd/baremetal/baremetal.go
@@ -0,0 +1,1232 @@
+// Package baremetal provides functionality to perform operations on
+// bare metal servers through the CLI
+package baremetal
+
+import (
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "github.com/spf13/cobra"
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/applications"
+ "github.com/vultr/vultr-cli/v3/cmd/ip"
+ "github.com/vultr/vultr-cli/v3/cmd/operatingsystems"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/userdata"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+ "github.com/vultr/vultr-cli/v3/pkg/cli"
+)
+
+var (
+ long = `Show all commands available to bare-metal`
+ example = `
+ # Full example
+ vultr-cli bare-metal
+ `
+
+ listLong = ``
+ listExample = ``
+ getLong = ``
+ getExample = ``
+ createLong = ``
+ createExample = ``
+ deleteLong = ``
+ deleteExample = ``
+
+ haltLong = `
+ Halt a bare metal server. This is a hard power off, meaning that the power
+ to the machine is severed. The data on the machine will not be modified,
+ and you will still be billed for the machine.
+ `
+
+ haltExample = ``
+
+ startLong = ``
+ startExample = ``
+ rebootLong = `This is a hard reboot, which means that the server is powered off, then back on.`
+ rebootExample = ``
+
+ reinstallLong = `Reinstall the operating system on a bare metal server.
+All data will be permanently lost, but the IP address will remain the same.
+There is no going back from this call.`
+ reinstallExample = ``
+
+ tagsLong = `Update the tags on a bare metal server`
+ tagsExample = `
+ # Full example
+ vultr-cli bare-metal tags tags="tag-1,tag-2"
+
+ # Shortened example with aliases
+ vultr-cli bm tags -t="tag-1,tag-2"
+ `
+
+ vpc2AttachLong = `Attaches an existing VPC 2.0 network to the specified bare metal server`
+ vpc2AttachExample = `
+ # Full example
+ vultr-cli bare-metal vpc2 attach --vpc-id="2126b7d9-5e2a-491e-8840-838aa6b5f294"
+ `
+ vpc2DetachLong = `Detaches an existing VPC 2.0 network from the specified bare metal server`
+ vpc2DetachExample = `
+ # Full example
+ vultr-cli bare-metal vpc2 detach --vpc-id="2126b7d9-5e2a-491e-8840-838aa6b5f294"
+ `
+
+ applicationLong = ``
+ applicationExample = ``
+
+ applicationChangeLong = ``
+ applicationChangeExample = ``
+
+ applicationListLong = ``
+ applicationListExample = ``
+
+ imageLong = ``
+ imageExample = ``
+ imageChangeLong = ``
+ imageChangeExample = ``
+
+ operatingSystemLong = ``
+ operatingSystemExample = ``
+ operatingSystemChangeLong = ``
+ operatingSystemChangeExample = ``
+ operatingSystemListLong = ``
+ operatingSystemListExample = ``
+
+ userDataLong = ``
+ userDataExample = ``
+ userDataGetLong = ``
+ userDataGetExample = ``
+ userDataSetLong = ``
+ userDataSetExample = ``
+
+ vncLong = ``
+ vncExample = ``
+
+ bandwidthLong = ``
+ bandwidthExample = ``
+
+ ipv4Long = `IP information is only available for bare metal servers in the "active" state.`
+ ipv4Example = ``
+
+ ipv6Long = `
+List the IPv6 information of a bare metal server. IP information is only available for bare metal servers in the "active" state.
+`
+ ipv6Example = ``
+
+ vpc2Long = ``
+ vpc2ListLong = ``
+ vpc2ListExample = ``
+)
+
+// NewCmdBareMetal ...
+func NewCmdBareMetal(base *cli.Base) *cobra.Command { //nolint:funlen,gocyclo
+ o := options{Base: base}
+
+ cmd := &cobra.Command{
+ Use: "bare-metal",
+ Short: "Bare metal server commands",
+ Aliases: []string{"bm"},
+ Long: long,
+ Example: example,
+ PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+ utils.SetOptions(o.Base, cmd, args)
+ if !o.Base.HasAuth {
+ return errors.New(utils.APIKeyError)
+ }
+ return nil
+ },
+ }
+
+ // List
+ list := &cobra.Command{
+ Use: "list",
+ Short: "List all bare metal servers.",
+ Aliases: []string{"l"},
+ Long: listLong,
+ Example: listExample,
+ Run: func(cmd *cobra.Command, args []string) {
+ o.Base.Options = utils.GetPaging(cmd)
+ list, meta, err := o.list()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving bare metal list : %v", err))
+ os.Exit(1)
+ }
+ data := &BareMetalsPrinter{BareMetals: list, Meta: meta}
+ o.Base.Printer.Display(data, err)
+ },
+ }
+
+ list.Flags().StringP("cursor", "c", "", "(optional) cursor for paging.")
+ list.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ fmt.Sprintf("(optional) Number of items requested per page. Default is %d and Max is 500.", utils.PerPageDefault),
+ )
+
+ // Get
+ get := &cobra.Command{
+ Use: "get ",
+ Short: "Get a bare metal server by ID",
+ Aliases: []string{"l"},
+ Long: getLong,
+ Example: getExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ bm, err := o.get()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving bare metal : %v", err))
+ os.Exit(1)
+ }
+ data := &BareMetalPrinter{BareMetal: *bm}
+ o.Base.Printer.Display(data, err)
+ },
+ }
+
+ // Create
+ create := &cobra.Command{
+ Use: "create",
+ Short: "Create a bare metal server",
+ Aliases: []string{"c"},
+ Long: createLong,
+ Example: createExample,
+ Run: func(cmd *cobra.Command, args []string) {
+ o.CreateReq = parseCreateFlags(cmd)
+ bm, err := o.create()
+ if err != nil {
+ printer.Error(fmt.Errorf("error with bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ data := &BareMetalPrinter{BareMetal: *bm}
+ o.Base.Printer.Display(data, err)
+ },
+ }
+
+ create.Flags().StringP("region", "r", "", "ID of the region where the server will be created.")
+ create.Flags().StringP("plan", "p", "", "ID of the plan that the server will subscribe to.")
+ create.Flags().Int("os", 0, "ID of the operating system that will be installed on the server.")
+ create.Flags().StringP(
+ "script",
+ "s",
+ "",
+ "(optional) ID of the startup script that will run after the server is created.",
+ )
+ create.Flags().StringP(
+ "snapshot",
+ "",
+ "",
+ "(optional) ID of the snapshot that the server will be restored from.",
+ )
+ create.Flags().StringP(
+ "ipv6",
+ "i",
+ "",
+ "(optional) Whether IPv6 is enabled on the server. Possible values: 'yes', 'no'. Defaults to 'no'.",
+ )
+ create.Flags().StringP("label", "l", "", "(optional) The label to assign to the server.")
+ create.Flags().StringSliceP(
+ "ssh",
+ "k",
+ []string{},
+ "(optional) Comma separated list of SSH key IDs that will be added to the server.",
+ )
+ create.Flags().IntP(
+ "app",
+ "a",
+ 0,
+ "(optional) ID of the application that will be installed on the server.",
+ )
+ create.Flags().StringP("image", "", "", "(optional) Image ID of the application that will be installed on the server.")
+ create.Flags().StringP(
+ "userdata",
+ "u",
+ "",
+ "(optional) A generic data store, which some provisioning tools and cloud operating systems use as a configuration file.",
+ )
+ create.Flags().StringP(
+ "notify",
+ "n",
+ "",
+ "(optional) Whether an activation email will be sent when the server is ready. Possible values: 'yes', 'no'. Defaults to 'yes'.",
+ )
+ create.Flags().StringP("hostname", "m", "", "(optional) The hostname to assign to the server.")
+ create.Flags().StringP("tag", "t", "", "Deprecated: use `tags` instead. (optional) The tag to assign to the server.")
+ create.Flags().StringSliceP("tags", "", []string{}, "(optional) A comma separated list of tags to assign to the server.")
+ create.Flags().StringP("ripv4", "v", "", "(optional) IP address of the floating IP to use as the main IP of this server.")
+ create.Flags().BoolP("persistent_pxe", "x", false, "enable persistent_pxe | true or false")
+
+ if err := create.MarkFlagRequired("region"); err != nil {
+ printer.Error(fmt.Errorf("error marking bare metal create 'region' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ if err := create.MarkFlagRequired("plan"); err != nil {
+ printer.Error(fmt.Errorf("error marking bare metal create 'plan' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ installFlags := []string{"app", "snapshot", "os", "image"}
+ create.MarkFlagsMutuallyExclusive(installFlags...)
+ create.MarkFlagsOneRequired(installFlags...)
+
+ // Delete
+ del := &cobra.Command{
+ Use: "delete ",
+ Short: "Delete a bare metal server",
+ Aliases: []string{"destroy"},
+ Long: deleteLong,
+ Example: deleteExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ if err := o.del(); err != nil {
+ printer.Error(fmt.Errorf("error deleting bare metal : %v", err))
+ os.Exit(1)
+ }
+ o.Base.Printer.Display(printer.Info("bare metal server has been deleted"), nil)
+ },
+ }
+
+ // Halt
+ halt := &cobra.Command{
+ Use: "halt ",
+ Short: "Halt a bare metal server.",
+ Aliases: []string{"h"},
+ Long: haltLong,
+ Example: haltExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ if err := o.halt(); err != nil {
+ printer.Error(fmt.Errorf("error halting bare metal : %v", err))
+ os.Exit(1)
+ }
+ o.Base.Printer.Display(printer.Info("bare metal server has been halted"), nil)
+ },
+ }
+
+ // Start
+ start := &cobra.Command{
+ Use: "start ",
+ Short: "Start a bare metal server.",
+ Long: startLong,
+ Example: startExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ if err := o.start(); err != nil {
+ printer.Error(fmt.Errorf("error starting bare metal : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("bare metal server has been started"), nil)
+ },
+ }
+
+ // Reboot
+ reboot := &cobra.Command{
+ Use: "reboot ",
+ Short: "Reboot a bare metal server.",
+ Aliases: []string{"r"},
+ Long: rebootLong,
+ Example: rebootExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ if err := o.reboot(); err != nil {
+ printer.Error(fmt.Errorf("error rebooting bare metal : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("bare metal server has been rebooted"), nil)
+ },
+ }
+
+ // Reinstall
+ reinstall := &cobra.Command{
+ Use: "reinstall ",
+ Short: "Reinstall the operating system on a bare metal server.",
+ Long: reinstallLong,
+ Example: reinstallExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ if err := o.reinstall(); err != nil {
+ printer.Error(fmt.Errorf("error reinstalling bare metal : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("bare metal server has initiated reinstallation"), nil)
+ },
+ }
+
+ // Application
+ application := &cobra.Command{
+ Use: "app",
+ Short: "app is used to access bare metal server application commands",
+ Aliases: []string{"a", "application"},
+ Long: applicationLong,
+ Example: applicationExample,
+ }
+
+ // Application Change
+ applicationChange := &cobra.Command{
+ Use: "change ",
+ Short: "Change a bare metal server application",
+ Aliases: []string{"c"},
+ Long: applicationChangeLong,
+ Example: applicationChangeExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ appID, err := cmd.Flags().GetInt("app")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing app flag for bare metal app ID change : %v", err))
+ os.Exit(1)
+ }
+
+ o.UpdateReq = &govultr.BareMetalUpdate{
+ AppID: appID,
+ }
+
+ bm, err := o.update()
+ if err != nil {
+ printer.Error(fmt.Errorf("error with bare metal update : %v", err))
+ os.Exit(1)
+ }
+
+ data := &BareMetalPrinter{BareMetal: *bm}
+ o.Base.Printer.Display(data, err)
+ },
+ }
+
+ applicationChange.Flags().IntP(
+ "app",
+ "a",
+ 0,
+ "ID of the application that will be installed on the server",
+ )
+
+ if err := applicationChange.MarkFlagRequired("app"); err != nil {
+ printer.Error(fmt.Errorf("error marking bare metal 'app' flag required : %v", err))
+ os.Exit(1)
+ }
+
+ // Application List
+ applicationList := &cobra.Command{
+ Use: "list ",
+ Short: "Available apps for a bare metal server",
+ Long: applicationListLong,
+ Example: applicationListExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ upgrades, err := o.getUpgrades()
+ if err != nil {
+ printer.Error(fmt.Errorf("error with bare metal get upgrades : %v", err))
+ os.Exit(1)
+ }
+ data := &applications.ApplicationsPrinter{Applications: upgrades.Applications}
+ o.Base.Printer.Display(data, err)
+ },
+ }
+
+ application.AddCommand(applicationChange, applicationList)
+
+ // Image
+ image := &cobra.Command{
+ Use: "image",
+ Short: "image is used to access bare metal server image commands",
+ Aliases: []string{"i"},
+ Long: imageLong,
+ Example: imageExample,
+ }
+
+ // Image Change
+ imageChange := &cobra.Command{
+ Use: "change ",
+ Short: "Change a bare metal server's image",
+ Aliases: []string{"c"},
+ Long: imageChangeLong,
+ Example: imageChangeExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ imageID, err := cmd.Flags().GetString("image")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing image flag for bare metal image change : %v", err))
+ os.Exit(1)
+ }
+
+ o.UpdateReq = &govultr.BareMetalUpdate{
+ ImageID: imageID,
+ }
+
+ bm, err := o.update()
+ if err != nil {
+ printer.Error(fmt.Errorf("error with bare metal image update : %v", err))
+ os.Exit(1)
+ }
+
+ data := &BareMetalPrinter{BareMetal: *bm}
+ o.Base.Printer.Display(data, err)
+ },
+ }
+
+ imageChange.Flags().StringP(
+ "image",
+ "i",
+ "",
+ "ID of the image that will be installed on the server",
+ )
+
+ if err := imageChange.MarkFlagRequired("image"); err != nil {
+ printer.Error(fmt.Errorf("error marking bare metal 'image' flag required : %v", err))
+ os.Exit(1)
+ }
+
+ image.AddCommand(imageChange)
+
+ // OS
+ operatingSystem := &cobra.Command{
+ Use: "os",
+ Short: "Server operating system commands",
+ Aliases: []string{"o"},
+ Long: operatingSystemLong,
+ Example: operatingSystemExample,
+ }
+
+ // OS Change
+ operatingSystemChange := &cobra.Command{
+ Use: "change ",
+ Short: "Change a bare metal server's image",
+ Aliases: []string{"c"},
+ Long: operatingSystemChangeLong,
+ Example: operatingSystemChangeExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ operatingSystemID, err := cmd.Flags().GetInt("os")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing os flag for bare metal os change : %v", err))
+ os.Exit(1)
+ }
+
+ o.UpdateReq = &govultr.BareMetalUpdate{
+ OsID: operatingSystemID,
+ }
+
+ bm, err := o.update()
+ if err != nil {
+ printer.Error(fmt.Errorf("error with bare metal os update : %v", err))
+ os.Exit(1)
+ }
+
+ data := &BareMetalPrinter{BareMetal: *bm}
+ o.Base.Printer.Display(data, err)
+ },
+ }
+
+ operatingSystemChange.Flags().IntP(
+ "os",
+ "o",
+ 0,
+ "ID of the operating system that will be installed on the server",
+ )
+ if err := operatingSystemChange.MarkFlagRequired("os"); err != nil {
+ printer.Error(fmt.Errorf("error marking bare metal 'os' flag required : %v", err))
+ os.Exit(1)
+ }
+
+ // Operating System List
+ operatingSystemList := &cobra.Command{
+ Use: "list ",
+ Short: "Available operating systems for a bare metal server",
+ Long: operatingSystemListLong,
+ Example: operatingSystemListExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ upgrades, err := o.getUpgrades()
+ if err != nil {
+ printer.Error(fmt.Errorf("error with bare metal get upgrades : %v", err))
+ os.Exit(1)
+ }
+
+ data := &operatingsystems.OSPrinter{OperatingSystems: upgrades.OS}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ operatingSystem.AddCommand(operatingSystemChange, operatingSystemList)
+
+ // User Data
+ userData := &cobra.Command{
+ Use: "user-data",
+ Short: "Commands for bare metal server user data",
+ Aliases: []string{"u"},
+ Long: userDataLong,
+ Example: userDataExample,
+ }
+
+ // User Data Get
+ userDataGet := &cobra.Command{
+ Use: "get ",
+ Short: "Get the user data of a bare metal server",
+ Aliases: []string{"g"},
+ Long: userDataGetLong,
+ Example: userDataGetExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ ud, err := o.getUserData()
+ if err != nil {
+ printer.Error(fmt.Errorf("error with bare metal get user data : %v", err))
+ os.Exit(1)
+ }
+
+ data := &userdata.UserDataPrinter{UserData: *ud}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ // User Data Set
+ userDataSet := &cobra.Command{
+ Use: "set ",
+ Short: "Set the plain text user-data of a bare metal server",
+ Long: userDataSetLong,
+ Example: userDataSetExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ path, err := cmd.Flags().GetString("user-data")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing user-data flag for bare metal user data set : %v", err))
+ os.Exit(1)
+ }
+
+ rawData, err := os.ReadFile(filepath.Clean(path))
+ if err != nil {
+ printer.Error(fmt.Errorf("error reading user-data : %v", err))
+ os.Exit(1)
+ }
+
+ o.UpdateReq = &govultr.BareMetalUpdate{
+ UserData: base64.StdEncoding.EncodeToString(rawData),
+ }
+
+ _, errUpdate := o.update()
+ if err != nil {
+ printer.Error(fmt.Errorf("error updating bare metal user-data : %v", errUpdate))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("bare metal server user data has been set"), nil)
+ },
+ }
+
+ userDataSet.Flags().StringP("user-data", "d", "/dev/stdin", "file to read userdata from")
+ if err := userDataSet.MarkFlagRequired("user-data"); err != nil {
+ printer.Error(fmt.Errorf("error marking bare metal 'user-data' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ userData.AddCommand(userDataGet, userDataSet)
+
+ // VNC URL
+ vnc := &cobra.Command{
+ Use: "vnc ",
+ Short: "get a bare metal server's VNC url",
+ Long: vncLong,
+ Example: vncExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ vnc, err := o.getVNCURL()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving bare metal VNC URL : %v", err))
+ os.Exit(1)
+ }
+
+ data := &BareMetalVNCPrinter{VNC: *vnc}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ // Bandwidth
+ bandwidth := &cobra.Command{
+ Use: "bandwidth ",
+ Short: "Get a bare metal server's bandwidth usage",
+ Aliases: []string{"b"},
+ Long: bandwidthLong,
+ Example: bandwidthExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ bw, err := o.getBandwidth()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving bare metal bandwidth usage : %v", err))
+ os.Exit(1)
+ }
+
+ data := &BareMetalBandwidthPrinter{Bandwidth: *bw}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ // Tags
+ tags := &cobra.Command{
+ Use: "tags ",
+ Short: "add or modify tags on the bare metal server.",
+ Long: tagsLong,
+ Example: tagsExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ tags, _ := cmd.Flags().GetStringSlice("tags")
+ o.UpdateReq = &govultr.BareMetalUpdate{
+ Tags: tags,
+ }
+
+ _, err := o.update()
+ if err != nil {
+ printer.Error(fmt.Errorf("error updating bare metal tags : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("bare metal server tags have been updated"), nil)
+ },
+ }
+
+ tags.Flags().StringSliceP("tags", "t", []string{}, "A comma separated list of tags to apply to the server")
+ if err := tags.MarkFlagRequired("tags"); err != nil {
+ printer.Error(fmt.Errorf("error marking bare metal 'tags' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ // IPv4 Addresses
+ ipv4 := &cobra.Command{
+ Use: "ipv4 ",
+ Short: "List the IPv4 information of a bare metal server",
+ Long: ipv4Long,
+ Example: ipv4Example,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ o.Base.Options = utils.GetPaging(cmd)
+ ipv4, meta, err := o.getIPv4Addresses()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving bare metal IPv4 information : %v", err))
+ os.Exit(1)
+ }
+ data := &ip.IPv4sPrinter{IPv4s: ipv4, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ // IPv6 Addresses
+ ipv6 := &cobra.Command{
+ Use: "ipv6 ",
+ Short: "list the IPv6 information of a bare metal server.",
+ Long: ipv6Long,
+ Example: ipv6Example,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ o.Base.Options = utils.GetPaging(cmd)
+ ipv6, meta, err := o.getIPv6Addresses()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving bare metal IPv6 information : %v", err))
+ os.Exit(1)
+ }
+ data := &ip.IPv6sPrinter{IPv6s: ipv6, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ // VPC2
+ vpc2 := &cobra.Command{
+ Use: "vpc2",
+ Short: "commands to manage vpc 2.0 on bare metal servers",
+ Long: vpc2Long,
+ }
+
+ // VPC2 List
+ vpc2List := &cobra.Command{
+ Use: "list ",
+ Short: "List all VPC2 networks attached to a server",
+ Aliases: []string{"l"},
+ Long: vpc2ListLong,
+ Example: vpc2ListExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ vpc2s, err := o.vpc2NetworksList()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving bare metal vpc2 information : %v", err))
+ os.Exit(1)
+ }
+ data := &BareMetalVPC2sPrinter{VPC2s: vpc2s}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ // VPC2 Attach
+ vpc2Attach := &cobra.Command{
+ Use: "attach ",
+ Short: "Attach a VPC2 network to a server",
+ Long: vpc2AttachLong,
+ Example: vpc2AttachExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ vpcID, errID := cmd.Flags().GetString("vpc-id")
+ if errID != nil {
+ printer.Error(fmt.Errorf("error parsing vpc-id flag for bare metal VPC2 attach : %v", errID))
+ os.Exit(1)
+ }
+
+ IPAddress, errIP := cmd.Flags().GetString("ip-address")
+ if errIP != nil {
+ printer.Error(fmt.Errorf("error parsing ip-address flag for bare metal VPC2 attach : %v", errIP))
+ os.Exit(1)
+ }
+
+ o.VPC2Req = &govultr.AttachVPC2Req{
+ VPCID: vpcID,
+ IPAddress: &IPAddress,
+ }
+
+ if err := o.vpc2NetworksAttach(); err != nil {
+ printer.Error(fmt.Errorf("error attaching bare metal to VPC2 : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("bare metal server has been attached to VPC2 network"), nil)
+ },
+ }
+
+ vpc2Attach.Flags().StringP("vpc-id", "v", "", "the ID of the VPC 2.0 network you wish to attach")
+ vpc2Attach.Flags().StringP("ip-address", "i", "", "the IP address to use for this server on the attached VPC 2.0 network")
+ if errVPC := vpc2Attach.MarkFlagRequired("vpc-id"); errVPC != nil {
+ printer.Error(fmt.Errorf("error marking bare metal 'vpc-id' flag required for attach : %v", errVPC))
+ os.Exit(1)
+ }
+
+ // VPC2 Detach
+ vpc2Detach := &cobra.Command{
+ Use: "detach ",
+ Short: "Detach a VPC2 network from a server",
+ Long: vpc2DetachLong,
+ Example: vpc2DetachExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a bare metal ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ vpcID, errID := cmd.Flags().GetString("vpc-id")
+ if errID != nil {
+ printer.Error(fmt.Errorf("error parsing vpc-id flag for bare metal VPC2 detach : %v", errID))
+ os.Exit(1)
+ }
+
+ o.VPC2ID = vpcID
+ if err := o.vpc2NetworksDetach(); err != nil {
+ printer.Error(fmt.Errorf("error detaching bare metal VPC2 : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("bare metal server has been detached from VPC2 network"), nil)
+ },
+ }
+
+ vpc2Detach.Flags().StringP("vpc-id", "v", "", "the ID of the VPC 2.0 network you wish to detach")
+ if errVPC2 := vpc2Detach.MarkFlagRequired("vpc-id"); errVPC2 != nil {
+ printer.Error(fmt.Errorf("error marking bare metal 'vpc-id' flag required for detach : %v", errVPC2))
+ os.Exit(1)
+ }
+
+ vpc2.AddCommand(vpc2List, vpc2Attach, vpc2Detach)
+
+ cmd.AddCommand(
+ get,
+ list,
+ create,
+ del,
+ halt,
+ start,
+ reboot,
+ reinstall,
+ application,
+ image,
+ operatingSystem,
+ userData,
+ vnc,
+ bandwidth,
+ tags,
+ ipv4,
+ ipv6,
+ vpc2,
+ )
+
+ return cmd
+}
+
+type options struct {
+ Base *cli.Base
+ CreateReq *govultr.BareMetalCreate
+ UpdateReq *govultr.BareMetalUpdate
+ VPC2Req *govultr.AttachVPC2Req
+ VPC2ID string
+}
+
+func (b *options) list() ([]govultr.BareMetalServer, *govultr.Meta, error) {
+ bms, meta, _, err := b.Base.Client.BareMetalServer.List(b.Base.Context, b.Base.Options)
+ return bms, meta, err
+}
+
+func (b *options) get() (*govultr.BareMetalServer, error) {
+ bm, _, err := b.Base.Client.BareMetalServer.Get(b.Base.Context, b.Base.Args[0])
+ return bm, err
+}
+
+func (b *options) create() (*govultr.BareMetalServer, error) {
+ bm, _, err := b.Base.Client.BareMetalServer.Create(b.Base.Context, b.CreateReq)
+ return bm, err
+}
+
+func (b *options) update() (*govultr.BareMetalServer, error) {
+ bm, _, err := b.Base.Client.BareMetalServer.Update(b.Base.Context, b.Base.Args[0], b.UpdateReq)
+ return bm, err
+}
+
+func (b *options) del() error {
+ return b.Base.Client.BareMetalServer.Delete(b.Base.Context, b.Base.Args[0])
+}
+
+func (b *options) halt() error {
+ return b.Base.Client.BareMetalServer.Halt(b.Base.Context, b.Base.Args[0])
+}
+
+func (b *options) start() error {
+ return b.Base.Client.BareMetalServer.Start(b.Base.Context, b.Base.Args[0])
+}
+
+func (b *options) reboot() error {
+ return b.Base.Client.BareMetalServer.Reboot(b.Base.Context, b.Base.Args[0])
+}
+
+func (b *options) reinstall() error {
+ _, _, err := b.Base.Client.BareMetalServer.Reinstall(b.Base.Context, b.Base.Args[0])
+ return err
+}
+
+func (b *options) getUpgrades() (*govultr.Upgrades, error) {
+ list, _, err := b.Base.Client.BareMetalServer.GetUpgrades(b.Base.Context, b.Base.Args[0])
+ return list, err
+}
+
+func (b *options) getUserData() (*govultr.UserData, error) {
+ ud, _, err := b.Base.Client.BareMetalServer.GetUserData(b.Base.Context, b.Base.Args[0])
+ return ud, err
+}
+
+func (b *options) getVNCURL() (*govultr.VNCUrl, error) {
+ url, _, err := b.Base.Client.BareMetalServer.GetVNCUrl(b.Base.Context, b.Base.Args[0])
+ return url, err
+}
+
+func (b *options) getBandwidth() (*govultr.Bandwidth, error) {
+ bw, _, err := b.Base.Client.BareMetalServer.GetBandwidth(b.Base.Context, b.Base.Args[0])
+ return bw, err
+}
+
+func (b *options) getIPv4Addresses() ([]govultr.IPv4, *govultr.Meta, error) {
+ ips, meta, _, err := b.Base.Client.BareMetalServer.ListIPv4s(b.Base.Context, b.Base.Args[0], b.Base.Options)
+ return ips, meta, err
+}
+
+func (b *options) getIPv6Addresses() ([]govultr.IPv6, *govultr.Meta, error) {
+ ips, meta, _, err := b.Base.Client.BareMetalServer.ListIPv6s(b.Base.Context, b.Base.Args[0], b.Base.Options)
+ return ips, meta, err
+}
+
+func (b *options) vpc2NetworksList() ([]govultr.VPC2Info, error) {
+ vpc2s, _, err := b.Base.Client.BareMetalServer.ListVPC2Info(b.Base.Context, b.Base.Args[0])
+ return vpc2s, err
+}
+
+func (b *options) vpc2NetworksAttach() error {
+ return b.Base.Client.BareMetalServer.AttachVPC2(b.Base.Context, b.Base.Args[0], b.VPC2Req)
+}
+
+func (b *options) vpc2NetworksDetach() error {
+ return b.Base.Client.BareMetalServer.DetachVPC2(b.Base.Context, b.Base.Args[0], b.VPC2ID)
+}
+
+// ============================
+
+func parseCreateFlags(cmd *cobra.Command) *govultr.BareMetalCreate { //nolint:funlen,gocyclo
+ region, err := cmd.Flags().GetString("region")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing region flag for bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ plan, err := cmd.Flags().GetString("plan")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing plan flag for bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ osID, err := cmd.Flags().GetInt("os")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing os flag for bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ script, err := cmd.Flags().GetString("script")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing script flag bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ snapshot, err := cmd.Flags().GetString("snapshot")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing snapshot flag for bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ ipv6, err := cmd.Flags().GetString("ipv6")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing ipv6 flag for bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ label, err := cmd.Flags().GetString("label")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing label flag for bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ sshKeys, err := cmd.Flags().GetStringSlice("ssh")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing ssh flag for bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ app, err := cmd.Flags().GetInt("app")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing app flag for bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ userdata, err := cmd.Flags().GetString("userdata")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing userdata flag for bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ notify, err := cmd.Flags().GetString("notify")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing notify flag for bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ hostname, err := cmd.Flags().GetString("hostname")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing hostname flag for bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ tags, err := cmd.Flags().GetStringSlice("tags")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing tags flag for bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ ripv4, err := cmd.Flags().GetString("ripv4")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing ripv4 flag for bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ pxe, err := cmd.Flags().GetBool("persistenterrpxe")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing persistenterrpxe flag for bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ image, err := cmd.Flags().GetString("image")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing image flag for bare metal create : %v", err))
+ os.Exit(1)
+ }
+
+ options := &govultr.BareMetalCreate{
+ StartupScriptID: script,
+ Plan: plan,
+ SnapshotID: snapshot,
+ AppID: app,
+ OsID: osID,
+ ImageID: image,
+ Label: label,
+ SSHKeyIDs: sshKeys,
+ Hostname: hostname,
+ Tags: tags,
+ ReservedIPv4: ripv4,
+ Region: region,
+ PersistentPxe: govultr.BoolToBoolPtr(pxe),
+ }
+ if userdata != "" {
+ options.UserData = base64.StdEncoding.EncodeToString([]byte(userdata))
+ }
+
+ if notify == "yes" {
+ options.ActivationEmail = govultr.BoolToBoolPtr(true)
+ }
+
+ if ipv6 == "yes" {
+ options.EnableIPv6 = govultr.BoolToBoolPtr(true)
+ }
+
+ return options
+}
+
+func parseUpdateFlags(cmd *cobra.Command) *govultr.BareMetalUpdate { //nolint:unused
+ osID, err := cmd.Flags().GetInt("os")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing os flag for bare metal update : %v", err))
+ os.Exit(1)
+ }
+
+ label, err := cmd.Flags().GetString("label")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing label flag for bare metal update : %v", err))
+ os.Exit(1)
+ }
+
+ app, err := cmd.Flags().GetInt("app")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing app flag for bare metal update : %v", err))
+ os.Exit(1)
+ }
+
+ userdata, err := cmd.Flags().GetString("userdata")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing userdata flag for bare metal update : %v", err))
+ os.Exit(1)
+ }
+
+ tags, err := cmd.Flags().GetStringSlice("tags")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing tags flag for bare metal update : %v", err))
+ os.Exit(1)
+ }
+
+ image, err := cmd.Flags().GetString("image")
+ if err != nil {
+ printer.Error(fmt.Errorf("error parsing image flag for bare metal update : %v", err))
+ os.Exit(1)
+ }
+
+ options := &govultr.BareMetalUpdate{
+ AppID: app,
+ OsID: osID,
+ ImageID: image,
+ Label: label,
+ Tags: tags,
+ }
+ if userdata != "" {
+ options.UserData = base64.StdEncoding.EncodeToString([]byte(userdata))
+ }
+
+ return options
+}
diff --git a/cmd/baremetal/printer.go b/cmd/baremetal/printer.go
new file mode 100644
index 00000000..1a67c367
--- /dev/null
+++ b/cmd/baremetal/printer.go
@@ -0,0 +1,262 @@
+package baremetal
+
+import (
+ "strconv"
+
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+)
+
+// BareMetalsPrinter ...
+type BareMetalsPrinter struct {
+ BareMetals []govultr.BareMetalServer `json:"bare_metals"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (b *BareMetalsPrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BareMetalsPrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BareMetalsPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "IP",
+ "TAG",
+ "MAC ADDRESS",
+ "LABEL",
+ "OS",
+ "STATUS",
+ "REGION",
+ "CPU",
+ "RAM",
+ "DISK",
+ "FEATURES",
+ "TAGS",
+ }}
+}
+
+// Data ...
+func (b *BareMetalsPrinter) Data() [][]string {
+ var data [][]string
+ for i := range b.BareMetals {
+ data = append(data, []string{
+ b.BareMetals[i].ID,
+ b.BareMetals[i].MainIP,
+ b.BareMetals[i].Tag, //nolint: staticcheck
+ strconv.Itoa(b.BareMetals[i].MacAddress),
+ b.BareMetals[i].Label,
+ b.BareMetals[i].Os,
+ b.BareMetals[i].Status,
+ b.BareMetals[i].Region,
+ strconv.Itoa(b.BareMetals[i].CPUCount),
+ b.BareMetals[i].RAM,
+ b.BareMetals[i].Disk,
+ printer.ArrayOfStringsToString(b.BareMetals[i].Features),
+ printer.ArrayOfStringsToString(b.BareMetals[i].Tags),
+ })
+ }
+ return data
+}
+
+// Paging ...
+func (b *BareMetalsPrinter) Paging() [][]string {
+ return printer.NewPaging(b.Meta.Total, &b.Meta.Links.Next, &b.Meta.Links.Prev).Compose()
+}
+
+// ======================================
+
+// BareMetalPrinter ...
+type BareMetalPrinter struct {
+ BareMetal govultr.BareMetalServer `json:"bare_metal"`
+}
+
+// JSON ...
+func (b *BareMetalPrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BareMetalPrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BareMetalPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "IP",
+ "TAG",
+ "MAC ADDRESS",
+ "LABEL",
+ "OS",
+ "STATUS",
+ "REGION",
+ "CPU",
+ "RAM",
+ "DISK",
+ "FEATURES",
+ "TAGS",
+ }}
+}
+
+// Data ...
+func (b *BareMetalPrinter) Data() [][]string {
+ return [][]string{0: {
+ b.BareMetal.ID,
+ b.BareMetal.MainIP,
+ b.BareMetal.Tag, //nolint: staticcheck
+ strconv.Itoa(b.BareMetal.MacAddress),
+ b.BareMetal.Label,
+ b.BareMetal.Os,
+ b.BareMetal.Status,
+ b.BareMetal.Region,
+ strconv.Itoa(b.BareMetal.CPUCount),
+ b.BareMetal.RAM,
+ b.BareMetal.Disk,
+ printer.ArrayOfStringsToString(b.BareMetal.Features),
+ printer.ArrayOfStringsToString(b.BareMetal.Tags),
+ }}
+}
+
+// Paging ...
+func (b *BareMetalPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// BareMetalVNCPrinter ...
+type BareMetalVNCPrinter struct {
+ VNC govultr.VNCUrl `json:"vnc"`
+}
+
+// JSON ...
+func (b *BareMetalVNCPrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BareMetalVNCPrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BareMetalVNCPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "URL",
+ }}
+}
+
+// Data ...
+func (b *BareMetalVNCPrinter) Data() [][]string {
+ return [][]string{0: {
+ b.VNC.URL,
+ }}
+}
+
+// Paging ...
+func (b *BareMetalVNCPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// BareMetalBandwidthPrinter ...
+type BareMetalBandwidthPrinter struct {
+ Bandwidth govultr.Bandwidth `json:"all_bandwidth"`
+}
+
+// JSON ...
+func (b *BareMetalBandwidthPrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BareMetalBandwidthPrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BareMetalBandwidthPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "DATE",
+ "INCOMING BYTES",
+ "OUTGOING BYTES",
+ }}
+}
+
+// Data ...
+func (b *BareMetalBandwidthPrinter) Data() [][]string {
+ var data [][]string
+ for k := range b.Bandwidth.Bandwidth {
+ data = append(data, []string{
+ k,
+ strconv.Itoa(b.Bandwidth.Bandwidth[k].IncomingBytes),
+ strconv.Itoa(b.Bandwidth.Bandwidth[k].OutgoingBytes),
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (b *BareMetalBandwidthPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// BareMetalVPC2sPrinter ...
+type BareMetalVPC2sPrinter struct {
+ VPC2s []govultr.VPC2Info `json:"vpcs"`
+}
+
+// JSON ...
+func (b *BareMetalVPC2sPrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BareMetalVPC2sPrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BareMetalVPC2sPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "MAC ADDRESS",
+ "IP ADDRESS",
+ }}
+}
+
+// Data ...
+func (b *BareMetalVPC2sPrinter) Data() [][]string {
+ var data [][]string
+
+ if len(b.VPC2s) == 0 {
+ return [][]string{0: {"---", "---", "---"}}
+ }
+
+ for i := range b.VPC2s {
+ data = append(data, []string{
+ b.VPC2s[i].ID,
+ b.VPC2s[i].MacAddress,
+ b.VPC2s[i].IPAddress,
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (b *BareMetalVPC2sPrinter) Paging() [][]string {
+ return nil
+}
diff --git a/cmd/billing/billing.go b/cmd/billing/billing.go
new file mode 100644
index 00000000..f618721e
--- /dev/null
+++ b/cmd/billing/billing.go
@@ -0,0 +1,275 @@
+// Package billing provides the billing commands for the CLI
+package billing
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "strconv"
+
+ "github.com/spf13/cobra"
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+ "github.com/vultr/vultr-cli/v3/pkg/cli"
+)
+
+var (
+ long = `Get all available commands for billing`
+ example = `
+ # Full example
+ vultr-cli billing
+ `
+
+ historyLong = `Get all available commands for billing history`
+ historyExample = `
+ # Full example
+ vultr-cli billing history
+
+ # Shortened with alias commands
+ vultr-cli billing h
+ `
+
+ historyListLong = `Retrieve a list of all billing history on your account`
+ historyListExample = `
+ # Full example
+ vultr-cli billing history list
+
+ # Shortened with alias commands
+ vultr-cli billing h l
+ `
+
+ invoicesLong = `Get all available commands for billing invoices`
+ invoicesExample = `
+ # Full example
+ vultr-cli billing invoice
+
+ # Shortened with alias commands
+ vultr-cli billing i
+ `
+
+ invoiceListLong = `Retrieve a list of all invoices on your account`
+ invoiceListExample = `
+ # Full example
+ vultr-cli billing invoice list
+
+ # Shortened with alias commands
+ vultr-cli billing i l
+ `
+
+ invoiceGetLong = `Get a specific invoice on your account`
+ invoiceGetExample = `
+ # Full example
+ vultr-cli billing invoice get 123456
+
+ # Shortened with alias commands
+ vultr-cli billing i g 123456
+ `
+
+ invoiceItemsListLong = `Retrieve a list of invoice items from a specific invoice on your account`
+ invoiceItemsListExample = `
+ # Full example
+ vultr-cli billing invoice items 123456
+
+ # Shortened with alias commands
+ vultr-cli billing i i 123456
+ `
+)
+
+func NewCmdBilling(base *cli.Base) *cobra.Command {
+ o := &options{Base: base}
+
+ cmd := &cobra.Command{
+ Use: "billing",
+ Short: "display billing information",
+ Long: long,
+ Example: example,
+ PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+ utils.SetOptions(o.Base, cmd, args)
+ if !o.Base.HasAuth {
+ return errors.New(utils.APIKeyError)
+ }
+ return nil
+ },
+ }
+
+ // Invoice
+ invoice := &cobra.Command{
+ Use: "invoice",
+ Aliases: []string{"i"},
+ Short: "display invoice information",
+ Long: invoicesLong,
+ Example: invoicesExample,
+ }
+
+ // Invoice List
+ invoicesList := &cobra.Command{
+ Use: "list",
+ Short: "list billing invoices",
+ Aliases: []string{"l"},
+ Long: invoiceListLong,
+ Example: invoiceListExample,
+ Run: func(cmd *cobra.Command, args []string) {
+ o.Base.Options = utils.GetPaging(cmd)
+ invs, meta, err := o.listInvoices()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving billing invoice list : %v", err))
+ os.Exit(1)
+ }
+ data := &BillingInvoicesPrinter{Invoices: invs, Meta: meta}
+ o.Base.Printer.Display(data, err)
+ },
+ }
+
+ invoicesList.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
+ invoicesList.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ "(optional) Number of items requested per page. Default is 100 and Max is 500.",
+ )
+
+ // Invoice Get
+ invoiceGet := &cobra.Command{
+ Use: "get",
+ Short: "get invoice",
+ Aliases: []string{"g"},
+ Long: invoiceGetLong,
+ Example: invoiceGetExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an invoice ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ inv, err := o.get()
+ if err != nil {
+ printer.Error(fmt.Errorf("error getting invoice : %v", err))
+ os.Exit(1)
+ }
+
+ data := &BillingInvoicePrinter{Invoice: *inv}
+ o.Base.Printer.Display(data, err)
+ },
+ }
+
+ // Invoice Items List
+ invoiceItemsList := &cobra.Command{
+ Use: "items ",
+ Short: "list invoice items",
+ Aliases: []string{"i"},
+ Long: invoiceItemsListLong,
+ Example: invoiceItemsListExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an invoice ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ o.Base.Options = utils.GetPaging(cmd)
+ id, errConv := strconv.Atoi(args[0])
+ if errConv != nil {
+ printer.Error(fmt.Errorf("error converting invoice item id : %v", errConv))
+ os.Exit(1)
+ }
+
+ o.InvoiceItemID = id
+
+ items, meta, err := o.listInvoiceItems()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving billing invoice item list : %v", err))
+ os.Exit(1)
+ }
+ data := &BillingInvoiceItemsPrinter{InvoiceItems: items, Meta: meta}
+ o.Base.Printer.Display(data, err)
+ },
+ }
+
+ invoiceItemsList.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
+ invoiceItemsList.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ fmt.Sprintf("(optional) Number of items requested per page. Default is %d and Max is 500.", utils.PerPageDefault),
+ )
+
+ invoice.AddCommand(
+ invoicesList,
+ invoiceGet,
+ invoiceItemsList,
+ )
+
+ // History
+ history := &cobra.Command{
+ Use: "history",
+ Aliases: []string{"h"},
+ Short: "display billing history information",
+ Long: historyLong,
+ Example: historyExample,
+ }
+
+ // History List
+ historyList := &cobra.Command{
+ Use: "list",
+ Short: "list billing history",
+ Aliases: []string{"l"},
+ Long: historyListLong,
+ Example: historyListExample,
+ Run: func(cmd *cobra.Command, args []string) {
+ o.Base.Options = utils.GetPaging(cmd)
+ hs, meta, err := o.listHistory()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving billing history list : %v", err))
+ os.Exit(1)
+ }
+ data := &BillingHistoryPrinter{Billing: hs, Meta: meta}
+ o.Base.Printer.Display(data, err)
+ },
+ }
+
+ historyList.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
+ historyList.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ "(optional) Number of items requested per page. Default is 100 and Max is 500.",
+ )
+
+ history.AddCommand(
+ historyList,
+ )
+
+ cmd.AddCommand(
+ history,
+ invoice,
+ )
+
+ return cmd
+}
+
+type options struct {
+ Base *cli.Base
+ InvoiceItemID int
+}
+
+func (b *options) listHistory() ([]govultr.History, *govultr.Meta, error) {
+ hs, meta, _, err := b.Base.Client.Billing.ListHistory(b.Base.Context, b.Base.Options)
+ return hs, meta, err
+}
+
+func (b *options) get() (*govultr.Invoice, error) {
+ inv, _, err := b.Base.Client.Billing.GetInvoice(b.Base.Context, b.Base.Args[0])
+ return inv, err
+}
+
+func (b *options) listInvoices() ([]govultr.Invoice, *govultr.Meta, error) {
+ invs, meta, _, err := b.Base.Client.Billing.ListInvoices(b.Base.Context, b.Base.Options)
+ return invs, meta, err
+}
+
+func (b *options) listInvoiceItems() ([]govultr.InvoiceItem, *govultr.Meta, error) {
+ items, meta, _, err := b.Base.Client.Billing.ListInvoiceItems(b.Base.Context, b.InvoiceItemID, b.Base.Options)
+ return items, meta, err
+}
diff --git a/cmd/billing/printer.go b/cmd/billing/printer.go
new file mode 100644
index 00000000..fdb9a030
--- /dev/null
+++ b/cmd/billing/printer.go
@@ -0,0 +1,221 @@
+// Package billing provides the account billing operations and
+// functionality for the CLI
+package billing
+
+import (
+ "strconv"
+
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+)
+
+// BillingHistoryPrinter ...
+type BillingHistoryPrinter struct {
+ Billing []govultr.History `json:"billing_history"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (b *BillingHistoryPrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BillingHistoryPrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BillingHistoryPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "DATE",
+ "TYPE",
+ "DESCRIPTION",
+ "AMOUNT",
+ "BALANCE",
+ }}
+}
+
+// Data ...
+func (b *BillingHistoryPrinter) Data() [][]string {
+ if len(b.Billing) == 0 {
+ return [][]string{0: {"---", "---", "---", "---", "---", "---"}}
+ }
+
+ var data [][]string
+ for i := range b.Billing {
+ data = append(data, []string{
+ strconv.Itoa(b.Billing[i].ID),
+ b.Billing[i].Date,
+ b.Billing[i].Type,
+ b.Billing[i].Description,
+ strconv.FormatFloat(float64(b.Billing[i].Amount), 'f', utils.DecimalPrecision, 32),
+ strconv.FormatFloat(float64(b.Billing[i].Balance), 'f', utils.DecimalPrecision, 32),
+ })
+ }
+ return data
+}
+
+// Paging ...
+func (b *BillingHistoryPrinter) Paging() [][]string {
+ return printer.NewPaging(b.Meta.Total, &b.Meta.Links.Next, &b.Meta.Links.Prev).Compose()
+}
+
+// ======================================
+
+// BillingInvoicesPrinter ...
+type BillingInvoicesPrinter struct {
+ Invoices []govultr.Invoice `json:"billing_invoices"`
+ Meta *govultr.Meta
+}
+
+// JSON ...
+func (b *BillingInvoicesPrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BillingInvoicesPrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BillingInvoicesPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "DATE",
+ "DESCRIPTION",
+ "AMOUNT",
+ "BALANCE",
+ }}
+}
+
+// Data ...
+func (b *BillingInvoicesPrinter) Data() [][]string {
+ if len(b.Invoices) == 0 {
+ return [][]string{0: {"---", "---", "---", "---", "---"}}
+ }
+
+ var data [][]string
+ for i := range b.Invoices {
+ data = append(data, []string{
+ strconv.Itoa(b.Invoices[i].ID),
+ b.Invoices[i].Date,
+ b.Invoices[i].Description,
+ strconv.FormatFloat(float64(b.Invoices[i].Amount), 'f', utils.DecimalPrecision, 32),
+ strconv.FormatFloat(float64(b.Invoices[i].Balance), 'f', utils.DecimalPrecision, 32),
+ })
+ }
+ return data
+}
+
+// Paging ...
+func (b *BillingInvoicesPrinter) Paging() [][]string {
+ return printer.NewPaging(b.Meta.Total, &b.Meta.Links.Next, &b.Meta.Links.Prev).Compose()
+}
+
+// ======================================
+
+// BillingInvoicePrinter ...
+type BillingInvoicePrinter struct {
+ Invoice govultr.Invoice `json:"billing_invoice"`
+}
+
+// JSON ...
+func (b *BillingInvoicePrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BillingInvoicePrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BillingInvoicePrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "DATE",
+ "DESCRIPTION",
+ "AMOUNT",
+ "BALANCE",
+ }}
+}
+
+// Data ...
+func (b *BillingInvoicePrinter) Data() [][]string {
+ return [][]string{0: {
+ strconv.Itoa(b.Invoice.ID),
+ b.Invoice.Date,
+ b.Invoice.Description,
+ strconv.FormatFloat(float64(b.Invoice.Amount), 'f', utils.DecimalPrecision, 32),
+ strconv.FormatFloat(float64(b.Invoice.Balance), 'f', utils.DecimalPrecision, 32),
+ }}
+}
+
+// Paging ...
+func (b *BillingInvoicePrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// BillingInvoiceItemsPrinter ...
+type BillingInvoiceItemsPrinter struct {
+ InvoiceItems []govultr.InvoiceItem `json:"invoice_items"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (b *BillingInvoiceItemsPrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BillingInvoiceItemsPrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BillingInvoiceItemsPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "DESCRIPTION",
+ "PRODUCT",
+ "START DATE",
+ "END DATE",
+ "UNITS",
+ "UNIT TYPE",
+ "UNIT PRICE",
+ "TOTAL",
+ }}
+}
+
+// Data ...
+func (b *BillingInvoiceItemsPrinter) Data() [][]string {
+ if len(b.InvoiceItems) == 0 {
+ return [][]string{0: {"---", "---", "---", "---", "---", "---", "---", "---"}}
+ }
+
+ var data [][]string
+ for i := range b.InvoiceItems {
+ data = append(data, []string{
+ b.InvoiceItems[i].Description,
+ b.InvoiceItems[i].Product,
+ b.InvoiceItems[i].StartDate,
+ b.InvoiceItems[i].EndDate,
+ strconv.Itoa(b.InvoiceItems[i].Units),
+ b.InvoiceItems[i].UnitType,
+ strconv.FormatFloat(float64(b.InvoiceItems[i].UnitPrice), 'f', utils.DecimalPrecision, 32),
+ strconv.FormatFloat(float64(b.InvoiceItems[i].Total), 'f', utils.DecimalPrecision, 32),
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (b *BillingInvoiceItemsPrinter) Paging() [][]string {
+ return printer.NewPaging(b.Meta.Total, &b.Meta.Links.Next, &b.Meta.Links.Prev).Compose()
+}
diff --git a/cmd/blockStorage.go b/cmd/blockStorage.go
deleted file mode 100644
index 25e04fed..00000000
--- a/cmd/blockStorage.go
+++ /dev/null
@@ -1,268 +0,0 @@
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cmd
-
-import (
- "context"
- "errors"
- "fmt"
- "os"
-
- "github.com/spf13/cobra"
- "github.com/vultr/govultr/v2"
- "github.com/vultr/vultr-cli/cmd/printer"
-)
-
-// BlockStorageCmd represents the blockStorage command
-func BlockStorageCmd() *cobra.Command {
-
- bsCmd := &cobra.Command{
- Use: "block-storage",
- Aliases: []string{"bs"},
- Short: "block storage commands",
- Long: `block-storage is used to interact with the block-storage api`,
- }
-
- bsCmd.AddCommand(bsAttach, bsCreate, bsDelete, bsDetach, bsLabelSet, bsList, bsGet, bsResize)
-
- // List
- bsList.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
- bsList.Flags().IntP("per-page", "p", 100, "(optional) Number of items requested per page. Default is 100 and Max is 500.")
-
- // Attach
- bsAttach.Flags().StringP("instance", "i", "", "instance id you want to attach to")
- bsAttach.Flags().Bool("live", false, "attach Block Storage without restarting the Instance.")
- bsAttach.MarkFlagRequired("instance")
-
- // Detach
- bsDetach.Flags().Bool("live", false, "detach block storage from instance without a restart")
-
- // Create
- bsCreate.Flags().StringP("region", "r", "", "regionID you want to create the block storage in")
- bsCreate.MarkFlagRequired("region")
-
- bsCreate.Flags().IntP("size", "s", 0, "size of the block storage you want to create")
- bsCreate.MarkFlagRequired("size")
-
- bsCreate.Flags().StringP("label", "l", "", "label you want to give the block storage")
-
- // Label
- bsLabelSet.Flags().StringP("label", "l", "", "label you want your block storage to have")
- bsLabelSet.MarkFlagRequired("label")
-
- // Resize
- bsResize.Flags().IntP("size", "s", 0, "size you want your block storage to be")
- bsResize.MarkFlagRequired("size")
-
- return bsCmd
-}
-
-var bsAttach = &cobra.Command{
- Use: "attach ",
- Short: "attaches a block storage to an instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a blockStorageID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- instance, _ := cmd.Flags().GetString("instance")
- live, _ := cmd.Flags().GetBool("live")
-
- bsAttach := &govultr.BlockStorageAttach{
- InstanceID: instance,
- Live: govultr.BoolToBoolPtr(live),
- }
-
- if err := client.BlockStorage.Attach(context.Background(), id, bsAttach); err != nil {
- fmt.Printf("error attaching block storage : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("attached block storage")
- },
-}
-
-var bsCreate = &cobra.Command{
- Use: "create",
- Short: "create a new block storage",
- Long: ``,
- Run: func(cmd *cobra.Command, args []string) {
- region, _ := cmd.Flags().GetString("region")
- size, _ := cmd.Flags().GetInt("size")
- label, _ := cmd.Flags().GetString("label")
-
- bsCreate := &govultr.BlockStorageCreate{
- Region: region,
- SizeGB: size,
- Label: label,
- }
-
- bs, err := client.BlockStorage.Create(context.Background(), bsCreate)
- if err != nil {
- fmt.Printf("error creating block storage : %v\n", err)
- os.Exit(1)
- }
-
- printer.SingleBlockStorage(bs)
-
- },
-}
-
-var bsDelete = &cobra.Command{
- Use: "delete ",
- Short: "delete a block storage",
- Aliases: []string{"destroy"},
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a blockStorageID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- if err := client.BlockStorage.Delete(context.Background(), id); err != nil {
- fmt.Printf("error deleting block storage : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("deleted block storage")
- },
-}
-
-var bsDetach = &cobra.Command{
- Use: "detach ",
- Short: "detaches a block storage from an instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a blockStorageID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- live, _ := cmd.Flags().GetBool("live")
-
- bsDetach := &govultr.BlockStorageDetach{
- Live: govultr.BoolToBoolPtr(live),
- }
-
- if err := client.BlockStorage.Detach(context.Background(), id, bsDetach); err != nil {
- fmt.Printf("error detaching block storage : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("detached block storage")
- },
-}
-
-var bsLabelSet = &cobra.Command{
- Use: "label ",
- Short: "sets a label for a block storage",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a blockStorageID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- label, _ := cmd.Flags().GetString("label")
-
- options := &govultr.BlockStorageUpdate{
- Label: label,
- }
-
- if err := client.BlockStorage.Update(context.Background(), id, options); err != nil {
- fmt.Printf("error setting label : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Printf("set label on block storage : %s\n", id)
- },
-}
-
-// List all of individual block storage
-var bsList = &cobra.Command{
- Use: "list",
- Short: "retrieves a list of active block storage",
- Long: ``,
- Run: func(cmd *cobra.Command, args []string) {
- options := getPaging(cmd)
- bs, meta, err := client.BlockStorage.List(context.Background(), options)
- if err != nil {
- fmt.Printf("error getting block storage : %v\n", err)
- os.Exit(1)
- }
-
- printer.BlockStorage(bs, meta)
- },
-}
-
-// Get a block storage
-var bsGet = &cobra.Command{
- Use: "get ",
- Short: "retrieves a block storage",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a blockStorageID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- bs, err := client.BlockStorage.Get(context.Background(), id)
- if err != nil {
- fmt.Printf("error getting block storage : %v\n", err)
- os.Exit(1)
- }
-
- printer.SingleBlockStorage(bs)
- },
-}
-
-var bsResize = &cobra.Command{
- Use: "resize ",
- Short: "resize a block storage",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a blockStorageID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- size, _ := cmd.Flags().GetInt("size")
-
- options := &govultr.BlockStorageUpdate{
- SizeGB: size,
- }
-
- if err := client.BlockStorage.Update(context.Background(), id, options); err != nil {
- fmt.Printf("error resizing block storage : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("resized block storage")
- },
-}
diff --git a/cmd/blockstorage/blockstorage.go b/cmd/blockstorage/blockstorage.go
new file mode 100644
index 00000000..967896b3
--- /dev/null
+++ b/cmd/blockstorage/blockstorage.go
@@ -0,0 +1,473 @@
+// Package blockstorage provides the block storage functionality for
+// the CLI
+package blockstorage
+
+import (
+ "errors"
+ "fmt"
+ "os"
+
+ "github.com/spf13/cobra"
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+ "github.com/vultr/vultr-cli/v3/pkg/cli"
+)
+
+var (
+ attachLong = `Attaches a block storage resource to an specified instance`
+ attachExample = `
+ #Full example
+ vultr-cli block-storage attach 67181686-5455-4ebb-81eb-7299f3506e2c --instance=a7898453-dd9e-4b47-bdab-9dd7a3448f1f
+
+ #Shortened with aliased commands
+ vultr-cli bs a 67181686-5455-4ebb-81eb-7299f3506e2c -i=a7898453-dd9e-4b47-bdab-9dd7a3448f1f
+ `
+
+ createLong = `Create a new block storage resource in a specified region`
+ createExample = `
+ #Full example
+ vultr-cli block-storage create --region='lax' --size=10 --label='your-label'
+
+ #Full example with block-type
+ vultr-cli block-storage create --region='lax' --size=10 --block-type='high_perf'
+
+ #Shortened with aliased commands
+ vultr-cli bs c -r='lax' -s=10 -l='your-label'
+
+ #Shortened with aliased commands and block-type
+ vultr-cli bs c -r='lax' -s=10 -b='high_perf'
+ `
+
+ deleteLong = `Delete a block storage resource`
+ deleteExample = `
+ #Full example
+ vultr-cli block-storage delete 67181686-5455-4ebb-81eb-7299f3506e2c
+
+ #Shortened with aliased commands
+ vultr-cli bs d 67181686-5455-4ebb-81eb-7299f3506e2c
+ `
+
+ detachLong = `Detach a block storage resource from an instance`
+ detachExample = `
+ #Full example
+ vultr-cli block-storage detach 67181686-5455-4ebb-81eb-7299f3506e2c
+
+ #Shortened with aliased commands
+ vultr-cli bs detach 67181686-5455-4ebb-81eb-7299f3506e2c
+ `
+
+ labelLong = `Set a label for a block storage resource`
+ labelExample = `
+ #Full example
+ vultr-cli block-storage label 67181686-5455-4ebb-81eb-7299f3506e2c --label="Example Label"
+
+ #Shortened with aliased commands
+ vultr-cli bs label 67181686-5455-4ebb-81eb-7299f3506e2c -l="Example Label"
+ `
+
+ listLong = `Retrieves a list of active block storage resources`
+ listExample = `
+ #Full example
+ vultr-cli block-storage list
+
+ #Shortened with aliased commands
+ vultr-cli bs l
+ `
+
+ getLong = `Retrieves a specified block storage resource`
+ getExample = `
+ #Full example
+ vultr-cli block-storage get 67181686-5455-4ebb-81eb-7299f3506e2c
+
+ #Shortened with aliased commands
+ vultr-cli bs g 67181686-5455-4ebb-81eb-7299f3506e2c
+ `
+
+ resizeLong = `Resizes a specified block storage resource`
+ resizeExample = `
+ #Full example
+ vultr-cli block-storage resize 67181686-5455-4ebb-81eb-7299f3506e2c --size=20
+
+ #Shortened with aliased commands
+ vultr-cli bs r 67181686-5455-4ebb-81eb-7299f3506e2c -s=20
+ `
+)
+
+// NewCmdBlockStorage provides the command for block storage to the CLI
+func NewCmdBlockStorage(base *cli.Base) *cobra.Command { //nolint:gocyclo
+ o := &options{Base: base}
+
+ cmd := &cobra.Command{
+ Use: "block-storage",
+ 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 {
+ utils.SetOptions(o.Base, cmd, args)
+ if !o.Base.HasAuth {
+ return errors.New(utils.APIKeyError)
+ }
+ return nil
+ },
+ }
+
+ // List
+ list := &cobra.Command{
+ Use: "list",
+ Short: "List block storage",
+ Aliases: []string{"l"},
+ Long: listLong,
+ Example: listExample,
+ Run: func(cmd *cobra.Command, args []string) {
+ o.Base.Options = utils.GetPaging(cmd)
+ bss, meta, err := o.list()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving block storage list : %v", err))
+ os.Exit(1)
+ }
+
+ data := &BlockStoragesPrinter{BlockStorages: bss, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ list.Flags().StringP("cursor", "c", "", "(optional) cursor for paging.")
+ list.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ fmt.Sprintf("(optional) Number of items requested per page. Default is %d and Max is 500.", utils.PerPageDefault),
+ )
+
+ // Get
+ get := &cobra.Command{
+ Use: "get ",
+ Short: "Retrieve a block storage",
+ Aliases: []string{"g"},
+ Long: getLong,
+ Example: getExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a block storage ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ bs, err := o.get()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving block storage : %v", err))
+ os.Exit(1)
+ }
+
+ data := &BlockStoragePrinter{BlockStorage: bs}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ // Create
+ create := &cobra.Command{
+ Use: "create",
+ Short: "Create a new block storage",
+ Aliases: []string{"c"},
+ Long: createLong,
+ Example: createExample,
+ Run: func(cmd *cobra.Command, args []string) {
+ reg, errRg := cmd.Flags().GetString("region")
+ if errRg != nil {
+ printer.Error(fmt.Errorf("error parsing 'region' flag for block storage create : %v", errRg))
+ os.Exit(1)
+ }
+
+ size, errSz := cmd.Flags().GetInt("size")
+ if errSz != nil {
+ printer.Error(fmt.Errorf("error parsing 'size' flag for block storage create : %v", errSz))
+ os.Exit(1)
+ }
+
+ label, errLa := cmd.Flags().GetString("label")
+ if errLa != nil {
+ printer.Error(fmt.Errorf("error parsing 'label' flag for block storage create : %v", errLa))
+ os.Exit(1)
+ }
+
+ blockType, errBt := cmd.Flags().GetString("block-type")
+ if errBt != nil {
+ printer.Error(fmt.Errorf("error parsing 'block-type' flag for block storage create : %v", errBt))
+ os.Exit(1)
+ }
+
+ o.CreateReq = &govultr.BlockStorageCreate{
+ Region: reg,
+ SizeGB: size,
+ Label: label,
+ BlockType: blockType,
+ }
+
+ bs, err := o.create()
+ if err != nil {
+ printer.Error(fmt.Errorf("error creating block storage : %v", err))
+ os.Exit(1)
+ }
+
+ data := &BlockStoragePrinter{BlockStorage: bs}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ create.Flags().StringP("region", "r", "", "ID of the region in which to create the block storage")
+ if err := create.MarkFlagRequired("region"); err != nil {
+ fmt.Printf("error marking block storage create 'region' flag required: %v\n", err)
+ os.Exit(1)
+ }
+
+ create.Flags().IntP("size", "s", 0, "size of the block storage you want to create")
+ if err := create.MarkFlagRequired("size"); err != nil {
+ fmt.Printf("error marking block storage create 'size' flag required: %v\n", err)
+ os.Exit(1)
+ }
+
+ create.Flags().StringP("label", "l", "", "label you want to give the block storage")
+
+ create.Flags().StringP(
+ "block-type",
+ "b",
+ "",
+ `(optional) Block type you want to give the block storage.
+ Possible values: 'high_perf', 'storage_opt'. Currently defaults to 'high_perf'.`,
+ )
+
+ // Delete
+ del := &cobra.Command{
+ Use: "delete ",
+ Short: "Delete a block storage",
+ Aliases: []string{"d", "destroy"},
+ Long: deleteLong,
+ Example: deleteExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a block storage ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ if err := o.del(); err != nil {
+ printer.Error(fmt.Errorf("error deleting block storage : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("block storage has been deleted"), nil)
+ },
+ }
+
+ // Attach
+ attach := &cobra.Command{
+ Use: "attach ",
+ Short: "Attach a block storage to an instance",
+ Aliases: []string{"a"},
+ Long: attachLong,
+ Example: attachExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a block storage ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ instance, errIe := cmd.Flags().GetString("instance")
+ if errIe != nil {
+ printer.Error(fmt.Errorf("error parsing 'instance' flag for block storage attach : %v", errIe))
+ os.Exit(1)
+ }
+
+ live, errLe := cmd.Flags().GetBool("live")
+ if errLe != nil {
+ printer.Error(fmt.Errorf("error parsing 'live' flag for block storage attach : %v", errLe))
+ os.Exit(1)
+ }
+
+ o.AttachReq = &govultr.BlockStorageAttach{
+ InstanceID: instance,
+ Live: govultr.BoolToBoolPtr(live),
+ }
+
+ if err := o.attach(); err != nil {
+ printer.Error(fmt.Errorf("error attaching block storage : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("block storage has been attached"), nil)
+ },
+ }
+
+ attach.Flags().StringP("instance", "i", "", "instance ID to which to attach the block storage")
+ if err := attach.MarkFlagRequired("instance"); err != nil {
+ fmt.Printf("error marking block storage attach 'instance' flag required: %v\n", err)
+ os.Exit(1)
+ }
+
+ attach.Flags().Bool("live", false, "attach block storage without restarting the instance")
+
+ // Detach
+ detach := &cobra.Command{
+ Use: "detach ",
+ Short: "Detach a block storage from an instance",
+ Long: detachLong,
+ Example: detachExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a block storage ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ live, errLe := cmd.Flags().GetBool("live")
+ if errLe != nil {
+ printer.Error(fmt.Errorf("error parsing 'live' flag for block storage detach : %v", errLe))
+ os.Exit(1)
+ }
+
+ o.DetachReq = &govultr.BlockStorageDetach{
+ Live: govultr.BoolToBoolPtr(live),
+ }
+
+ if err := o.detach(); err != nil {
+ printer.Error(fmt.Errorf("error detaching block storage : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("block storage has been detached"), nil)
+ },
+ }
+
+ detach.Flags().Bool("live", false, "detach block storage without a restarting instance")
+
+ // Label
+ label := &cobra.Command{
+ Use: "label ",
+ Short: "Label a block storage",
+ Long: labelLong,
+ Example: labelExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a block storage ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ label, errLl := cmd.Flags().GetString("label")
+ if errLl != nil {
+ printer.Error(fmt.Errorf("error parsing 'label' flag for block storage : %v", errLl))
+ os.Exit(1)
+ }
+
+ o.UpdateReq = &govultr.BlockStorageUpdate{
+ Label: label,
+ }
+
+ if err := o.update(); err != nil {
+ printer.Error(fmt.Errorf("error updating block storage label : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("block storage label has been updated"), nil)
+ },
+ }
+
+ label.Flags().StringP("label", "l", "", "the label to apply to the block storage")
+ if err := label.MarkFlagRequired("label"); err != nil {
+ fmt.Printf("error marking block storage label set 'label' flag required: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Resize
+ resize := &cobra.Command{
+ Use: "resize ",
+ Short: "Resize a block storage",
+ Aliases: []string{"r"},
+ Long: resizeLong,
+ Example: resizeExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a block storage ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ size, errSz := cmd.Flags().GetInt("size")
+ if errSz != nil {
+ printer.Error(fmt.Errorf("error parsing 'size' flag for block storage resize : %v", errSz))
+ os.Exit(1)
+ }
+
+ o.UpdateReq = &govultr.BlockStorageUpdate{
+ SizeGB: size,
+ }
+
+ if err := o.update(); err != nil {
+ printer.Error(fmt.Errorf("error resizing block storage : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("block storage has been resized"), nil)
+ },
+ }
+
+ resize.Flags().IntP("size", "s", 0, "size you want your block storage to be")
+ if err := resize.MarkFlagRequired("size"); err != nil {
+ fmt.Printf("error marking block storage resize 'size' flag required: %v\n", err)
+ os.Exit(1)
+ }
+
+ cmd.AddCommand(
+ list,
+ get,
+ create,
+ del,
+ label,
+ attach,
+ detach,
+ resize,
+ )
+
+ return cmd
+}
+
+type options struct {
+ Base *cli.Base
+ CreateReq *govultr.BlockStorageCreate
+ UpdateReq *govultr.BlockStorageUpdate
+ AttachReq *govultr.BlockStorageAttach
+ DetachReq *govultr.BlockStorageDetach
+}
+
+func (o *options) list() ([]govultr.BlockStorage, *govultr.Meta, error) {
+ bs, meta, _, err := o.Base.Client.BlockStorage.List(o.Base.Context, o.Base.Options)
+ return bs, meta, err
+}
+
+func (o *options) get() (*govultr.BlockStorage, error) {
+ bs, _, err := o.Base.Client.BlockStorage.Get(o.Base.Context, o.Base.Args[0])
+ return bs, err
+}
+
+func (o *options) create() (*govultr.BlockStorage, error) {
+ bs, _, err := o.Base.Client.BlockStorage.Create(o.Base.Context, o.CreateReq)
+ return bs, err
+}
+
+func (o *options) del() error {
+ return o.Base.Client.BlockStorage.Delete(o.Base.Context, o.Base.Args[0])
+}
+
+func (o *options) update() error {
+ return o.Base.Client.BlockStorage.Update(o.Base.Context, o.Base.Args[0], o.UpdateReq)
+}
+
+func (o *options) attach() error {
+ return o.Base.Client.BlockStorage.Attach(o.Base.Context, o.Base.Args[0], o.AttachReq)
+}
+
+func (o *options) detach() error {
+ return o.Base.Client.BlockStorage.Detach(o.Base.Context, o.Base.Args[0], o.DetachReq)
+}
diff --git a/cmd/blockstorage/printer.go b/cmd/blockstorage/printer.go
new file mode 100644
index 00000000..6ed35044
--- /dev/null
+++ b/cmd/blockstorage/printer.go
@@ -0,0 +1,125 @@
+package blockstorage
+
+import (
+ "fmt"
+ "strconv"
+
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+)
+
+// BlockStoragesPrinter ...
+type BlockStoragesPrinter struct {
+ BlockStorages []govultr.BlockStorage `json:"blocks"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (b *BlockStoragesPrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BlockStoragesPrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BlockStoragesPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "REGION ID",
+ "INSTANCE ID",
+ "SIZE GB",
+ "STATUS",
+ "LABEL",
+ "BLOCK TYPE",
+ "DATE CREATED",
+ "MONTHLY COST",
+ "MOUNT ID",
+ }}
+}
+
+// Data ...
+func (b *BlockStoragesPrinter) Data() [][]string {
+ if len(b.BlockStorages) == 0 {
+ return [][]string{0: {"---", "---", "---", "---", "---", "---", "---", "---", "---", "---"}}
+ }
+
+ var data [][]string
+ for i := range b.BlockStorages {
+ data = append(data, []string{
+ b.BlockStorages[i].ID,
+ b.BlockStorages[i].Region,
+ b.BlockStorages[i].AttachedToInstance,
+ strconv.Itoa(b.BlockStorages[i].SizeGB),
+ b.BlockStorages[i].Status,
+ b.BlockStorages[i].Label,
+ b.BlockStorages[i].BlockType,
+ b.BlockStorages[i].DateCreated,
+ fmt.Sprintf("$%v", b.BlockStorages[i].Cost),
+ b.BlockStorages[i].MountID,
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (b *BlockStoragesPrinter) Paging() [][]string {
+ return printer.NewPaging(b.Meta.Total, &b.Meta.Links.Next, &b.Meta.Links.Prev).Compose()
+}
+
+// ======================================
+
+// BlockStoragePrinter ...
+type BlockStoragePrinter struct {
+ BlockStorage *govultr.BlockStorage `json:"block"`
+}
+
+// JSON ...
+func (b *BlockStoragePrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BlockStoragePrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BlockStoragePrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "REGION ID",
+ "INSTANCE ID",
+ "SIZE GB",
+ "STATUS",
+ "LABEL",
+ "BLOCK TYPE",
+ "DATE CREATED",
+ "MONTHLY COST",
+ "MOUNT ID",
+ }}
+}
+
+// Data ...
+func (b *BlockStoragePrinter) Data() [][]string {
+ return [][]string{0: {
+ b.BlockStorage.ID,
+ b.BlockStorage.Region,
+ b.BlockStorage.AttachedToInstance,
+ strconv.Itoa(b.BlockStorage.SizeGB),
+ b.BlockStorage.Status,
+ b.BlockStorage.Label,
+ b.BlockStorage.BlockType,
+ b.BlockStorage.DateCreated,
+ fmt.Sprintf("$%v", b.BlockStorage.Cost),
+ b.BlockStorage.MountID,
+ }}
+}
+
+// Paging ...
+func (b *BlockStoragePrinter) Paging() [][]string {
+ return nil
+}
diff --git a/cmd/containerregistry/containerregistry.go b/cmd/containerregistry/containerregistry.go
new file mode 100644
index 00000000..6a3ac6c3
--- /dev/null
+++ b/cmd/containerregistry/containerregistry.go
@@ -0,0 +1,696 @@
+// Package containerregistry provides functionality for the CLI to control
+// container registries
+package containerregistry
+
+import (
+ "errors"
+ "fmt"
+ "os"
+
+ "github.com/spf13/cobra"
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+ "github.com/vultr/vultr-cli/v3/pkg/cli"
+)
+
+var (
+ long = `Access information about container registries on the account and perform CRUD operations`
+ example = `
+ # Full example
+ vultr-cli container-registry
+ `
+ createLong = `Create a new container registry with specified options`
+ createExample = `
+ # Full example
+ vultr-cli container-registry create --region="sjc" --name="my-registry" --public=true --plan="start_up"
+
+ all flags are required
+
+ # Shortened example with aliases
+ vultr-cli cr c -i="sjc" -n="my-registry" -p=true -l="start_up"
+ `
+
+ getLong = `Display information for a specific VPC`
+ getExample = `
+ # Full example
+ vultr-cli container-registry get e8ba183d-df3b-487a-acbf-f6c06aa32468
+
+ # Shortened example with aliases
+ vultr-cli cr g e8ba183d-df3b-487a-acbf-f6c06aa32468
+ `
+ updateLong = `Update an existing container registry`
+ updateExample = `
+ # Full example
+ vultr-cli container-registry update 835fd402-e0eb-47aa-a5a9-a9885feea1cf --plan="premium" --public="true"
+
+ # Shortened example with aliases
+ vultr-cli cr u 835fd402-e0eb-47aa-a5a9-a9885feea1cf -p="premium" -b="true"
+ `
+ deleteLong = `Delete a container registry`
+ deleteExample = `
+ #Full example
+ vultr-cli container-registry delete b20fa61e-4abb-46c5-92c3-8700150e1f9a
+
+ #Shortened example with aliases
+ vultr-cli cr d b20fa61e-4abb-46c5-92c3-8700150e1f9a
+ `
+ listLong = `List all container registries on the account`
+ listExample = `
+ # Full example
+ vultr-cli container-registry list
+
+ # Shortened example with aliases
+ vultr-cli cr l
+ `
+ credentialsLong = `Commands for accessing the credentials on registries`
+ //nolint:gosec
+ credentialsExample = `
+ # Full example
+ vultr-cli container-registry credentials
+ `
+ credentialsDockerLong = `Create the credential string used by docker`
+ //nolint:gosec
+ credentialsDockerExample = `
+ # Full example
+ vultr-cli container-registry credentials docker d24cfdcc-0534-4700-bf88-8ee48f20064e
+ `
+ repoLong = `Access commands for individual repositories on a container registry`
+ repoExample = `
+ # Full example
+ vultr-cli container-registry repository
+
+ # Shortened example with aliases
+ vultr-cli cr r
+ `
+ repoUpdateLong = `Update the details of registry's repository`
+ repoUpdateExample = `
+ # Full example
+ vultr-cli container-registry repository update 4dcdc52e-9c63-401e-8c5f-1582490fe09c --image-name="my-thing" --description="new description"
+
+ # Shortened example with aliases
+ vultr-cli cr r u 4dcdc52e-9c63-401e-8c5f-1582490fe09c -i="my-thing" -d="new description"
+ `
+ repoDeleteLong = `Delete a repository in a registry`
+ repoDeleteExample = `
+ # Full example
+ vultr-cli container-registry repository delete 4dcdc52e-9c63-401e-8c5f-1582490fe09c --image-name="my-thing"
+
+ # Shortened example with aliases
+ vultr-cli cr r d 4dcdc52e-9c63-401e-8c5f-1582490fe09c -i="my-thing"
+ `
+ plansLong = `Retrieve the current plan details for container registry`
+ plansExample = `
+ # Full example
+ vultr-cli container-registry plans
+
+ # Shortened example with aliases
+ vultr-cli cr p
+ `
+ regionsLong = `Retrieve the available regions for container registries`
+ regionsExample = `
+ # Full example
+ vultr-cli container-registry regions
+
+ # Shortened example with aliases
+ vultr-cli cr r
+ `
+)
+
+// NewCmdContainerRegistry provides the CLI command functionality for container registry
+func NewCmdContainerRegistry(base *cli.Base) *cobra.Command { //nolint:funlen,gocyclo
+ o := &options{Base: base}
+
+ cmd := &cobra.Command{
+ Use: "container-registry",
+ Short: "Commands to interact with container registries",
+ Aliases: []string{"cr"},
+ Long: long,
+ Example: example,
+ PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+ utils.SetOptions(o.Base, cmd, args)
+ if !o.Base.HasAuth {
+ return errors.New(utils.APIKeyError)
+ }
+ return nil
+ },
+ }
+
+ // List
+ list := &cobra.Command{
+ Use: "list",
+ Short: "List all container registries",
+ Aliases: []string{"l"},
+ Long: listLong,
+ Example: listExample,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ o.Base.Options = utils.GetPaging(cmd)
+ regs, meta, err := o.list()
+ if err != nil {
+ return fmt.Errorf("error retrieving container registry list : %v", err)
+ }
+
+ data := &ContainerRegistriesPrinter{Registries: regs, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ list.Flags().StringP("cursor", "c", "", "(optional) cursor for paging.")
+ list.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ fmt.Sprintf("(optional) Number of items requested per page. Default is %d and Max is 500.", utils.PerPageDefault),
+ )
+
+ // Get
+ get := &cobra.Command{
+ Use: "get ",
+ Short: "Get a container registry",
+ Aliases: []string{"g"},
+ Long: getLong,
+ Example: getExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a container registry ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ reg, err := o.get()
+ if err != nil {
+ return fmt.Errorf("error retrieving container registry info : %v", err)
+ }
+
+ data := &ContainerRegistryPrinter{Registry: reg}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Create
+ create := &cobra.Command{
+ Use: "create",
+ Short: "Create a container registry",
+ Aliases: []string{"c"},
+ Long: createLong,
+ Example: createExample,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ name, errNa := cmd.Flags().GetString("name")
+ if errNa != nil {
+ return fmt.Errorf("error parsing 'name' flag for container registry create : %v", errNa)
+ }
+
+ region, errRe := cmd.Flags().GetString("region")
+ if errRe != nil {
+ return fmt.Errorf("error parsing 'region' flag for container registry create : %v", errRe)
+ }
+
+ public, errPu := cmd.Flags().GetBool("public")
+ if errPu != nil {
+ return fmt.Errorf("error parsing 'public' flag for container registry create : %v", errPu)
+ }
+
+ plan, errPl := cmd.Flags().GetString("plan")
+ if errPl != nil {
+ return fmt.Errorf("error parsing 'plan' flag for container registry create : %v", errPl)
+ }
+
+ o.CreateReq = &govultr.ContainerRegistryReq{
+ Name: name,
+ Region: region,
+ Public: public,
+ Plan: plan,
+ }
+
+ reg, err := o.create()
+ if err != nil {
+ return fmt.Errorf("error creating container registry : %v", err)
+ }
+
+ data := &ContainerRegistryPrinter{Registry: reg}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ create.Flags().StringP("name", "n", "", "The name to use for the container registry")
+ if err := create.MarkFlagRequired("name"); err != nil {
+ printer.Error(fmt.Errorf("error marking container registry create 'name' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ create.Flags().StringP("region", "i", "", "The ID of the region in which to create the container registry")
+ if err := create.MarkFlagRequired("region"); err != nil {
+ printer.Error(fmt.Errorf("error marking container registry create 'region' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ create.Flags().BoolP("public", "p", false, "If the registry is publicly available. Should be true | false (default is false)")
+ if err := create.MarkFlagRequired("public"); err != nil {
+ printer.Error(fmt.Errorf("error marking container registry create 'public' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ create.Flags().StringP("plan", "l", "", "The type of plan to use for the container registry")
+ if err := create.MarkFlagRequired("plan"); err != nil {
+ printer.Error(fmt.Errorf("error marking container registry create 'plan' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ // Update
+ update := &cobra.Command{
+ Use: "update ",
+ Short: "Update a container registry",
+ Aliases: []string{"u"},
+ Long: updateLong,
+ Example: updateExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a container registry ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ public, errPu := cmd.Flags().GetBool("public")
+ if errPu != nil {
+ return fmt.Errorf("error parsing 'public' flag for container registry update : %v", errPu)
+ }
+
+ plan, errPl := cmd.Flags().GetString("plan")
+ if errPl != nil {
+ return fmt.Errorf("error parsing 'plan' flag for container registry update : %v", errPl)
+ }
+
+ o.UpdateReq = &govultr.ContainerRegistryUpdateReq{
+ Plan: govultr.StringToStringPtr(plan),
+ }
+
+ if cmd.Flags().Changed("public") {
+ o.UpdateReq.Public = govultr.BoolToBoolPtr(public)
+ }
+
+ if err := o.update(); err != nil {
+ return fmt.Errorf("error updating container registry : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("container registry has been updated"), nil)
+
+ return nil
+ },
+ }
+
+ update.Flags().StringP("plan", "p", "", "Name of the plan used for the container registry")
+ update.Flags().BoolP("public", "b", false, "The container registry availability status")
+
+ // Delete
+ del := &cobra.Command{
+ Use: "delete ",
+ Short: "Delete a container registry",
+ Aliases: []string{"destroy", "d"},
+ Long: deleteLong,
+ Example: deleteExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a container registry ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.del(); err != nil {
+ return fmt.Errorf("error deleting container registry : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("container registry has been deleted"), nil)
+
+ return nil
+ },
+ }
+
+ // Plans
+ plans := &cobra.Command{
+ Use: "plans",
+ Short: "List the plan names for container registry",
+ Aliases: []string{"p"},
+ Long: plansLong,
+ Example: plansExample,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ plans, err := o.plans()
+ if err != nil {
+ return fmt.Errorf("error retrieving plans for container registry : %v", err)
+ }
+
+ data := &ContainerRegistryPlansPrinter{Plans: plans.Plans}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Regions
+ regions := &cobra.Command{
+ Use: "regions",
+ Short: "List the available regions for container registry",
+ Aliases: []string{"i"},
+ Long: regionsLong,
+ Example: regionsExample,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ regs, meta, err := o.regions()
+ if err != nil {
+ return fmt.Errorf("error retrieving regions for container registry : %v", err)
+ }
+
+ data := &ContainerRegistryRegionsPrinter{Regions: regs, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Repository
+ repository := &cobra.Command{
+ Use: "repository",
+ Short: "Interact with container registry repositories",
+ Aliases: []string{"r", "repo"},
+ Long: repoLong,
+ Example: repoExample,
+ }
+
+ // Repository List
+ repoList := &cobra.Command{
+ Use: "list ",
+ Short: "List all container registries",
+ Aliases: []string{"l"},
+ Long: listLong,
+ Example: listExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a container registry ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ o.Base.Options = utils.GetPaging(cmd)
+ repos, meta, err := o.repositoryList()
+ if err != nil {
+ return fmt.Errorf("error retrieving repositories for container registry : %v", err)
+ }
+
+ data := &ContainerRegistryRepositoriesPrinter{Repositories: repos, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Repository Get
+ repoGet := &cobra.Command{
+ Use: "get ",
+ Short: "Get a container registry repository",
+ Aliases: []string{"g"},
+ Long: getLong,
+ Example: getExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a container registry ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ name, errIm := cmd.Flags().GetString("image-name")
+ if errIm != nil {
+ return fmt.Errorf("error parsing 'image-name' flag for container registry repository get : %v", errIm)
+ }
+
+ o.RepoName = name
+
+ repo, err := o.repositoryGet()
+ if err != nil {
+ return fmt.Errorf("error getting container registry repository : %v", err)
+ }
+
+ data := &ContainerRegistryRepositoryPrinter{Repository: repo}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ repoGet.Flags().StringP("image-name", "i", "", "The name of the image/repo")
+ if err := repoGet.MarkFlagRequired("image-name"); err != nil {
+ printer.Error(fmt.Errorf("error marking get container registry repository 'image-name' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ // Repository Update
+ repoUpdate := &cobra.Command{
+ Use: "update ",
+ Short: "Update a container registry repository",
+ Aliases: []string{"u"},
+ Long: repoUpdateLong,
+ Example: repoUpdateExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a container registry ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ name, errIm := cmd.Flags().GetString("image-name")
+ if errIm != nil {
+ return fmt.Errorf("error parsing 'image-name' flag for container registry repository update : %v", errIm)
+ }
+
+ description, errDe := cmd.Flags().GetString("description")
+ if errDe != nil {
+ return fmt.Errorf("error parsing 'description' flag for container registry repository update : %v", errDe)
+ }
+
+ o.RepoName = name
+ o.RepoUpdateReq = &govultr.ContainerRegistryRepoUpdateReq{
+ Description: description,
+ }
+
+ if err := o.repositoryUpdate(); err != nil {
+ return fmt.Errorf("error updating container registry repository : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("container registry repository has been updated"), nil)
+
+ return nil
+ },
+ }
+
+ repoUpdate.Flags().StringP("image-name", "i", "", "The name of the image/repo")
+ if err := repoUpdate.MarkFlagRequired("image-name"); err != nil {
+ printer.Error(fmt.Errorf("error marking update container registry repository 'image-name' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ repoUpdate.Flags().StringP("description", "d", "", "The description of the image/repo")
+ if err := repoUpdate.MarkFlagRequired("description"); err != nil {
+ printer.Error(fmt.Errorf("error marking update container registry repository 'description' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ // Repository Delete
+ repoDelete := &cobra.Command{
+ Use: "delete ",
+ Short: "Delete a container registry repository",
+ Aliases: []string{"destroy", "d"},
+ Long: repoDeleteLong,
+ Example: repoDeleteExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a container registry ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ name, errIm := cmd.Flags().GetString("image-name")
+ if errIm != nil {
+ return fmt.Errorf("error parsing 'image-name' flag for container registry repository delete : %v", errIm)
+ }
+
+ o.RepoName = name
+
+ if err := o.repositoryDelete(); err != nil {
+ return fmt.Errorf("error deleting container registry repository : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("container registry repository has been deleted"), nil)
+
+ return nil
+ },
+ }
+
+ repoDelete.Flags().StringP("image-name", "i", "", "The name of the image/repo")
+ if err := repoDelete.MarkFlagRequired("image-name"); err != nil {
+ printer.Error(fmt.Errorf("error marking delete container registry repository 'image-name' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ repository.AddCommand(
+ repoGet,
+ repoList,
+ repoUpdate,
+ repoDelete,
+ )
+
+ // Credentials
+ credentials := &cobra.Command{
+ Use: "credentials",
+ Short: "Commands for container registry credentials",
+ Aliases: []string{""},
+ Long: credentialsLong,
+ Example: credentialsExample,
+ }
+
+ // Credentials Docker
+ credentialsDocker := &cobra.Command{
+ Use: "docker ",
+ Short: "Create Docker credentials for a container registry",
+ Aliases: []string{"d"},
+ Long: credentialsDockerLong,
+ Example: credentialsDockerExample,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ expiry, errEx := cmd.Flags().GetInt("expiry-seconds")
+ if errEx != nil {
+ return fmt.Errorf("error parsing 'expiry-seconds' flag for container registry docker creds : %v", errEx)
+ }
+
+ access, errAc := cmd.Flags().GetBool("read-write")
+ if errAc != nil {
+ return fmt.Errorf("error parsing 'read-write' flag for container registry docker creds : %v", errAc)
+ }
+
+ o.CredentialsDockerReq = &govultr.DockerCredentialsOpt{
+ ExpirySeconds: govultr.IntToIntPtr(expiry),
+ WriteAccess: govultr.BoolToBoolPtr(access),
+ }
+
+ cred, err := o.credentialsDocker()
+ if err != nil {
+ return fmt.Errorf("error generating container registry repository docker credentials : %v", err)
+ }
+
+ data := &ContainerRegistryCredentialDockerPrinter{Credential: cred}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ credentialsDocker.Flags().IntP(
+ "expiry-seconds",
+ "e",
+ 0,
+ "(optional) The seconds until these credentials expire. Default is 0, never",
+ )
+
+ credentialsDocker.Flags().BoolP(
+ "read-write",
+ "w",
+ false,
+ "(optional) Whether or not these credentials have write access. Should be true or false. Default is false",
+ )
+
+ credentials.AddCommand(
+ credentialsDocker,
+ )
+
+ cmd.AddCommand(
+ list,
+ get,
+ create,
+ update,
+ del,
+ plans,
+ regions,
+ repository,
+ credentials,
+ )
+
+ return cmd
+}
+
+type options struct {
+ Base *cli.Base
+ CreateReq *govultr.ContainerRegistryReq
+ UpdateReq *govultr.ContainerRegistryUpdateReq
+ RepoName string
+ RepoUpdateReq *govultr.ContainerRegistryRepoUpdateReq
+ CredentialsDockerReq *govultr.DockerCredentialsOpt
+}
+
+func (o *options) list() ([]govultr.ContainerRegistry, *govultr.Meta, error) {
+ cr, meta, _, err := o.Base.Client.ContainerRegistry.List(o.Base.Context, o.Base.Options)
+ return cr, meta, err
+}
+
+func (o *options) get() (*govultr.ContainerRegistry, error) {
+ cr, _, err := o.Base.Client.ContainerRegistry.Get(o.Base.Context, o.Base.Args[0])
+ return cr, err
+}
+
+func (o *options) create() (*govultr.ContainerRegistry, error) {
+ cr, _, err := o.Base.Client.ContainerRegistry.Create(o.Base.Context, o.CreateReq)
+ return cr, err
+}
+
+func (o *options) update() error {
+ _, _, err := o.Base.Client.ContainerRegistry.Update(o.Base.Context, o.Base.Args[0], o.UpdateReq)
+ return err
+}
+
+func (o *options) del() error {
+ return o.Base.Client.ContainerRegistry.Delete(o.Base.Context, o.Base.Args[0])
+}
+
+func (o *options) plans() (*govultr.ContainerRegistryPlans, error) {
+ plans, _, err := o.Base.Client.ContainerRegistry.ListPlans(o.Base.Context)
+ return plans, err
+}
+
+func (o *options) regions() ([]govultr.ContainerRegistryRegion, *govultr.Meta, error) {
+ regions, meta, _, err := o.Base.Client.ContainerRegistry.ListRegions(o.Base.Context)
+ return regions, meta, err
+}
+
+func (o *options) repositoryList() ([]govultr.ContainerRegistryRepo, *govultr.Meta, error) {
+ repos, meta, _, err := o.Base.Client.ContainerRegistry.ListRepositories(o.Base.Context, o.Base.Args[0], o.Base.Options)
+ return repos, meta, err
+}
+
+func (o *options) repositoryGet() (*govultr.ContainerRegistryRepo, error) {
+ repo, _, err := o.Base.Client.ContainerRegistry.GetRepository(o.Base.Context, o.Base.Args[0], o.RepoName)
+ return repo, err
+}
+
+func (o *options) repositoryUpdate() error {
+ _, _, err := o.Base.Client.ContainerRegistry.UpdateRepository(
+ o.Base.Context,
+ o.Base.Args[0],
+ o.RepoName,
+ o.RepoUpdateReq,
+ )
+
+ return err
+}
+
+func (o *options) repositoryDelete() error {
+ return o.Base.Client.ContainerRegistry.DeleteRepository(o.Base.Context, o.Base.Args[0], o.RepoName)
+}
+
+func (o *options) credentialsDocker() (*govultr.ContainerRegistryDockerCredentials, error) {
+ cred, _, err := o.Base.Client.ContainerRegistry.CreateDockerCredentials(
+ o.Base.Context,
+ o.Base.Args[0],
+ o.CredentialsDockerReq,
+ )
+ return cred, err
+}
diff --git a/cmd/containerregistry/printer.go b/cmd/containerregistry/printer.go
new file mode 100644
index 00000000..098fc94e
--- /dev/null
+++ b/cmd/containerregistry/printer.go
@@ -0,0 +1,376 @@
+package containerregistry
+
+import (
+ "fmt"
+ "reflect"
+ "strconv"
+
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+)
+
+// ContainerRegistryPrinter ...
+type ContainerRegistryPrinter struct {
+ Registry *govultr.ContainerRegistry `json:"registry"`
+}
+
+// JSON ...
+func (c *ContainerRegistryPrinter) JSON() []byte {
+ return printer.MarshalObject(c, "json")
+}
+
+// YAML ...
+func (c *ContainerRegistryPrinter) YAML() []byte {
+ return printer.MarshalObject(c, "yaml")
+}
+
+// Columns ...
+func (c *ContainerRegistryPrinter) Columns() [][]string {
+ return nil
+}
+
+// Data ...
+func (c *ContainerRegistryPrinter) Data() [][]string {
+ return [][]string{
+ 0: {"ID", c.Registry.ID},
+ 1: {"NAME", c.Registry.Name},
+ 2: {"PUBLIC", strconv.FormatBool(c.Registry.Public)},
+ 3: {"URN", c.Registry.URN},
+ 4: {"REGION", c.Registry.Metadata.Region.Name},
+ 5: {" "},
+ 6: {"ROOT USER"},
+ 7: {"ID", strconv.Itoa(c.Registry.RootUser.ID)},
+ 8: {"USER NAME", c.Registry.RootUser.UserName},
+ 9: {"PASSWORD", c.Registry.RootUser.Password},
+ 10: {"CREATED", c.Registry.RootUser.DateCreated},
+ 11: {"MODIFIED", c.Registry.RootUser.DateModified},
+ 12: {" "},
+ 13: {"STORAGE"},
+ 14: {"USED", fmt.Sprintf("%vGB", c.Registry.Storage.Used.GigaBytes)},
+ 15: {"ALLOWED", fmt.Sprintf("%vGB", c.Registry.Storage.Allowed.GigaBytes)},
+ 16: {" "},
+ 17: {"BILLING"},
+ 18: {"PRICE",
+ strconv.FormatFloat(
+ float64(c.Registry.Metadata.Subscription.Billing.MonthlyPrice),
+ 'f',
+ utils.FloatPrecision,
+ utils.FloatBitDepth,
+ ),
+ },
+ 19: {"CHARGES",
+ strconv.FormatFloat(
+ float64(c.Registry.Metadata.Subscription.Billing.PendingCharges),
+ 'f',
+ utils.FloatPrecision,
+ utils.FloatBitDepth,
+ ),
+ },
+ 20: {" "},
+ 21: {"CREATED", c.Registry.DateCreated},
+ }
+}
+
+// Paging ...
+func (c *ContainerRegistryPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// ContainerRegistriesPrinter ...
+type ContainerRegistriesPrinter struct {
+ Registries []govultr.ContainerRegistry `json:"registries"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (c *ContainerRegistriesPrinter) JSON() []byte {
+ return printer.MarshalObject(c, "json")
+}
+
+// YAML ...
+func (c *ContainerRegistriesPrinter) YAML() []byte {
+ return printer.MarshalObject(c, "yaml")
+}
+
+// Columns ...
+func (c *ContainerRegistriesPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "NAME",
+ "URN",
+ "USED/ALLOWED",
+ "REGION ID",
+ "REGION NAME",
+ "PUBLIC",
+ }}
+}
+
+// Data ...
+func (c *ContainerRegistriesPrinter) Data() [][]string {
+ if len(c.Registries) == 0 {
+ return [][]string{0: {"---", "---", "---", "---", "---", "---", "---", "---"}}
+ }
+
+ var data [][]string
+ for i := range c.Registries {
+ usage := fmt.Sprintf("%vGB / %vGB", c.Registries[i].Storage.Used.GigaBytes, c.Registries[i].Storage.Allowed.GigaBytes)
+ data = append(data, []string{
+ c.Registries[i].ID,
+ c.Registries[i].Name,
+ c.Registries[i].URN,
+ usage,
+ strconv.Itoa(c.Registries[i].Metadata.Region.ID),
+ c.Registries[i].Metadata.Region.Name,
+ strconv.FormatBool(c.Registries[i].Public),
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (c *ContainerRegistriesPrinter) Paging() [][]string {
+ return printer.NewPaging(c.Meta.Total, &c.Meta.Links.Next, &c.Meta.Links.Prev).Compose()
+}
+
+// ======================================
+
+// ContainerRegistryPlansPrinter ...
+type ContainerRegistryPlansPrinter struct {
+ Plans govultr.ContainerRegistryPlanTypes `json:"plans"`
+}
+
+// JSON ...
+func (c *ContainerRegistryPlansPrinter) JSON() []byte {
+ return printer.MarshalObject(c, "json")
+}
+
+// YAML ...
+func (c *ContainerRegistryPlansPrinter) YAML() []byte {
+ return printer.MarshalObject(c, "yaml")
+}
+
+// Columns ...
+func (c *ContainerRegistryPlansPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "NAME",
+ "MAX STORAGE",
+ "MONTHLY PRICE",
+ }}
+}
+
+// Data ...
+func (c *ContainerRegistryPlansPrinter) Data() [][]string {
+ var data [][]string
+ topVals := reflect.ValueOf(c.Plans)
+ for i := 0; i < topVals.NumField(); i++ {
+ botVals := reflect.ValueOf(topVals.Field(i).Interface())
+
+ data = append(data, []string{
+ botVals.FieldByName("VanityName").String(),
+ fmt.Sprintf("%vGB", botVals.FieldByName("MaxStorageMB").Int()/1024), //nolint:gomnd
+ strconv.FormatInt(botVals.FieldByName("MonthlyPrice").Int(), 10),
+ })
+ }
+ return data
+}
+
+// Paging ...
+func (c *ContainerRegistryPlansPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// ContainerRegistryRegionsPrinter ...
+type ContainerRegistryRegionsPrinter struct {
+ Regions []govultr.ContainerRegistryRegion `json:"regions"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (c *ContainerRegistryRegionsPrinter) JSON() []byte {
+ return printer.MarshalObject(c, "json")
+}
+
+// YAML ...
+func (c *ContainerRegistryRegionsPrinter) YAML() []byte {
+ return printer.MarshalObject(c, "yaml")
+}
+
+// Columns ...
+func (c *ContainerRegistryRegionsPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "NAME",
+ "URN",
+ "COUNTRY",
+ "REGION",
+ }}
+}
+
+// Data ...
+func (c *ContainerRegistryRegionsPrinter) Data() [][]string {
+ if len(c.Regions) == 0 {
+ return [][]string{0: {"---", "---", "---", "---", "---", "---"}}
+ }
+
+ var data [][]string
+ for i := range c.Regions {
+ data = append(data, []string{
+ strconv.Itoa(c.Regions[i].ID),
+ c.Regions[i].Name,
+ c.Regions[i].URN,
+ c.Regions[i].DataCenter.Country,
+ c.Regions[i].DataCenter.Region,
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (c *ContainerRegistryRegionsPrinter) Paging() [][]string {
+ return printer.NewPaging(c.Meta.Total, &c.Meta.Links.Next, &c.Meta.Links.Prev).Compose()
+}
+
+// ======================================
+
+// ContainerRegistryRepositoryPrinter ...
+type ContainerRegistryRepositoryPrinter struct {
+ Repository *govultr.ContainerRegistryRepo `json:"repository"`
+}
+
+// JSON ...
+func (c *ContainerRegistryRepositoryPrinter) JSON() []byte {
+ return printer.MarshalObject(c, "json")
+}
+
+// YAML ...
+func (c *ContainerRegistryRepositoryPrinter) YAML() []byte {
+ return printer.MarshalObject(c, "yaml")
+}
+
+// Columns ...
+func (c *ContainerRegistryRepositoryPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "NAME",
+ "IMAGE",
+ "DESCRIPTION",
+ "DATE CREATED",
+ "DATE MODIFIED",
+ "PULLS",
+ "ARTIFACTS",
+ }}
+}
+
+// Data ...
+func (c *ContainerRegistryRepositoryPrinter) Data() [][]string {
+ return [][]string{0: {
+ c.Repository.Name,
+ c.Repository.Image,
+ c.Repository.Description,
+ c.Repository.DateCreated,
+ c.Repository.DateModified,
+ strconv.Itoa(c.Repository.PullCount),
+ strconv.Itoa(c.Repository.ArtifactCount),
+ }}
+}
+
+// Paging ...
+func (c *ContainerRegistryRepositoryPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// ContainerRegistryRepositoriesPrinter ...
+type ContainerRegistryRepositoriesPrinter struct {
+ Repositories []govultr.ContainerRegistryRepo `json:"repositories"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (c *ContainerRegistryRepositoriesPrinter) JSON() []byte {
+ return printer.MarshalObject(c, "json")
+}
+
+// YAML ...
+func (c *ContainerRegistryRepositoriesPrinter) YAML() []byte {
+ return printer.MarshalObject(c, "yaml")
+}
+
+// Columns ...
+func (c *ContainerRegistryRepositoriesPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "NAME",
+ "IMAGE",
+ "DESCRIPTION",
+ "DATE CREATED",
+ "DATE MODIFIED",
+ "PULLS",
+ "ARTIFACTS",
+ }}
+}
+
+// Data ...
+func (c *ContainerRegistryRepositoriesPrinter) Data() [][]string {
+ if len(c.Repositories) == 0 {
+ return [][]string{0: {"---", "---", "---", "---", "---", "---", "---"}}
+ }
+
+ var data [][]string
+ for i := range c.Repositories {
+ data = append(data, []string{
+ c.Repositories[i].Name,
+ c.Repositories[i].Image,
+ c.Repositories[i].Description,
+ c.Repositories[i].DateCreated,
+ c.Repositories[i].DateModified,
+ strconv.Itoa(c.Repositories[i].PullCount),
+ strconv.Itoa(c.Repositories[i].ArtifactCount),
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (c *ContainerRegistryRepositoriesPrinter) Paging() [][]string {
+ return printer.NewPaging(c.Meta.Total, &c.Meta.Links.Next, &c.Meta.Links.Prev).Compose()
+}
+
+// ======================================
+
+// ContainerRegistryCredentialDockerPrinter ...
+type ContainerRegistryCredentialDockerPrinter struct {
+ Credential *govultr.ContainerRegistryDockerCredentials `json:"docker_credentials"`
+}
+
+// JSON ...
+func (c *ContainerRegistryCredentialDockerPrinter) JSON() []byte {
+ return printer.MarshalObject(c, "json")
+}
+
+// YAML ...
+func (c *ContainerRegistryCredentialDockerPrinter) YAML() []byte {
+ return printer.MarshalObject(c, "yaml")
+}
+
+// Columns ...
+func (c *ContainerRegistryCredentialDockerPrinter) Columns() [][]string {
+ return nil
+}
+
+// Data ...
+func (c *ContainerRegistryCredentialDockerPrinter) Data() [][]string {
+ return [][]string{0: {c.Credential.String()}}
+}
+
+// Paging ...
+func (c *ContainerRegistryCredentialDockerPrinter) Paging() [][]string {
+ return nil
+}
diff --git a/cmd/database/database.go b/cmd/database/database.go
new file mode 100644
index 00000000..fa989276
--- /dev/null
+++ b/cmd/database/database.go
@@ -0,0 +1,2612 @@
+// Package database is used by the CLI to control databases
+package database
+
+import (
+ "errors"
+ "fmt"
+ "os"
+
+ "github.com/spf13/cobra"
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+ "github.com/vultr/vultr-cli/v3/pkg/cli"
+)
+
+var (
+ long = `Get commands available to database`
+ example = `
+ # Full example
+ vultr-cli database
+ `
+ listLong = `Get all databases on your Vultr account`
+ listExample = `
+ # Full example
+ vultr-cli database list
+
+ # Summarized view
+ vultr-cli database list --summarize
+ `
+ createLong = `Create a new Managed Database with specified plan, region, and database engine/version`
+ createExample = `
+ # Full example
+ vultr-cli database create --database-engine="mysql" --database-engine-version="8" --region="ewr" \
+ --plan="vultr-dbaas-startup-cc-1-55-2" --label="example-db"
+
+ # Full example with custom MySQL settings
+ vultr-cli database create --database-engine="mysql" --database-engine-version="8" --region="ewr" \
+ --plan="vultr-dbaas-startup-cc-1-55-2" --label="example-db" --mysql-slow-query-log="true" --mysql-long-query-time="2"
+ `
+ updateLong = `Updates a Managed Database with the supplied information`
+ updateExample = `
+ # Full example
+ vultr-cli database update --region="sea" --plan="vultr-dbaas-startup-cc-2-80-4"
+
+ # Full example with custom MySQL settings
+ vultr-cli database update --mysql-slow-query-log="true" --mysql-long-query-time="2"
+ `
+)
+
+// NewCmdDatabase provides the CLI command for database functions
+func NewCmdDatabase(base *cli.Base) *cobra.Command { //nolint:funlen,gocyclo
+ o := &options{Base: base}
+
+ cmd := &cobra.Command{
+ Use: "database",
+ Short: "Access database commands",
+ Long: long,
+ Example: example,
+ PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+ utils.SetOptions(o.Base, cmd, args)
+ if !o.Base.HasAuth {
+ return errors.New(utils.APIKeyError)
+ }
+ return nil
+ },
+ }
+
+ // List
+ list := &cobra.Command{
+ Use: "list",
+ Short: "List databases",
+ Aliases: []string{"l"},
+ Long: listLong,
+ Example: listExample,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ summarize, errSu := cmd.Flags().GetBool("summarize")
+ if errSu != nil {
+ return fmt.Errorf("error parsing flag 'summarize' for database list : %v", errSu)
+ }
+
+ dbs, meta, err := o.list()
+ if err != nil {
+ return fmt.Errorf("error retrieving database list : %v", err)
+ }
+
+ var data printer.ResourceOutput
+ if summarize {
+ data = &DBsSummaryPrinter{DBs: dbs, Meta: meta}
+ } else {
+ data = &DBsPrinter{DBs: dbs, Meta: meta}
+ }
+
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ list.Flags().BoolP("summarize", "", false, "(optional) Summarize the list output. One line per database")
+
+ // Get
+ get := &cobra.Command{
+ Use: "get ",
+ Short: "Retrieve a database",
+ Aliases: []string{"g"},
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ db, err := o.get()
+ if err != nil {
+ return fmt.Errorf("error retrieving database : %v", err)
+ }
+
+ data := &DBPrinter{DB: db}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Create
+ create := &cobra.Command{
+ Use: "create",
+ Short: "Create database",
+ Aliases: []string{"c"},
+ Long: createLong,
+ Example: createExample,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ engine, errEn := cmd.Flags().GetString("database-engine")
+ if errEn != nil {
+ return fmt.Errorf("error parsing flag 'database-engine' for database create : %v", errEn)
+ }
+
+ engineVersion, errEg := cmd.Flags().GetString("database-engine-version")
+ if errEg != nil {
+ return fmt.Errorf("error parsing flag 'database-engine-version' for database create : %v", errEg)
+ }
+
+ region, errRe := cmd.Flags().GetString("region")
+ if errRe != nil {
+ return fmt.Errorf("error parsing flag 'region' for database create : %v", errRe)
+ }
+
+ plan, errPl := cmd.Flags().GetString("plan")
+ if errPl != nil {
+ return fmt.Errorf("error parsing flag 'plan' for database create : %v", errPl)
+ }
+
+ label, errLa := cmd.Flags().GetString("label")
+ if errLa != nil {
+ return fmt.Errorf("error parsing flag 'label' for database create : %v", errLa)
+ }
+
+ // Optional
+ tag, errTa := cmd.Flags().GetString("tag")
+ if errTa != nil {
+ return fmt.Errorf("error parsing flag 'tag' for database create : %v", errTa)
+ }
+
+ vpc, errVp := cmd.Flags().GetString("vpc-id")
+ if errVp != nil {
+ return fmt.Errorf("error parsing flag 'vpc-id' for database create : %v", errVp)
+ }
+
+ maintenanceDOW, errMa := cmd.Flags().GetString("maintenance-dow")
+ if errMa != nil {
+ return fmt.Errorf("error parsing flag 'maintenance-dow' for database create : %v", errMa)
+ }
+
+ maintenanceTime, errMt := cmd.Flags().GetString("maintenance-time")
+ if errMt != nil {
+ return fmt.Errorf("error parsing flag 'maintenance-time' for database create : %v", errMt)
+ }
+
+ trustedIPs, errTr := cmd.Flags().GetStringSlice("trusted-ips")
+ if errTr != nil {
+ return fmt.Errorf("error parsing flag 'trusted-ips' for database create : %v", errTr)
+ }
+
+ mysqlSQLModes, errMy := cmd.Flags().GetStringSlice("mysql-sql-modes")
+ if errMy != nil {
+ return fmt.Errorf("error parsing flag 'mysql-sql-modes' for database create : %v", errMy)
+ }
+
+ mysqlRequirePrimaryKey, errMq := cmd.Flags().GetBool("mysql-require-primary-key")
+ if errMq != nil {
+ return fmt.Errorf("error parsing flag 'mysql-require-primary-key' for database create : %v", errMq)
+ }
+
+ mySQLSlowQueryLog, errMl := cmd.Flags().GetBool("mysql-slow-query-log")
+ if errMl != nil {
+ return fmt.Errorf("error parsing flag 'mysql-slow-query-log' for database create : %v", errMl)
+ }
+
+ mySQLLongQueryTime, errMt := cmd.Flags().GetInt("mysql-long-query-time")
+ if errMt != nil {
+ return fmt.Errorf("error parsing flag 'mysql-long-query-time' for database create : %v", errMt)
+ }
+
+ redisEvictionPolicy, errEe := cmd.Flags().GetString("redis-eviction-policy")
+ if errEe != nil {
+ return fmt.Errorf("error parsing flag 'redis-eviction-policy' for database create : %v", errEe)
+ }
+
+ o.CreateReq = &govultr.DatabaseCreateReq{
+ DatabaseEngine: engine,
+ DatabaseEngineVersion: engineVersion,
+ Region: region,
+ Plan: plan,
+ Label: label,
+ Tag: tag,
+ VPCID: vpc,
+ MaintenanceDOW: maintenanceDOW,
+ MaintenanceTime: maintenanceTime,
+ TrustedIPs: trustedIPs,
+ MySQLSQLModes: mysqlSQLModes,
+ MySQLRequirePrimaryKey: &mysqlRequirePrimaryKey,
+ MySQLSlowQueryLog: &mySQLSlowQueryLog,
+ MySQLLongQueryTime: mySQLLongQueryTime,
+ RedisEvictionPolicy: redisEvictionPolicy,
+ }
+
+ db, err := o.create()
+ if err != nil {
+ return fmt.Errorf("error creating database : %v", err)
+ }
+
+ data := &DBPrinter{DB: db}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ create.Flags().StringP("database-engine", "e", "", "database engine for the new manaaged database")
+ if err := create.MarkFlagRequired("database-engine"); err != nil {
+ fmt.Printf("error marking database create 'database-engine' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ create.Flags().StringP("database-engine-version", "v", "", "database engine version for the new manaaged database")
+ if err := create.MarkFlagRequired("database-engine-version"); err != nil {
+ fmt.Printf("error marking database create 'database-engine-version' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ create.Flags().StringP("region", "r", "", "region id for the new managed database")
+ if err := create.MarkFlagRequired("region"); err != nil {
+ fmt.Printf("error marking database create 'region' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ create.Flags().StringP("plan", "p", "", "plan id for the new managed database")
+ if err := create.MarkFlagRequired("plan"); err != nil {
+ fmt.Printf("error marking database create 'plan' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ create.Flags().StringP("label", "l", "", "label for the new managed database")
+ if err := create.MarkFlagRequired("label"); err != nil {
+ fmt.Printf("error marking database create 'label' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ create.Flags().String("tag", "t", "tag for the new managed database")
+ create.Flags().String("vpc-id", "", "vpc id for the new managed database")
+ create.Flags().String("maintenance-dow", "", "maintenance day of week for the new managed database")
+ create.Flags().String("maintenance-time", "", "maintenance time for the new managed database")
+ create.Flags().StringSlice(
+ "trusted-ips",
+ []string{},
+ "comma-separated list of trusted ip addresses for the new managed database",
+ )
+ create.Flags().StringSlice("mysql-sql-modes", []string{}, "comma-separated list of sql modes for the new managed database")
+ create.Flags().Bool("mysql-require-primary-key", true, "enable requiring primary keys for the new mysql managed database")
+ create.Flags().Bool("mysql-slow-query-log", false, "enable slow query logging for the new mysql managed database")
+ create.Flags().Int(
+ "mysql-long-query-time",
+ 0,
+ "long query time for the new mysql managed database when slow query logging is enabled",
+ )
+ create.Flags().String("redis-eviction-policy", "", "eviction policy for the new redis managed database")
+
+ // Update
+ update := &cobra.Command{
+ Use: "update ",
+ Short: "Update a database",
+ Aliases: []string{"u"},
+ Long: updateLong,
+ Example: updateExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ region, errRe := cmd.Flags().GetString("region")
+ if errRe != nil {
+ return fmt.Errorf("error parsing flag 'region' for database update : %v", errRe)
+ }
+
+ plan, errPl := cmd.Flags().GetString("plan")
+ if errPl != nil {
+ return fmt.Errorf("error parsing flag 'plan' for database update : %v", errPl)
+ }
+
+ label, errLa := cmd.Flags().GetString("label")
+ if errLa != nil {
+ return fmt.Errorf("error parsing flag 'label' for database update : %v", errLa)
+ }
+
+ tag, errTa := cmd.Flags().GetString("tag")
+ if errTa != nil {
+ return fmt.Errorf("error parsing flag 'tag' for database update : %v", errTa)
+ }
+
+ maintenanceDOW, errMa := cmd.Flags().GetString("maintenance-dow")
+ if errMa != nil {
+ return fmt.Errorf("error parsing flag 'maintenance-dow' for database update : %v", errMa)
+ }
+
+ maintenanceTime, errMt := cmd.Flags().GetString("maintenance-time")
+ if errMt != nil {
+ return fmt.Errorf("error parsing flag 'maintenance-time' for database update : %v", errMt)
+ }
+
+ clusterTimeZone, errTz := cmd.Flags().GetString("cluster-time-zone")
+ if errTz != nil {
+ return fmt.Errorf("error parsing flag 'cluster-time-zone' for database update : %v", errTz)
+ }
+
+ trustedIPs, errTr := cmd.Flags().GetStringSlice("trusted-ips")
+ if errTr != nil {
+ return fmt.Errorf("error parsing flag 'trusted-ips' for database update : %v", errTr)
+ }
+
+ mysqlSQLModes, errMy := cmd.Flags().GetStringSlice("mysql-sql-modes")
+ if errMy != nil {
+ return fmt.Errorf("error parsing flag 'mysql-sql-modes' for database update : %v", errMy)
+ }
+
+ mySQLLongQueryTime, errMt := cmd.Flags().GetInt("mysql-long-query-time")
+ if errMt != nil {
+ return fmt.Errorf("error parsing flag 'mysql-long-query-time' for database update : %v", errMt)
+ }
+
+ redisEvictionPolicy, errEe := cmd.Flags().GetString("redis-eviction-policy")
+ if errEe != nil {
+ return fmt.Errorf("error parsing flag 'redis-eviction-policy' for database update : %v", errEe)
+ }
+
+ o.UpdateReq = &govultr.DatabaseUpdateReq{}
+
+ if cmd.Flags().Changed("region") {
+ o.UpdateReq.Region = region
+ }
+
+ if cmd.Flags().Changed("plan") {
+ o.UpdateReq.Plan = plan
+ }
+
+ if cmd.Flags().Changed("label") {
+ o.UpdateReq.Label = label
+ }
+
+ if cmd.Flags().Changed("tag") {
+ o.UpdateReq.Tag = tag
+ }
+
+ if cmd.Flags().Changed("maintenance-dow") {
+ o.UpdateReq.MaintenanceDOW = maintenanceDOW
+ }
+
+ if cmd.Flags().Changed("maintenance-time") {
+ o.UpdateReq.MaintenanceTime = maintenanceTime
+ }
+
+ if cmd.Flags().Changed("cluster-time-zone") {
+ o.UpdateReq.ClusterTimeZone = clusterTimeZone
+ }
+
+ if cmd.Flags().Changed("trusted-ips") {
+ o.UpdateReq.TrustedIPs = trustedIPs
+ }
+
+ if cmd.Flags().Changed("mysql-sql-modes") {
+ o.UpdateReq.MySQLSQLModes = mysqlSQLModes
+ }
+
+ if cmd.Flags().Changed("mysql-long-query-time") {
+ o.UpdateReq.MySQLLongQueryTime = mySQLLongQueryTime
+ }
+
+ if cmd.Flags().Changed("redis-eviction-policy") {
+ o.UpdateReq.RedisEvictionPolicy = redisEvictionPolicy
+ }
+
+ db, err := o.update()
+ if err != nil {
+ return fmt.Errorf("error updating database : %v", err)
+ }
+
+ data := &DBPrinter{DB: db}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ update.Flags().StringP("region", "r", "", "region id for the managed database")
+ update.Flags().StringP("plan", "p", "", "plan id for the managed database")
+ update.Flags().StringP("label", "l", "", "label for the managed database")
+ update.Flags().StringP("tag", "t", "", "tag for the managed database")
+ update.Flags().String("vpc-id", "", "vpc id for the managed database")
+ update.Flags().String("maintenance-dow", "", "maintenance day of week for the managed database")
+ update.Flags().String("maintenance-time", "", "maintenance time for the managed database")
+ update.Flags().String("cluster-time-zone", "", "configured time zone for the managed database")
+ update.Flags().StringSlice(
+ "trusted-ips",
+ []string{},
+ "comma-separated list of trusted ip addresses for the managed database",
+ )
+ update.Flags().StringSlice(
+ "mysql-sql-modes",
+ []string{},
+ "comma-separated list of sql modes for the managed database",
+ )
+ update.Flags().Bool("mysql-require-primary-key", true, "enable requiring primary keys for the mysql managed database")
+ update.Flags().Bool("mysql-slow-query-log", false, "enable slow query logging for the mysql managed database")
+ update.Flags().String(
+ "mysql-long-query-time",
+ "",
+ "long query time for the mysql managed database when slow query logging is enabled",
+ )
+ update.Flags().String("redis-eviction-policy", "", "eviction policy for the redis managed database")
+
+ // Delete
+ del := &cobra.Command{
+ Use: "delete ",
+ Short: "Delete a database",
+ Aliases: []string{"destroy", "d"},
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.del(); err != nil {
+ return fmt.Errorf("error deleting database : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Database has been deleted"), nil)
+
+ return nil
+ },
+ }
+
+ // Plan
+ plan := &cobra.Command{
+ Use: "plan",
+ Short: "Commands to access database plans",
+ }
+
+ // Plan List
+ planList := &cobra.Command{
+ Use: "list",
+ Short: "List database plans",
+ Aliases: []string{"l"},
+ RunE: func(cmd *cobra.Command, args []string) error {
+ plans, meta, err := o.listPlans()
+ if err != nil {
+ return fmt.Errorf("error retrieving database plans : %v", err)
+ }
+
+ data := &PlansPrinter{Plans: plans, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ plan.AddCommand(
+ planList,
+ )
+
+ // User
+ user := &cobra.Command{
+ Use: "user",
+ Short: "Commands to handle database users",
+ }
+
+ // User List
+ userList := &cobra.Command{
+ Use: "list ",
+ Short: "List database users",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ us, meta, err := o.listUsers()
+ if err != nil {
+ return fmt.Errorf("error retrieving database users : %v", err)
+ }
+
+ data := &UsersPrinter{Users: us, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // User Get
+ userGet := &cobra.Command{
+ Use: "get ",
+ Short: "Get a database user",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 2 {
+ return errors.New("please provide a database ID and a user name")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ us, err := o.getUser()
+ if err != nil {
+ return fmt.Errorf("error retrieving database user : %v", err)
+ }
+
+ data := &UserPrinter{User: us}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // User Create
+ userCreate := &cobra.Command{
+ Use: "create ",
+ Short: "Create a database user",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ username, errUs := cmd.Flags().GetString("username")
+ if errUs != nil {
+ return fmt.Errorf("error parsing flag 'username' for database user create : %v", errUs)
+ }
+
+ password, errPa := cmd.Flags().GetString("password")
+ if errPa != nil {
+ return fmt.Errorf("error parsing flag 'password' for database user create : %v", errPa)
+ }
+
+ encryption, errEn := cmd.Flags().GetString("encryption")
+ if errEn != nil {
+ return fmt.Errorf("error parsing flag 'encryption' for database user create : %v", errEn)
+ }
+
+ o.UserCreateReq = &govultr.DatabaseUserCreateReq{
+ Username: username,
+ Password: password,
+ Encryption: encryption,
+ }
+
+ us, err := o.createUser()
+ if err != nil {
+ return fmt.Errorf("error creating database user : %v", err)
+ }
+
+ data := &UserPrinter{User: us}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+ userCreate.Flags().StringP("username", "u", "", "username for the new manaaged database user")
+ userCreate.Flags().StringP(
+ "password",
+ "p",
+ "",
+ "password for the new manaaged database user (omit or leave empty to generate a random secure password)",
+ )
+ userCreate.Flags().StringP("encryption", "e", "", "encryption type for the new managed database user (MySQL only)")
+
+ // User Update
+ userUpdate := &cobra.Command{
+ Use: "update ",
+ Short: "Update a database user",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 2 {
+ return errors.New("please provide a database ID and a user name")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ password, errPa := cmd.Flags().GetString("password")
+ if errPa != nil {
+ return fmt.Errorf("error parsing flag 'password' for database user create : %v", errPa)
+ }
+
+ o.UserUpdateReq = &govultr.DatabaseUserUpdateReq{
+ Password: password,
+ }
+
+ us, err := o.updateUser()
+ if err != nil {
+ return fmt.Errorf("error updating database user : %v", err)
+ }
+
+ data := &UserPrinter{User: us}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ userUpdate.Flags().StringP(
+ "password",
+ "p",
+ "",
+ "password for the new manaaged database user (omit or leave empty to generate a random secure password)",
+ )
+
+ // User Delete
+ userDelete := &cobra.Command{
+ Use: "delete ",
+ Short: "Delete a database user",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 2 {
+ return errors.New("please provide a database ID and a user name")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.delUser(); err != nil {
+ return fmt.Errorf("error deleting database user : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("User deleted"), nil)
+
+ return nil
+ },
+ }
+
+ // User ACL
+ userACL := &cobra.Command{
+ Use: "acl",
+ Short: "commands to handle managed database user access control (Redis only)",
+ }
+
+ // User ACL Update
+ userACLUpdate := &cobra.Command{
+ Use: "update ",
+ Short: "Update a database user ACL",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 2 {
+ return errors.New("please provide a database ID and a user name")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ categories, errCa := cmd.Flags().GetStringSlice("redis-acl-categories")
+ if errCa != nil {
+ return fmt.Errorf("error parsing flag 'redis-acl-categories' for database user create : %v", errCa)
+ }
+
+ channels, errCh := cmd.Flags().GetStringSlice("redis-acl-channels")
+ if errCh != nil {
+ return fmt.Errorf("error parsing flag 'redis-acl-channels' for database user create : %v", errCh)
+ }
+
+ commands, errCo := cmd.Flags().GetStringSlice("redis-acl-commands")
+ if errCo != nil {
+ return fmt.Errorf("error parsing flag 'redis-acl-commands' for database user create : %v", errCo)
+ }
+
+ keys, errKe := cmd.Flags().GetStringSlice("redis-acl-keys")
+ if errKe != nil {
+ return fmt.Errorf("error parsing flag 'redis-acl-keys' for database user create : %v", errKe)
+ }
+
+ o.UserUpdateACLReq = &govultr.DatabaseUserACLReq{}
+
+ if cmd.Flags().Changed("redis-acl-categories") {
+ o.UserUpdateACLReq.RedisACLCategories = &categories
+ }
+
+ if cmd.Flags().Changed("redis-acl-channels") {
+ o.UserUpdateACLReq.RedisACLChannels = &channels
+ }
+
+ if cmd.Flags().Changed("redis-acl-commands") {
+ o.UserUpdateACLReq.RedisACLCommands = &commands
+ }
+
+ if cmd.Flags().Changed("redis-acl-keys") {
+ o.UserUpdateACLReq.RedisACLKeys = &keys
+ }
+
+ us, err := o.updateUserACL()
+ if err != nil {
+ return fmt.Errorf("error updating database user acl : %v", err)
+ }
+
+ data := &UserPrinter{User: us}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ userACLUpdate.Flags().StringSlice(
+ "redis-acl-categories",
+ []string{},
+ "list of rules for command categories",
+ )
+ userACLUpdate.Flags().StringSlice(
+ "redis-acl-channels",
+ []string{},
+ "list of publish/subscribe channel patterns",
+ )
+ userACLUpdate.Flags().StringSlice(
+ "redis-acl-commands",
+ []string{},
+ "list of rules for individual commands",
+ )
+ userACLUpdate.Flags().StringSlice(
+ "redis-acl-keys",
+ []string{},
+ "list of key access rules",
+ )
+
+ userACLUpdate.MarkFlagsOneRequired(
+ "redis-acl-categories",
+ "redis-acl-channels",
+ "redis-acl-commands",
+ "redis-acl-keys",
+ )
+
+ userACL.AddCommand(
+ userACLUpdate,
+ )
+
+ user.AddCommand(
+ userList,
+ userGet,
+ userCreate,
+ userUpdate,
+ userDelete,
+ userACL,
+ )
+
+ // Logical Database
+ db := &cobra.Command{
+ Use: "db",
+ Short: "Commands to handle database logical dbs",
+ }
+
+ // Logical DB List
+ dbList := &cobra.Command{
+ Use: "list ",
+ Short: "List logical databases",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ dbs, meta, err := o.listDBs()
+ if err != nil {
+ return fmt.Errorf("error retrieving logical databases: %v", err)
+ }
+
+ data := &LogicalDBsPrinter{DBs: dbs, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Logical DB Create
+ dbCreate := &cobra.Command{
+ Use: "create ",
+ Short: "Create a logical database ",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ name, errNa := cmd.Flags().GetString("name")
+ if errNa != nil {
+ return fmt.Errorf("error parsing flag 'name' for logical database create : %v", errNa)
+ }
+
+ o.DBCreateReq = &govultr.DatabaseDBCreateReq{
+ Name: name,
+ }
+
+ db, err := o.createDB()
+ if err != nil {
+ return fmt.Errorf("error creating a logical database : %v", err)
+ }
+
+ data := &LogicalDBPrinter{DB: db}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ dbCreate.Flags().StringP("name", "n", "", "name of the new logical database within the manaaged database")
+ if err := dbCreate.MarkFlagRequired("name"); err != nil {
+ fmt.Printf("error marking logical database create 'name' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ // Logical DB Delete
+ dbDel := &cobra.Command{
+ Use: "delete ",
+ Short: "Delete a logical database ",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 2 {
+ return errors.New("please provide a database ID and a DB name")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.delDB(); err != nil {
+ return fmt.Errorf("error deleting logical database : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Logical DB deleted"), nil)
+
+ return nil
+ },
+ }
+
+ db.AddCommand(
+ dbList,
+ dbCreate,
+ dbDel,
+ )
+
+ // Usage
+ usage := &cobra.Command{
+ Use: "usage",
+ Short: "Commands to display database usage information",
+ }
+
+ // Usage Get
+ usageGet := &cobra.Command{
+ Use: "get ",
+ Short: "Get database usage",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ us, err := o.getUsage()
+ if err != nil {
+ return fmt.Errorf("error retrieving database usage : %v", err)
+ }
+
+ data := &UsagePrinter{Usage: us}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ usage.AddCommand(
+ usageGet,
+ )
+
+ // Maintenance
+ maintenance := &cobra.Command{
+ Use: "maintenance",
+ Short: "Commands to handle database maintenance updates",
+ }
+
+ // Maintenance List
+ maintenanceList := &cobra.Command{
+ Use: "list ",
+ Short: "List maintenance updates for a database",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ upds, err := o.listMaintUpdates()
+ if err != nil {
+ return fmt.Errorf("error retrieving database maintenance updates : %v", err)
+ }
+
+ data := &UpdatesPrinter{Updates: upds}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Maintenance Start
+ maintenanceStart := &cobra.Command{
+ Use: "start ",
+ Short: "Start database maintenance update",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ message, err := o.startMaintUpdate()
+ if err != nil {
+ return fmt.Errorf("error starting database maintenance update: %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info(message), nil)
+
+ return nil
+ },
+ }
+
+ maintenance.AddCommand(
+ maintenanceList,
+ maintenanceStart,
+ )
+
+ // Alert
+ alert := &cobra.Command{
+ Use: "alert",
+ Short: "Commands to handle database alerts",
+ }
+
+ // Alert List
+ alertList := &cobra.Command{
+ Use: "list ",
+ Short: "List database alerts",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ period, errPe := cmd.Flags().GetString("period")
+ if errPe != nil {
+ return fmt.Errorf("error parsing flag 'period' for alert list : %v", errPe)
+ }
+
+ o.AlertsReq = &govultr.DatabaseListAlertsReq{
+ Period: period,
+ }
+
+ als, err := o.listAlerts()
+ if err != nil {
+ return fmt.Errorf("error retrieving database alerts : %v", err)
+ }
+
+ data := &AlertsPrinter{Alerts: als}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ alertList.Flags().StringP(
+ "period",
+ "p",
+ "",
+ "period (day, week, month, year) for viewing service alerts for a manaaged database",
+ )
+ if err := alertList.MarkFlagRequired("period"); err != nil {
+ fmt.Printf("error marking alert list 'period' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ alert.AddCommand(
+ alertList,
+ )
+
+ // Migration
+ migration := &cobra.Command{
+ Use: "migration",
+ Short: "Commands to handle database migrations",
+ }
+
+ // Migration Get
+ migrationGet := &cobra.Command{
+ Use: "get ",
+ Short: "Get migration status of a database",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ mig, err := o.getMigrationStatus()
+ if err != nil {
+ return fmt.Errorf("error retrieving database migration status : %v", err)
+ }
+
+ data := &MigrationPrinter{Migration: mig}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Migration Start
+ migrationStart := &cobra.Command{
+ Use: "start ",
+ Short: "Get migration status of a database",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ host, errHo := cmd.Flags().GetString("host")
+ if errHo != nil {
+ return fmt.Errorf("error parsing flag 'encryption' for migration start : %v", errHo)
+ }
+
+ port, errPo := cmd.Flags().GetInt("port")
+ if errPo != nil {
+ return fmt.Errorf("error parsing flag 'encryption' for migration start : %v", errPo)
+ }
+
+ username, errUs := cmd.Flags().GetString("username")
+ if errUs != nil {
+ return fmt.Errorf("error parsing flag 'encryption' for migration start : %v", errUs)
+ }
+
+ password, errPa := cmd.Flags().GetString("password")
+ if errPa != nil {
+ return fmt.Errorf("error parsing flag 'encryption' for migration start : %v", errPa)
+ }
+
+ database, errDa := cmd.Flags().GetString("database")
+ if errDa != nil {
+ return fmt.Errorf("error parsing flag 'encryption' for migration start : %v", errDa)
+ }
+
+ ignored, errIg := cmd.Flags().GetString("ignored-dbs")
+ if errIg != nil {
+ return fmt.Errorf("error parsing flag 'encryption' for migration start : %v", errIg)
+ }
+
+ ssl, errSs := cmd.Flags().GetBool("ssl")
+ if errSs != nil {
+ return fmt.Errorf("error parsing flag 'encryption' for migration start : %v", errSs)
+ }
+
+ o.MigrationReq = &govultr.DatabaseMigrationStartReq{
+ Host: host,
+ Port: port,
+ Username: username,
+ Password: password,
+ Database: database,
+ IgnoredDatabases: ignored,
+ SSL: &ssl,
+ }
+
+ mig, err := o.startMigration()
+ if err != nil {
+ return fmt.Errorf("error retrieving database migration status : %v", err)
+ }
+
+ data := &MigrationPrinter{Migration: mig}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ migrationStart.Flags().String("host", "", "source host for the manaaged database migration")
+ migrationStart.Flags().Int("port", 0, "source port for the manaaged database migration")
+ migrationStart.Flags().String(
+ "username",
+ "",
+ "source username for the manaaged database migration (uses `default` for Redis if omitted)",
+ )
+ migrationStart.Flags().String("password", "", "source password for the manaaged database migration")
+ migrationStart.Flags().String(
+ "database",
+ "",
+ "source database for the manaaged database migration (MySQL/PostgreSQL only)",
+ )
+ migrationStart.Flags().String(
+ "ignored-dbs",
+ "",
+ "comma-separated list of ignored databases for the manaaged database migration (MySQL/PostgreSQL only)",
+ )
+ migrationStart.Flags().Bool("ssl", true, "source ssl requirement for the manaaged database migration")
+
+ // Migration Detach
+ migrationDetach := &cobra.Command{
+ Use: "detach ",
+ Short: "Detach a migration from a database ",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.detachMigration(); err != nil {
+ return fmt.Errorf("error detaching migration from database : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Migration detached"), nil)
+
+ return nil
+ },
+ }
+
+ migration.AddCommand(
+ migrationGet,
+ migrationStart,
+ migrationDetach,
+ )
+
+ // Read Replica
+ readReplica := &cobra.Command{
+ Use: "read-replica",
+ Short: "Commands to handle database read replicas",
+ }
+
+ // Read Replica Add
+ readReplicaCreate := &cobra.Command{
+ Use: "create ",
+ Short: "Create a read-only replica of a database",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ region, errRe := cmd.Flags().GetString("region")
+ if errRe != nil {
+ return fmt.Errorf("error parsing flag 'region' for read-replica create : %v", errRe)
+ }
+
+ label, errLa := cmd.Flags().GetString("label")
+ if errLa != nil {
+ return fmt.Errorf("error parsing flag 'label' for read-replica create : %v", errLa)
+ }
+
+ o.ReadReplicaCreateReq = &govultr.DatabaseAddReplicaReq{
+ Region: region,
+ Label: label,
+ }
+
+ rr, err := o.createReadReplica()
+ if err != nil {
+ return fmt.Errorf("error creating database read replica: %v", err)
+ }
+
+ data := &DBPrinter{DB: rr}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ readReplicaCreate.Flags().StringP("region", "r", "", "region id for the new managed database read replica")
+ if err := readReplicaCreate.MarkFlagRequired("region"); err != nil {
+ fmt.Printf("error marking read replica create 'region' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ readReplicaCreate.Flags().StringP("label", "l", "", "label for the new managed database read replica")
+ if err := readReplicaCreate.MarkFlagRequired("label"); err != nil {
+ fmt.Printf("error marking read replica create 'label' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ // Read Replica Promote
+ readReplicaPromote := &cobra.Command{
+ Use: "promote ",
+ Short: "Promote a read-only replica of a database",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.promoteReadReplica(); err != nil {
+ return fmt.Errorf("error promoting database read replica: %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Read replica has been promoted"), nil)
+
+ return nil
+ },
+ }
+
+ readReplica.AddCommand(
+ readReplicaCreate,
+ readReplicaPromote,
+ )
+
+ // Backup
+ backup := &cobra.Command{
+ Use: "backup",
+ Short: "Commands to handle database backups, restores and forks",
+ }
+
+ // Backup Get
+ backupGet := &cobra.Command{
+ Use: "get ",
+ Short: "Get get latest and oldest database backup",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ bk, err := o.getBackup()
+ if err != nil {
+ return fmt.Errorf("error retrieving database backups : %v", err)
+ }
+
+ data := &BackupPrinter{Backup: bk}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Backup Restore
+ backupRestore := &cobra.Command{
+ Use: "restore ",
+ Short: "Restore a database backup ",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ label, errLa := cmd.Flags().GetString("label")
+ if errLa != nil {
+ return fmt.Errorf("error parsing flag 'label' for backup restore : %v", errLa)
+ }
+
+ rtype, errRt := cmd.Flags().GetString("type")
+ if errRt != nil {
+ return fmt.Errorf("error parsing flag 'type' for backup restore : %v", errRt)
+ }
+
+ date, errDa := cmd.Flags().GetString("date")
+ if errDa != nil {
+ return fmt.Errorf("error parsing flag 'date' for backup restore : %v", errDa)
+ }
+
+ time, errTi := cmd.Flags().GetString("time")
+ if errTi != nil {
+ return fmt.Errorf("error parsing flag 'time' for backup restore : %v", errTi)
+ }
+
+ o.BackupReq = &govultr.DatabaseBackupRestoreReq{
+ Label: label,
+ Type: rtype,
+ Date: date,
+ Time: time,
+ }
+
+ bk, err := o.restoreBackup()
+ if err != nil {
+ return fmt.Errorf("error restoring database from backup : %v", err)
+ }
+
+ data := &DBPrinter{DB: bk}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ backupRestore.Flags().String("label", "", "label for the new managed database restored from backup")
+ if err := backupRestore.MarkFlagRequired("label"); err != nil {
+ fmt.Printf("error marking backup restore 'label' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ backupRestore.Flags().String(
+ "type",
+ "",
+ "restoration type: `pitr` for point-in-time recovery or `basebackup` for latest backup (default)",
+ )
+ backupRestore.Flags().String("date", "", "backup date to use for point-in-time recovery")
+ backupRestore.Flags().String("time", "", "backup time to use for point-in-time recovery")
+
+ // Backup Fork
+ backupFork := &cobra.Command{
+ Use: "fork ",
+ Short: "Fork a database from backup",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ region, errDa := cmd.Flags().GetString("region")
+ if errDa != nil {
+ return fmt.Errorf("error parsing flag 'region' for backup fork: %v", errDa)
+ }
+
+ plan, errPl := cmd.Flags().GetString("plan")
+ if errPl != nil {
+ return fmt.Errorf("error parsing flag 'time' for backup fork: %v", errPl)
+ }
+
+ label, errLa := cmd.Flags().GetString("label")
+ if errLa != nil {
+ return fmt.Errorf("error parsing flag 'label' for backup fork : %v", errLa)
+ }
+
+ rtype, errRt := cmd.Flags().GetString("type")
+ if errRt != nil {
+ return fmt.Errorf("error parsing flag 'type' for backup fork: %v", errRt)
+ }
+
+ date, errDa := cmd.Flags().GetString("date")
+ if errDa != nil {
+ return fmt.Errorf("error parsing flag 'date' for backup fork: %v", errDa)
+ }
+
+ time, errTi := cmd.Flags().GetString("time")
+ if errTi != nil {
+ return fmt.Errorf("error parsing flag 'time' for backup fork: %v", errTi)
+ }
+
+ o.ForkReq = &govultr.DatabaseForkReq{
+ Label: label,
+ Region: region,
+ Plan: plan,
+ Type: rtype,
+ Date: date,
+ Time: time,
+ }
+
+ db, err := o.fork()
+ if err != nil {
+ return fmt.Errorf("error forking database from backup : %v", err)
+ }
+
+ data := &DBPrinter{DB: db}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ backupFork.Flags().String("label", "", "label for the new managed database forked from the backup")
+ if err := backupFork.MarkFlagRequired("label"); err != nil {
+ fmt.Printf("error marking backup fork 'label' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ backupFork.Flags().String("region", "", "region id for the new managed database forked from the backup")
+ if err := backupFork.MarkFlagRequired("region"); err != nil {
+ fmt.Printf("error marking backup fork 'region' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ backupFork.Flags().String("plan", "", "plan id for the new managed database forked from the backup")
+ if err := backupFork.MarkFlagRequired("plan"); err != nil {
+ fmt.Printf("error marking backup fork 'label' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ backupFork.Flags().String(
+ "type",
+ "",
+ "restoration type: `pitr` for point-in-time recovery or `basebackup` for latest backup (default)",
+ )
+ backupFork.Flags().String("date", "", "backup date to use for point-in-time recovery")
+ backupFork.Flags().String("time", "", "backup time to use for point-in-time recovery")
+
+ backup.AddCommand(
+ backupGet,
+ backupRestore,
+ backupFork,
+ )
+
+ // Connection Pool
+ connectionPool := &cobra.Command{
+ Use: "connection-pool",
+ Short: "Commands to handle PostgreSQL database connection pools",
+ }
+
+ // Connection Pool List
+ connectionPoolList := &cobra.Command{
+ Use: "list ",
+ Short: "List connection pools within a PostgreSQL managed database",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ cns, pools, meta, err := o.listConnectionPools()
+ if err != nil {
+ return fmt.Errorf("error retrieving connection pool data : %v", err)
+ }
+
+ data := &ConnectionsPrinter{Connections: cns, ConnectionPools: pools, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Connection Pool Get
+ connectionPoolGet := &cobra.Command{
+ Use: "get ",
+ Short: "Get a database connection pool",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 2 {
+ return errors.New("please provide a database ID and a pool name")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ cnp, err := o.getConnectionPool()
+ if err != nil {
+ return fmt.Errorf("error retrieving connection pool: %v", err)
+ }
+
+ data := &ConnectionPoolPrinter{ConnectionPool: cnp}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Connection Pool Create
+ connectionPoolCreate := &cobra.Command{
+ Use: "create ",
+ Short: "Create a database connection pool",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ name, errNa := cmd.Flags().GetString("name")
+ if errNa != nil {
+ return fmt.Errorf("error parsing flag 'name' for connection pool create : %v", errNa)
+ }
+
+ database, errDa := cmd.Flags().GetString("database")
+ if errDa != nil {
+ return fmt.Errorf("error parsing flag 'database' for connection pool create : %v", errDa)
+ }
+
+ username, errUs := cmd.Flags().GetString("username")
+ if errUs != nil {
+ return fmt.Errorf("error parsing flag 'username' for connection pool create : %v", errUs)
+ }
+
+ mode, errMo := cmd.Flags().GetString("mode")
+ if errMo != nil {
+ return fmt.Errorf("error parsing flag 'mode' for connection pool create : %v", errMo)
+ }
+
+ size, errSi := cmd.Flags().GetInt("size")
+ if errSi != nil {
+ return fmt.Errorf("error parsing flag 'size' for connection pool create : %v", errSi)
+ }
+
+ o.ConnectionPoolCreateReq = &govultr.DatabaseConnectionPoolCreateReq{
+ Name: name,
+ Database: database,
+ Username: username,
+ Mode: mode,
+ Size: size,
+ }
+
+ cnp, err := o.createConnectionPool()
+ if err != nil {
+ return fmt.Errorf("error creating connection pool: %v", err)
+ }
+
+ data := &ConnectionPoolPrinter{ConnectionPool: cnp}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ connectionPoolCreate.Flags().StringP("name", "n", "", "name for the new managed database connection pool")
+ if err := connectionPoolCreate.MarkFlagRequired("name"); err != nil {
+ fmt.Printf("error marking connection pool create 'name' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ connectionPoolCreate.Flags().StringP("database", "d", "", "database for the new managed database connection pool")
+ if err := connectionPoolCreate.MarkFlagRequired("database"); err != nil {
+ fmt.Printf("error marking connection pool create 'database' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ connectionPoolCreate.Flags().StringP("username", "u", "", "username for the new managed database connection pool")
+ if err := connectionPoolCreate.MarkFlagRequired("username"); err != nil {
+ fmt.Printf("error marking connection pool create 'username' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ connectionPoolCreate.Flags().StringP("mode", "m", "", "mode for the new managed database connection pool")
+ if err := connectionPoolCreate.MarkFlagRequired("mode"); err != nil {
+ fmt.Printf("error marking connection pool create 'mode' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ connectionPoolCreate.Flags().IntP("size", "s", 0, "size for the new managed database connection pool")
+ if err := connectionPoolCreate.MarkFlagRequired("size"); err != nil {
+ fmt.Printf("error marking connection pool create 'size' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ // Connection Pool Update
+ connectionPoolUpdate := &cobra.Command{
+ Use: "update ",
+ Short: "Update a database connection pool",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 2 {
+ return errors.New("please provide a database ID pool name")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ database, errDa := cmd.Flags().GetString("database")
+ if errDa != nil {
+ return fmt.Errorf("error parsing flag 'database' for connection pool update : %v", errDa)
+ }
+
+ username, errUs := cmd.Flags().GetString("username")
+ if errUs != nil {
+ return fmt.Errorf("error parsing flag 'username' for connection pool update : %v", errUs)
+ }
+
+ mode, errMo := cmd.Flags().GetString("mode")
+ if errMo != nil {
+ return fmt.Errorf("error parsing flag 'mode' for connection pool update : %v", errMo)
+ }
+
+ size, errSi := cmd.Flags().GetInt("size")
+ if errSi != nil {
+ return fmt.Errorf("error parsing flag 'size' for connection pool update : %v", errSi)
+ }
+
+ o.ConnectionPoolCreateReq = &govultr.DatabaseConnectionPoolCreateReq{}
+
+ if cmd.Flags().Changed("database") {
+ o.ConnectionPoolCreateReq.Database = database
+ }
+
+ if cmd.Flags().Changed("username") {
+ o.ConnectionPoolCreateReq.Username = username
+ }
+
+ if cmd.Flags().Changed("mode") {
+ o.ConnectionPoolCreateReq.Mode = mode
+ }
+
+ if cmd.Flags().Changed("size") {
+ o.ConnectionPoolCreateReq.Size = size
+ }
+
+ cnp, err := o.updateConnectionPool()
+ if err != nil {
+ return fmt.Errorf("error updating connection pool : %v", err)
+ }
+
+ data := &ConnectionPoolPrinter{ConnectionPool: cnp}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ connectionPoolUpdate.Flags().StringP("database", "d", "", "database for the managed database connection pool")
+ connectionPoolUpdate.Flags().StringP("username", "u", "", "username for the managed database connection pool")
+ connectionPoolUpdate.Flags().StringP("mode", "m", "", "mode for the managed database connection pool")
+ connectionPoolUpdate.Flags().IntP("size", "s", 0, "size for the managed database connection pool")
+
+ connectionPoolUpdate.MarkFlagsOneRequired(
+ "database",
+ "username",
+ "mode",
+ "size",
+ )
+
+ // Connection Pool Delete
+ connectionPoolDelete := &cobra.Command{
+ Use: "delete ",
+ Short: "Delete a database connection pool",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 2 {
+ return errors.New("please provide a database ID and a pool name")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.delConnectionPool(); err != nil {
+ return fmt.Errorf("error deleting connection pool : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Connection pool has been deleted"), nil)
+
+ return nil
+ },
+ }
+
+ connectionPool.AddCommand(
+ connectionPoolList,
+ connectionPoolGet,
+ connectionPoolCreate,
+ connectionPoolUpdate,
+ connectionPoolDelete,
+ )
+
+ // Advanced Option
+ advancedOption := &cobra.Command{
+ Use: "advanced-option",
+ Short: "Commands to handle PostgreSQL database advanced options",
+ }
+
+ // Advanced Option List
+ advancedOptionList := &cobra.Command{
+ Use: "list ",
+ Short: "List all available and configured advanced options for a PostgreSQL database",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ cur, avail, err := o.listAdvancedOptions()
+ if err != nil {
+ return fmt.Errorf("error retrieving database options : %v", err)
+ }
+
+ data := &AdvancedOptionsPrinter{Configured: cur, Available: avail}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Advanced Option Update
+ advancedOptionUpdate := &cobra.Command{
+ Use: "update ",
+ Short: "Update advanced options for a PostgreSQL managed database",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ autovacuumAnalyzeScaleFactor, errAu := cmd.Flags().GetFloat32("autovacuum-analyze-scale-factor")
+ if errAu != nil {
+ return fmt.Errorf("error parsing flag 'autovacuum-analyze-scale-factor' for advanced options update : %v", errAu)
+ }
+
+ autovacuumAnalyzeThreshold, errAt := cmd.Flags().GetInt("autovacuum-analyze-threshold")
+ if errAt != nil {
+ return fmt.Errorf("error parsing flag 'autovacuum-analyze-threshold' for advanced options update : %v", errAt)
+ }
+
+ autovacuumFreezeMaxAge, errAo := cmd.Flags().GetInt("autovacuum-freeze-max-age")
+ if errAo != nil {
+ return fmt.Errorf("error parsing flag 'autovacuum-freeze-max-age' for advanced options update : %v", errAo)
+ }
+
+ autovacuumMaxWorkers, errAv := cmd.Flags().GetInt("autovacuum-max-workers")
+ if errAv != nil {
+ return fmt.Errorf("error parsing flag 'autovacuum-max-workers' for advanced options update : %v", errAv)
+ }
+
+ autovacuumNaptime, errAa := cmd.Flags().GetInt("autovacuum-naptime")
+ if errAa != nil {
+ return fmt.Errorf("error parsing flag 'autovacuum-naptime' for advanced options update : %v", errAa)
+ }
+
+ autovacuumVacuumCostDelay, errAc := cmd.Flags().GetInt("autovacuum-vacuum-cost-delay")
+ if errAc != nil {
+ return fmt.Errorf("error parsing flag 'autovacuum-vacuum-cost-delay' for advanced options update : %v", errAc)
+ }
+
+ autovacuumVacuumCostLimit, errAm := cmd.Flags().GetInt("autovacuum-vacuum-cost-limit")
+ if errAm != nil {
+ return fmt.Errorf("error parsing flag 'autovacuum-vacuum-cost-limit' for advanced options update : %v", errAm)
+ }
+
+ autovacuumVacuumScaleFactor, errAb := cmd.Flags().GetFloat32("autovacuum-vacuum-scale-factor")
+ if errAb != nil {
+ return fmt.Errorf("error parsing flag 'autovacuum-vacuum-scale-factor' for advanced options update : %v", errAb)
+ }
+
+ autovacuumVacuumThreshold, errAz := cmd.Flags().GetInt("autovacuum-vacuum-threshold")
+ if errAz != nil {
+ return fmt.Errorf("error parsing flag 'autovacuum-vacuum-threshold' for advanced options update : %v", errAz)
+ }
+
+ bgwriterDelay, errBg := cmd.Flags().GetInt("bgwriter-delay")
+ if errBg != nil {
+ return fmt.Errorf("error parsing flag 'bgwriter-delay' for advanced options update : %v", errBg)
+ }
+
+ bgwriterFlushAfter, errBw := cmd.Flags().GetInt("bgwriter-flush-after")
+ if errBw != nil {
+ return fmt.Errorf("error parsing flag 'bgwriter-flush-after' for advanced options update : %v", errBw)
+ }
+
+ bgwriterLruMaxpages, errBr := cmd.Flags().GetInt("bgwriter-lru-maxpages")
+ if errBr != nil {
+ return fmt.Errorf("error parsing flag 'bgwriter-lru-maxpages' for advanced options update : %v", errBr)
+ }
+
+ bgwriterLruMultiplier, errBi := cmd.Flags().GetFloat32("bgwriter-lru-multiplier")
+ if errBi != nil {
+ return fmt.Errorf("error parsing flag 'bgwriter-lru-multiplier' for advanced options update : %v", errBi)
+ }
+
+ deadlockTimeout, errDe := cmd.Flags().GetInt("deadlock-timeout")
+ if errDe != nil {
+ return fmt.Errorf("error parsing flag 'deadlock-timeout' for advanced options update : %v", errDe)
+ }
+
+ defaultToastCompression, errDf := cmd.Flags().GetString("default-toast-compression")
+ if errDf != nil {
+ return fmt.Errorf("error parsing flag 'default-toast-compression' for advanced options update : %v", errDf)
+ }
+
+ idleInTransactionSessionTimeout, errIl := cmd.Flags().GetInt("idle-in-transaction-session-timeout")
+ if errIl != nil {
+ return fmt.Errorf("error parsing flag 'idle-in-transaction-session-timeout' for advanced options update : %v", errIl)
+ }
+
+ jit, errJi := cmd.Flags().GetBool("jit")
+ if errJi != nil {
+ return fmt.Errorf("error parsing flag 'jit' for advanced options update : %v", errJi)
+ }
+
+ logAutovacuumMinDuration, errLo := cmd.Flags().GetInt("log-autovacuum-min-duration")
+ if errLo != nil {
+ return fmt.Errorf("error parsing flag 'log-autovacuum-min-duration' for advanced options update : %v", errLo)
+ }
+
+ logErrorVerbosity, errLg := cmd.Flags().GetString("log-error-verbosity")
+ if errLg != nil {
+ return fmt.Errorf("error parsing flag 'log-error-verbosity' for advanced options update : %v", errLg)
+ }
+
+ logLinePrefix, errLl := cmd.Flags().GetString("log-line-prefix")
+ if errLl != nil {
+ return fmt.Errorf("error parsing flag 'log-line-prefix' for advanced options update : %v", errLl)
+ }
+
+ logMinDurationStatement, errLm := cmd.Flags().GetInt("log-min-duration-statement")
+ if errLm != nil {
+ return fmt.Errorf("error parsing flag 'log-min-duration-statement' for advanced options update : %v", errLm)
+ }
+
+ maxFilesPerProcess, errMa := cmd.Flags().GetInt("max-files-per-process")
+ if errMa != nil {
+ return fmt.Errorf("error parsing flag 'max-files-per-process' for advanced options update : %v", errMa)
+ }
+
+ maxLocksPerTransaction, errMx := cmd.Flags().GetInt("max-locks-per-transaction")
+ if errMx != nil {
+ return fmt.Errorf("error parsing flag 'max-locks-per-transaction' for advanced options update : %v", errMx)
+ }
+
+ maxLogicalReplicationWorkers, errMl := cmd.Flags().GetInt("max-logical-replication-workers")
+ if errMl != nil {
+ return fmt.Errorf("error parsing flag 'max-logical-replication-workers' for advanced options update : %v", errMl)
+ }
+
+ maxParallelWorkers, errMo := cmd.Flags().GetInt("max-parallel-workers")
+ if errMo != nil {
+ return fmt.Errorf("error parsing flag 'max-parallel-workers' for advanced options update : %v", errMo)
+ }
+
+ maxParallelWorkersPerGather, errMp := cmd.Flags().GetInt("max-parallel-workers-per-gather")
+ if errMp != nil {
+ return fmt.Errorf("error parsing flag 'max-parallel-workers-per-gather' for advanced options update : %v", errMp)
+ }
+
+ maxPredLocksPerTransaction, errMr := cmd.Flags().GetInt("max-pred-locks-per-transaction")
+ if errMr != nil {
+ return fmt.Errorf("error parsing flag 'max-pred-locks-per-transaction' for advanced options update : %v", errMr)
+ }
+
+ maxPreparedTransactions, errMe := cmd.Flags().GetInt("max-prepared-transactions")
+ if errMe != nil {
+ return fmt.Errorf("error parsing flag 'max-prepared-transactions' for advanced options update : %v", errMe)
+ }
+
+ maxReplicationSlots, errMi := cmd.Flags().GetInt("max-replication-slots")
+ if errMi != nil {
+ return fmt.Errorf("error parsing flag 'max-replication-slots' for advanced options update : %v", errMi)
+ }
+
+ maxStackDepth, errMs := cmd.Flags().GetInt("max-stack-depth")
+ if errMs != nil {
+ return fmt.Errorf("error parsing flag 'max-stack-depth' for advanced options update : %v", errMs)
+ }
+
+ maxStandbyArchiveDelay, errMv := cmd.Flags().GetInt("max-standby-archive-delay")
+ if errMv != nil {
+ return fmt.Errorf("error parsing flag 'max-standby-archive-delay' for advanced options update : %v", errMv)
+ }
+
+ maxStandbyStreamingDelay, errMy := cmd.Flags().GetInt("max-standby-streaming-delay")
+ if errMy != nil {
+ return fmt.Errorf("error parsing flag 'max-standby-streaming-delay' for advanced options update : %v", errMy)
+ }
+
+ maxWalSenders, errMd := cmd.Flags().GetInt("max-wal-senders")
+ if errMd != nil {
+ return fmt.Errorf("error parsing flag 'max-wal-senders' for advanced options update : %v", errMd)
+ }
+
+ maxWorkerProcesses, errMs := cmd.Flags().GetInt("max-worker-processes")
+ if errMs != nil {
+ return fmt.Errorf("error parsing flag 'max-worker-processes' for advanced options update : %v", errMs)
+ }
+
+ pgPartmanBGWInterval, errPg := cmd.Flags().GetInt("pg-partman-bgw-interval")
+ if errPg != nil {
+ return fmt.Errorf("error parsing flag 'pg-partman-bgw-interval' for advanced options update : %v", errPg)
+ }
+
+ pgPartmanBGWRole, errPp := cmd.Flags().GetString("pg-partman-bgw-role")
+ if errPp != nil {
+ return fmt.Errorf("error parsing flag 'pg-partman-bgw-role' for advanced options update : %v", errPp)
+ }
+
+ pgStatStatementsTrack, errPs := cmd.Flags().GetString("pg-stat-statements-track")
+ if errPs != nil {
+ return fmt.Errorf("error parsing flag 'pg-stat-statements-track' for advanced options update : %v", errPs)
+ }
+
+ tempFileLimit, errTe := cmd.Flags().GetInt("temp-file-limit")
+ if errTe != nil {
+ return fmt.Errorf("error parsing flag 'temp-file-limit' for advanced options update : %v", errTe)
+ }
+
+ trackActivityQuerySize, errTr := cmd.Flags().GetInt("track-activity-query-size")
+ if errTr != nil {
+ return fmt.Errorf("error parsing flag 'track-activity-query-size' for advanced options update : %v", errTr)
+ }
+
+ trackCommitTimestamp, errTa := cmd.Flags().GetString("track-commit-timestamp")
+ if errTa != nil {
+ return fmt.Errorf("error parsing flag 'track-commit-timestamp' for advanced options update : %v", errTa)
+ }
+
+ trackFunctions, errTc := cmd.Flags().GetString("track-functions")
+ if errTc != nil {
+ return fmt.Errorf("error parsing flag 'track-functions' for advanced options update : %v", errTc)
+ }
+
+ trackIOTiming, errTi := cmd.Flags().GetString("track-io-timing")
+ if errTi != nil {
+ return fmt.Errorf("error parsing flag 'track-io-timing' for advanced options update : %v", errTi)
+ }
+
+ walSenderTimeout, errWa := cmd.Flags().GetInt("wal-sender-timeout")
+ if errWa != nil {
+ return fmt.Errorf("error parsing flag 'wal-sender-timeout' for advanced options update : %v", errWa)
+ }
+
+ walWriterDelay, errWl := cmd.Flags().GetInt("wal-writer-delay")
+ if errWl != nil {
+ return fmt.Errorf("error parsing flag 'wal-writer-delay' for advanced options update : %v", errWl)
+ }
+
+ o.AdvancedOptionsReq = &govultr.DatabaseAdvancedOptions{}
+
+ if cmd.Flags().Changed("autovacuum-analyze-scale-factor") {
+ o.AdvancedOptionsReq.AutovacuumAnalyzeScaleFactor = autovacuumAnalyzeScaleFactor
+ }
+
+ if cmd.Flags().Changed("autovacuum-analyze-threshold") {
+ o.AdvancedOptionsReq.AutovacuumAnalyzeThreshold = autovacuumAnalyzeThreshold
+ }
+
+ if cmd.Flags().Changed("autovacuum-freeze-max-age") {
+ o.AdvancedOptionsReq.AutovacuumFreezeMaxAge = autovacuumFreezeMaxAge
+ }
+
+ if cmd.Flags().Changed("autovacuum-max-workers") {
+ o.AdvancedOptionsReq.AutovacuumMaxWorkers = autovacuumMaxWorkers
+ }
+
+ if cmd.Flags().Changed("autovacuum-naptime") {
+ o.AdvancedOptionsReq.AutovacuumNaptime = autovacuumNaptime
+ }
+
+ if cmd.Flags().Changed("autovacuum-vacuum-cost-delay") {
+ o.AdvancedOptionsReq.AutovacuumVacuumCostDelay = autovacuumVacuumCostDelay
+ }
+
+ if cmd.Flags().Changed("autovacuum-vacuum-cost-limit") {
+ o.AdvancedOptionsReq.AutovacuumVacuumCostLimit = autovacuumVacuumCostLimit
+ }
+
+ if cmd.Flags().Changed("autovacuum-vacuum-scale-factor") {
+ o.AdvancedOptionsReq.AutovacuumVacuumScaleFactor = autovacuumVacuumScaleFactor
+ }
+
+ if cmd.Flags().Changed("autovacuum-vacuum-threshold") {
+ o.AdvancedOptionsReq.AutovacuumVacuumThreshold = autovacuumVacuumThreshold
+ }
+
+ if cmd.Flags().Changed("bgwriter-delay") {
+ o.AdvancedOptionsReq.BGWRITERDelay = bgwriterDelay
+ }
+
+ if cmd.Flags().Changed("bgwriter-flush-after") {
+ o.AdvancedOptionsReq.BGWRITERFlushAFter = bgwriterFlushAfter
+ }
+
+ if cmd.Flags().Changed("bgwriter-lru-maxpages") {
+ o.AdvancedOptionsReq.BGWRITERLRUMaxPages = bgwriterLruMaxpages
+ }
+
+ if cmd.Flags().Changed("bgwriter-lru-multiplier") {
+ o.AdvancedOptionsReq.BGWRITERLRUMultiplier = bgwriterLruMultiplier
+ }
+
+ if cmd.Flags().Changed("deadlock-timeout") {
+ o.AdvancedOptionsReq.DeadlockTimeout = deadlockTimeout
+ }
+
+ if cmd.Flags().Changed("default-toast-compression") {
+ o.AdvancedOptionsReq.DefaultToastCompression = defaultToastCompression
+ }
+
+ if cmd.Flags().Changed("idle-in-transaction-session-timeout") {
+ o.AdvancedOptionsReq.IdleInTransactionSessionTimeout = idleInTransactionSessionTimeout
+ }
+
+ if cmd.Flags().Changed("jit") {
+ o.AdvancedOptionsReq.Jit = nil
+ }
+
+ if cmd.Flags().Changed("log-autovacuum-min-duration") {
+ o.AdvancedOptionsReq.LogAutovacuumMinDuration = logAutovacuumMinDuration
+ }
+
+ if cmd.Flags().Changed("log-error-verbosity") {
+ o.AdvancedOptionsReq.LogErrorVerbosity = logErrorVerbosity
+ }
+
+ if cmd.Flags().Changed("log-line-prefix") {
+ o.AdvancedOptionsReq.LogLinePrefix = logLinePrefix
+ }
+
+ if cmd.Flags().Changed("log-min-duration-statement") {
+ o.AdvancedOptionsReq.LogMinDurationStatement = logMinDurationStatement
+ }
+
+ if cmd.Flags().Changed("max-files-per-process") {
+ o.AdvancedOptionsReq.MaxFilesPerProcess = maxFilesPerProcess
+ }
+
+ if cmd.Flags().Changed("max-locks-per-transaction") {
+ o.AdvancedOptionsReq.MaxLocksPerTransaction = maxLocksPerTransaction
+ }
+
+ if cmd.Flags().Changed("max-logical-replication-workers") {
+ o.AdvancedOptionsReq.MaxLogicalReplicationWorkers = maxLogicalReplicationWorkers
+ }
+
+ if cmd.Flags().Changed("max-parallel-workers") {
+ o.AdvancedOptionsReq.MaxParallelWorkers = maxParallelWorkers
+ }
+
+ if cmd.Flags().Changed("max-parallel-workers-per-gather") {
+ o.AdvancedOptionsReq.MaxParallelWorkersPerGather = maxParallelWorkersPerGather
+ }
+
+ if cmd.Flags().Changed("max-pred-locks-per-transaction") {
+ o.AdvancedOptionsReq.MaxPredLocksPerTransaction = maxPredLocksPerTransaction
+ }
+
+ if cmd.Flags().Changed("max-prepared-transactions") {
+ o.AdvancedOptionsReq.MaxPreparedTransactions = maxPreparedTransactions
+ }
+
+ if cmd.Flags().Changed("max-replication-slots") {
+ o.AdvancedOptionsReq.MaxReplicationSlots = maxReplicationSlots
+ }
+
+ if cmd.Flags().Changed("max-stack-depth") {
+ o.AdvancedOptionsReq.MaxStackDepth = maxStackDepth
+ }
+
+ if cmd.Flags().Changed("max-standby-archive-delay") {
+ o.AdvancedOptionsReq.MaxStandbyArchiveDelay = maxStandbyArchiveDelay
+ }
+
+ if cmd.Flags().Changed("max-standby-streaming-delay") {
+ o.AdvancedOptionsReq.MaxStandbyStreamingDelay = maxStandbyStreamingDelay
+ }
+
+ if cmd.Flags().Changed("max-wal-senders") {
+ o.AdvancedOptionsReq.MaxWalSenders = maxWalSenders
+ }
+
+ if cmd.Flags().Changed("max-worker-processes") {
+ o.AdvancedOptionsReq.MaxWorkerProcesses = maxWorkerProcesses
+ }
+
+ if cmd.Flags().Changed("pg-partman-bgw-interval") {
+ o.AdvancedOptionsReq.PGPartmanBGWInterval = pgPartmanBGWInterval
+ }
+
+ if cmd.Flags().Changed("pg-partman-bgw-role") {
+ o.AdvancedOptionsReq.PGPartmanBGWRole = pgPartmanBGWRole
+ }
+
+ if cmd.Flags().Changed("pg-stat-statements-track") {
+ o.AdvancedOptionsReq.PGStateStatementsTrack = pgStatStatementsTrack
+ }
+
+ if cmd.Flags().Changed("temp-file-limit") {
+ o.AdvancedOptionsReq.TempFileLimit = tempFileLimit
+ }
+
+ if cmd.Flags().Changed("track-activity-query-size") {
+ o.AdvancedOptionsReq.TrackActivityQuerySize = trackActivityQuerySize
+ }
+
+ if cmd.Flags().Changed("track-commit-timestamp") {
+ o.AdvancedOptionsReq.TrackCommitTimestamp = trackCommitTimestamp
+ }
+
+ if cmd.Flags().Changed("track-functions") {
+ o.AdvancedOptionsReq.TrackFunctions = trackFunctions
+ }
+
+ if cmd.Flags().Changed("track-io-timing") {
+ o.AdvancedOptionsReq.TrackIOTiming = trackIOTiming
+ }
+
+ if cmd.Flags().Changed("wal-sender-timeout") {
+ o.AdvancedOptionsReq.WALSenderTImeout = walSenderTimeout
+ }
+
+ if cmd.Flags().Changed("wal-writer-delay") {
+ o.AdvancedOptionsReq.WALWriterDelay = walWriterDelay
+ }
+
+ if cmd.Flags().Changed("jit") {
+ o.AdvancedOptionsReq.Jit = &jit
+ }
+
+ cur, avail, err := o.updateAdvancedOptions()
+ if err != nil {
+ return fmt.Errorf("error updating database advanced options : %v", err)
+ }
+
+ data := &AdvancedOptionsPrinter{Configured: cur, Available: avail}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ advancedOptionUpdate.Flags().Float32(
+ "autovacuum-analyze-scale-factor",
+ 0,
+ "set the managed postgresql configuration value for autovacuum_analyze_scale_factor",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "autovacuum-analyze-threshold",
+ 0,
+ "set the managed postgresql configuration value for autovacuum_analyze_threshold",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "autovacuum-freeze-max-age",
+ 0,
+ "set the managed postgresql configuration value for autovacuum_freeze_max_age",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "autovacuum-max-workers",
+ 0,
+ "set the managed postgresql configuration value for autovacuum_max_workers",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "autovacuum-naptime",
+ 0,
+ "set the managed postgresql configuration value for autovacuum_naptime",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "autovacuum-vacuum-cost-delay",
+ 0,
+ "set the managed postgresql configuration value for autovacuum_vacuum_cost_delay",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "autovacuum-vacuum-cost-limit",
+ 0,
+ "set the managed postgresql configuration value for autovacuum_vacuum_cost_limit",
+ )
+ advancedOptionUpdate.Flags().Float32(
+ "autovacuum-vacuum-scale-factor",
+ 0,
+ "set the managed postgresql configuration value for autovacuum_vacuum_scale_factor",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "autovacuum-vacuum-threshold",
+ 0,
+ "set the managed postgresql configuration value for autovacuum_vacuum_threshold",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "bgwriter-delay",
+ 0,
+ "set the managed postgresql configuration value for bgwriter_delay",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "bgwriter-flush-after",
+ 0,
+ "set the managed postgresql configuration value for bgwriter_flush_after",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "bgwriter-lru-maxpages",
+ 0,
+ "set the managed postgresql configuration value for bgwriter_lru_maxpages",
+ )
+ advancedOptionUpdate.Flags().Float32(
+ "bgwriter-lru-multiplier",
+ 0,
+ "set the managed postgresql configuration value for bgwriter_lru_multiplier",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "deadlock-timeout",
+ 0,
+ "set the managed postgresql configuration value for deadlock_timeout",
+ )
+ advancedOptionUpdate.Flags().String(
+ "default-toast-compression",
+ "",
+ "set the managed postgresql configuration value for default_toast_compression",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "idle-in-transaction-session-timeout",
+ 0,
+ "set the managed postgresql configuration value for idle_in_transaction_session_timeout",
+ )
+ advancedOptionUpdate.Flags().Bool(
+ "jit",
+ false,
+ "set the managed postgresql configuration value for jit",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "log-autovacuum-min-duration",
+ 0,
+ "set the managed postgresql configuration value for log_autovacuum_min_duration",
+ )
+ advancedOptionUpdate.Flags().String(
+ "log-error-verbosity",
+ "",
+ "set the managed postgresql configuration value for log_error_verbosity",
+ )
+ advancedOptionUpdate.Flags().String(
+ "log-line-prefix",
+ "",
+ "set the managed postgresql configuration value for log_line_prefix",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "log-min-duration-statement",
+ 0,
+ "set the managed postgresql configuration value for log_min_duration_statement",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "max-files-per-process",
+ 0,
+ "set the managed postgresql configuration value for max_files_per_process",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "max-locks-per-transaction",
+ 0,
+ "set the managed postgresql configuration value for max_locks_per_transaction",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "max-logical-replication-workers",
+ 0,
+ "set the managed postgresql configuration value for max_logical_replication_workers",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "max-parallel-workers",
+ 0,
+ "set the managed postgresql configuration value for max_parallel_workers",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "max-parallel-workers-per-gather",
+ 0,
+ "set the managed postgresql configuration value for max_parallel_workers_per_gather",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "max-pred-locks-per-transaction",
+ 0,
+ "set the managed postgresql configuration value for max_pred_locks_per_transaction",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "max-prepared-transactions",
+ 0,
+ "set the managed postgresql configuration value for max_prepared_transactions",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "max-replication-slots",
+ 0,
+ "set the managed postgresql configuration value for max_replication_slots",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "max-stack-depth",
+ 0,
+ "set the managed postgresql configuration value for max_stack_depth",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "max-standby-archive-delay",
+ 0,
+ "set the managed postgresql configuration value for max_standby_archive_delay",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "max-standby-streaming-delay",
+ 0,
+ "set the managed postgresql configuration value for max_standby_streaming_delay",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "max-wal-senders",
+ 0,
+ "set the managed postgresql configuration value for max_wal_senders",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "max-worker-processes",
+ 0,
+ "set the managed postgresql configuration value for max_worker_processes",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "pg-partman-bgw-interval",
+ 0,
+ "set the managed postgresql configuration value for pg_partman_bgw.interval",
+ )
+ advancedOptionUpdate.Flags().String(
+ "pg-partman-bgw-role",
+ "",
+ "set the managed postgresql configuration value for pg_partman_bgw.role",
+ )
+ advancedOptionUpdate.Flags().String(
+ "pg-stat-statements-track",
+ "",
+ "set the managed postgresql configuration value for pg_stat_statements.track",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "temp-file-limit",
+ 0,
+ "set the managed postgresql configuration value for temp_file_limit",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "track-activity-query-size",
+ 0,
+ "set the managed postgresql configuration value for track_activity_query_size",
+ )
+ advancedOptionUpdate.Flags().String(
+ "track-commit-timestamp",
+ "",
+ "set the managed postgresql configuration value for track_commit_timestamp",
+ )
+ advancedOptionUpdate.Flags().String(
+ "track-functions",
+ "",
+ "set the managed postgresql configuration value for track_functions",
+ )
+ advancedOptionUpdate.Flags().String(
+ "track-io-timing",
+ "",
+ "set the managed postgresql configuration value for track_io_timing",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "wal-sender-timeout",
+ 0,
+ "set the managed postgresql configuration value for wal_sender_timeout",
+ )
+ advancedOptionUpdate.Flags().Int(
+ "wal-writer-delay",
+ 0,
+ "set the managed postgresql configuration value for wal_writer_delay",
+ )
+
+ advancedOption.AddCommand(
+ advancedOptionList,
+ advancedOptionUpdate,
+ )
+
+ // Version
+ version := &cobra.Command{
+ Use: "version",
+ Short: "Commands to handle database version upgrades",
+ }
+
+ // Version List
+ versionList := &cobra.Command{
+ Use: "list ",
+ Short: "List all version upgrades for a database",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ vs, err := o.listVersions()
+ if err != nil {
+ return fmt.Errorf("error retrieving database versions : %v", err)
+ }
+
+ data := &VersionsPrinter{Versions: vs}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Version Upgrade
+ versionUpgrade := &cobra.Command{
+ Use: "upgrade ",
+ Short: "Start a version upgrade on a database",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) != 1 {
+ return errors.New("please provide a database ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ version, errVe := cmd.Flags().GetString("version")
+ if errVe != nil {
+ return fmt.Errorf("error parsing flag 'version' for database upgrade : %v", errVe)
+ }
+
+ o.UpgradeReq = &govultr.DatabaseVersionUpgradeReq{
+ Version: version,
+ }
+
+ msg, err := o.upgradeVersion()
+ if err != nil {
+ return fmt.Errorf("error starting database version upgrade : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info(msg), nil)
+
+ return nil
+ },
+ }
+
+ versionUpgrade.Flags().StringP("version", "v", "", "version of the manaaged database to upgrade to")
+ if err := versionUpgrade.MarkFlagRequired("version"); err != nil {
+ fmt.Printf("error marking version upgrade 'version' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ version.AddCommand(
+ versionList,
+ versionUpgrade,
+ )
+
+ cmd.AddCommand(
+ list,
+ get,
+ create,
+ update,
+ del,
+ user,
+ db,
+ usage,
+ maintenance,
+ plan,
+ alert,
+ migration,
+ readReplica,
+ backup,
+ connectionPool,
+ advancedOption,
+ version,
+ )
+
+ return cmd
+}
+
+type options struct {
+ Base *cli.Base
+ CreateReq *govultr.DatabaseCreateReq
+ UpdateReq *govultr.DatabaseUpdateReq
+ UserCreateReq *govultr.DatabaseUserCreateReq
+ UserUpdateReq *govultr.DatabaseUserUpdateReq
+ UserUpdateACLReq *govultr.DatabaseUserACLReq
+ DBCreateReq *govultr.DatabaseDBCreateReq
+ AlertsReq *govultr.DatabaseListAlertsReq
+ MigrationReq *govultr.DatabaseMigrationStartReq
+ ReadReplicaCreateReq *govultr.DatabaseAddReplicaReq
+ BackupReq *govultr.DatabaseBackupRestoreReq
+ ForkReq *govultr.DatabaseForkReq
+ ConnectionPoolCreateReq *govultr.DatabaseConnectionPoolCreateReq
+ ConnectionPoolUpdateReq *govultr.DatabaseConnectionPoolUpdateReq
+ AdvancedOptionsReq *govultr.DatabaseAdvancedOptions
+ UpgradeReq *govultr.DatabaseVersionUpgradeReq
+}
+
+func (o *options) list() ([]govultr.Database, *govultr.Meta, error) {
+ dbs, meta, _, err := o.Base.Client.Database.List(o.Base.Context, nil)
+ return dbs, meta, err
+}
+
+func (o *options) get() (*govultr.Database, error) {
+ db, _, err := o.Base.Client.Database.Get(o.Base.Context, o.Base.Args[0])
+ return db, err
+}
+
+func (o *options) create() (*govultr.Database, error) {
+ db, _, err := o.Base.Client.Database.Create(o.Base.Context, o.CreateReq)
+ return db, err
+}
+
+func (o *options) update() (*govultr.Database, error) {
+ db, _, err := o.Base.Client.Database.Update(o.Base.Context, o.Base.Args[0], o.UpdateReq)
+ return db, err
+}
+
+func (o *options) del() error {
+ return o.Base.Client.Database.Delete(o.Base.Context, o.Base.Args[0])
+}
+
+func (o *options) listPlans() ([]govultr.DatabasePlan, *govultr.Meta, error) {
+ plans, meta, _, err := o.Base.Client.Database.ListPlans(o.Base.Context, nil)
+ return plans, meta, err
+}
+
+func (o *options) listUsers() ([]govultr.DatabaseUser, *govultr.Meta, error) {
+ users, meta, _, err := o.Base.Client.Database.ListUsers(o.Base.Context, o.Base.Args[0])
+ return users, meta, err
+}
+
+func (o *options) getUser() (*govultr.DatabaseUser, error) {
+ user, _, err := o.Base.Client.Database.GetUser(o.Base.Context, o.Base.Args[0], o.Base.Args[1])
+ return user, err
+}
+
+func (o *options) createUser() (*govultr.DatabaseUser, error) {
+ user, _, err := o.Base.Client.Database.CreateUser(o.Base.Context, o.Base.Args[0], o.UserCreateReq)
+ return user, err
+}
+
+func (o *options) updateUser() (*govultr.DatabaseUser, error) {
+ user, _, err := o.Base.Client.Database.UpdateUser(o.Base.Context, o.Base.Args[0], o.Base.Args[1], o.UserUpdateReq)
+ return user, err
+}
+
+func (o *options) delUser() error {
+ return o.Base.Client.Database.DeleteUser(o.Base.Context, o.Base.Args[0], o.Base.Args[1])
+}
+
+func (o *options) updateUserACL() (*govultr.DatabaseUser, error) {
+ user, _, err := o.Base.Client.Database.UpdateUserACL(o.Base.Context, o.Base.Args[0], o.Base.Args[1], o.UserUpdateACLReq)
+ return user, err
+}
+
+func (o *options) listDBs() ([]govultr.DatabaseDB, *govultr.Meta, error) {
+ dbs, meta, _, err := o.Base.Client.Database.ListDBs(o.Base.Context, o.Base.Args[0])
+ return dbs, meta, err
+}
+
+func (o *options) createDB() (*govultr.DatabaseDB, error) {
+ db, _, err := o.Base.Client.Database.CreateDB(o.Base.Context, o.Base.Args[0], o.DBCreateReq)
+ return db, err
+}
+
+func (o *options) delDB() error {
+ return o.Base.Client.Database.DeleteDB(o.Base.Context, o.Base.Args[0], o.Base.Args[1])
+}
+
+func (o *options) getUsage() (*govultr.DatabaseUsage, error) {
+ usage, _, err := o.Base.Client.Database.GetUsage(o.Base.Context, o.Base.Args[0])
+ return usage, err
+}
+
+func (o *options) listMaintUpdates() ([]string, error) {
+ updates, _, err := o.Base.Client.Database.ListMaintenanceUpdates(o.Base.Context, o.Base.Args[0])
+ return updates, err
+}
+
+func (o *options) startMaintUpdate() (string, error) {
+ updates, _, err := o.Base.Client.Database.StartMaintenance(o.Base.Context, o.Base.Args[0])
+ return updates, err
+}
+
+func (o *options) listAlerts() ([]govultr.DatabaseAlert, error) {
+ alerts, _, err := o.Base.Client.Database.ListServiceAlerts(o.Base.Context, o.Base.Args[0], o.AlertsReq)
+ return alerts, err
+}
+
+func (o *options) getMigrationStatus() (*govultr.DatabaseMigration, error) {
+ status, _, err := o.Base.Client.Database.GetMigrationStatus(o.Base.Context, o.Base.Args[0])
+ return status, err
+}
+
+func (o *options) startMigration() (*govultr.DatabaseMigration, error) {
+ status, _, err := o.Base.Client.Database.StartMigration(o.Base.Context, o.Base.Args[0], o.MigrationReq)
+ return status, err
+}
+
+func (o *options) detachMigration() error {
+ return o.Base.Client.Database.DetachMigration(o.Base.Context, o.Base.Args[0])
+}
+
+func (o *options) createReadReplica() (*govultr.Database, error) {
+ db, _, err := o.Base.Client.Database.AddReadOnlyReplica(o.Base.Context, o.Base.Args[0], o.ReadReplicaCreateReq)
+ return db, err
+}
+
+func (o *options) promoteReadReplica() error {
+ return o.Base.Client.Database.PromoteReadReplica(o.Base.Context, o.Base.Args[0])
+}
+
+func (o *options) getBackup() (*govultr.DatabaseBackups, error) {
+ backup, _, err := o.Base.Client.Database.GetBackupInformation(o.Base.Context, o.Base.Args[0])
+ return backup, err
+}
+
+func (o *options) restoreBackup() (*govultr.Database, error) {
+ db, _, err := o.Base.Client.Database.RestoreFromBackup(o.Base.Context, o.Base.Args[0], o.BackupReq)
+ return db, err
+}
+
+func (o *options) fork() (*govultr.Database, error) {
+ db, _, err := o.Base.Client.Database.Fork(o.Base.Context, o.Base.Args[0], o.ForkReq)
+ return db, err
+}
+
+func (o *options) listConnectionPools() (*govultr.DatabaseConnections, []govultr.DatabaseConnectionPool, *govultr.Meta, error) {
+ cons, pool, meta, _, err := o.Base.Client.Database.ListConnectionPools(o.Base.Context, o.Base.Args[0])
+ return cons, pool, meta, err
+}
+
+func (o *options) getConnectionPool() (*govultr.DatabaseConnectionPool, error) {
+ pool, _, err := o.Base.Client.Database.GetConnectionPool(o.Base.Context, o.Base.Args[0], o.Base.Args[1])
+ return pool, err
+}
+
+func (o *options) createConnectionPool() (*govultr.DatabaseConnectionPool, error) {
+ pool, _, err := o.Base.Client.Database.CreateConnectionPool(o.Base.Context, o.Base.Args[0], o.ConnectionPoolCreateReq)
+ return pool, err
+}
+
+func (o *options) updateConnectionPool() (*govultr.DatabaseConnectionPool, error) {
+ pool, _, err := o.Base.Client.Database.UpdateConnectionPool(o.Base.Context, o.Base.Args[0], o.Base.Args[1], o.ConnectionPoolUpdateReq)
+ return pool, err
+}
+
+func (o *options) delConnectionPool() error {
+ return o.Base.Client.Database.DeleteConnectionPool(o.Base.Context, o.Base.Args[0], o.Base.Args[1])
+}
+
+func (o *options) listAdvancedOptions() (*govultr.DatabaseAdvancedOptions, []govultr.AvailableOption, error) {
+ cur, avail, _, err := o.Base.Client.Database.ListAdvancedOptions(o.Base.Context, o.Base.Args[0])
+ return cur, avail, err
+}
+
+func (o *options) updateAdvancedOptions() (*govultr.DatabaseAdvancedOptions, []govultr.AvailableOption, error) {
+ cur, avail, _, err := o.Base.Client.Database.UpdateAdvancedOptions(o.Base.Context, o.Base.Args[0], o.AdvancedOptionsReq)
+ return cur, avail, err
+}
+
+func (o *options) listVersions() ([]string, error) {
+ vers, _, err := o.Base.Client.Database.ListAvailableVersions(o.Base.Context, o.Base.Args[0])
+ return vers, err
+}
+
+func (o *options) upgradeVersion() (string, error) {
+ up, _, err := o.Base.Client.Database.StartVersionUpgrade(o.Base.Context, o.Base.Args[0], o.UpgradeReq)
+ return up, err
+}
diff --git a/cmd/database/printer.go b/cmd/database/printer.go
new file mode 100644
index 00000000..ccd9f1f6
--- /dev/null
+++ b/cmd/database/printer.go
@@ -0,0 +1,1318 @@
+package database
+
+import (
+ "reflect"
+ "strconv"
+
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+)
+
+// DBsPrinter ...
+type DBsPrinter struct {
+ DBs []govultr.Database `json:"databases"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (d *DBsPrinter) JSON() []byte {
+ return printer.MarshalObject(d, "json")
+}
+
+// YAML ...
+func (d *DBsPrinter) YAML() []byte {
+ return printer.MarshalObject(d, "yaml")
+}
+
+// Columns ...
+func (d *DBsPrinter) Columns() [][]string {
+ return nil
+}
+
+// Data ...
+func (d *DBsPrinter) Data() [][]string { //nolint:funlen,gocyclo
+ if len(d.DBs) == 0 {
+ return [][]string{0: {"No databases"}}
+ }
+
+ var data [][]string
+ for i := range d.DBs {
+ data = append(data,
+ []string{"ID", d.DBs[i].ID},
+ []string{"DATE CREATED", d.DBs[i].DateCreated},
+ []string{"PLAN", d.DBs[i].Plan},
+ []string{"PLAN DISK", strconv.Itoa(d.DBs[i].PlanDisk)},
+ []string{"PLAN RAM", strconv.Itoa(d.DBs[i].PlanRAM)},
+ []string{"PLAN VCPUS", strconv.Itoa(d.DBs[i].PlanVCPUs)},
+ []string{"PLAN REPLICAS", strconv.Itoa(d.DBs[i].PlanReplicas)},
+ []string{"REGION", d.DBs[i].Region},
+ []string{"DATABASE ENGINE", d.DBs[i].DatabaseEngine},
+ []string{"DATABASE ENGINE VERSION", d.DBs[i].DatabaseEngineVersion},
+ []string{"VPC ID", d.DBs[i].VPCID},
+ []string{"STATUS", d.DBs[i].Status},
+ []string{"LABEL", d.DBs[i].Label},
+ []string{"TAG", d.DBs[i].Tag},
+ []string{"DB NAME", d.DBs[i].DBName},
+ )
+
+ if d.DBs[i].DatabaseEngine == "ferretpg" {
+ data = append(data,
+ []string{" "},
+ []string{"FERRETDB CREDENTIALS"},
+ []string{"HOST", d.DBs[i].FerretDBCredentials.Host},
+ []string{"PORT", strconv.Itoa(d.DBs[i].FerretDBCredentials.Port)},
+ []string{"USER", d.DBs[i].FerretDBCredentials.User},
+ []string{"PASSWORD", d.DBs[i].FerretDBCredentials.Password},
+ []string{"PUBLIC IP", d.DBs[i].FerretDBCredentials.PublicIP},
+ )
+
+ if d.DBs[i].FerretDBCredentials.PrivateIP != "" {
+ data = append(data,
+ []string{"PRIVATE IP", d.DBs[i].FerretDBCredentials.PrivateIP},
+ )
+ }
+
+ data = append(data, []string{" "})
+ }
+
+ data = append(data, []string{"HOST", d.DBs[i].Host})
+
+ if d.DBs[i].PublicHost != "" {
+ data = append(data, []string{"PUBLIC HOST", d.DBs[i].PublicHost})
+ }
+
+ data = append(data,
+ []string{"USER", d.DBs[i].User},
+ []string{"PASSWORD", d.DBs[i].Password},
+ []string{"PORT", d.DBs[i].Port},
+ []string{"MAINTENANCE DOW", d.DBs[i].MaintenanceDOW},
+ []string{"MAINTENANCE TIME", d.DBs[i].MaintenanceTime},
+ []string{"LATEST BACKUP", d.DBs[i].LatestBackup},
+ []string{"TRUSTED IPS", printer.ArrayOfStringsToString(d.DBs[i].TrustedIPs)},
+ )
+
+ if d.DBs[i].DatabaseEngine == "mysql" {
+ data = append(data,
+ []string{"MYSQL SQL MODES", printer.ArrayOfStringsToString(d.DBs[i].MySQLSQLModes)},
+ []string{"MYSQL REQUIRE PRIMARY KEY", strconv.FormatBool(*d.DBs[i].MySQLRequirePrimaryKey)},
+ []string{"MYSQL SLOW QUERY LOG", strconv.FormatBool(*d.DBs[i].MySQLSlowQueryLog)},
+ )
+
+ if *d.DBs[i].MySQLSlowQueryLog {
+ data = append(data,
+ []string{"MYSQL LONG QUERY TIME", strconv.Itoa(d.DBs[i].MySQLLongQueryTime)},
+ )
+ }
+ }
+
+ if d.DBs[i].DatabaseEngine == "pg" && len(d.DBs[i].PGAvailableExtensions) > 0 {
+ data = append(data,
+ []string{" "},
+ []string{"PG AVAILABLE EXTENSIONS"},
+ []string{"NAME", "VERSIONS"},
+ )
+
+ for j := range d.DBs[i].PGAvailableExtensions {
+ if len(d.DBs[i].PGAvailableExtensions[j].Versions) > 0 {
+ data = append(data, []string{
+ d.DBs[i].PGAvailableExtensions[j].Name,
+ printer.ArrayOfStringsToString(d.DBs[i].PGAvailableExtensions[j].Versions)})
+ } else {
+ data = append(data, []string{d.DBs[i].PGAvailableExtensions[j].Name, ""})
+ }
+ }
+ data = append(data, []string{" "})
+ }
+
+ if d.DBs[i].DatabaseEngine == "redis" {
+ data = append(data, []string{"REDIS EVICTION POLICY", d.DBs[i].RedisEvictionPolicy})
+ }
+
+ data = append(data, []string{"CLUSTER TIME ZONE", d.DBs[i].ClusterTimeZone})
+
+ if len(d.DBs[i].ReadReplicas) > 0 {
+ data = append(data,
+ []string{" "},
+ []string{"READ REPLICAS"},
+ )
+
+ for j := range d.DBs[i].ReadReplicas {
+ data = append(data,
+ []string{"ID", d.DBs[i].ReadReplicas[j].ID},
+ []string{"DATE CREATED", d.DBs[i].ReadReplicas[j].DateCreated},
+ []string{"PLAN", d.DBs[i].ReadReplicas[j].Plan},
+ []string{"PLAN DISK", strconv.Itoa(d.DBs[i].ReadReplicas[j].PlanDisk)},
+ []string{"PLAN RAM", strconv.Itoa(d.DBs[i].ReadReplicas[j].PlanRAM)},
+ []string{"PLAN VCPUS", strconv.Itoa(d.DBs[i].ReadReplicas[j].PlanVCPUs)},
+ []string{"PLAN REPLICAS", strconv.Itoa(d.DBs[i].ReadReplicas[j].PlanReplicas)},
+ []string{"REGION", d.DBs[i].ReadReplicas[j].Region},
+ []string{"DATABASE ENGINE", d.DBs[i].ReadReplicas[j].DatabaseEngine},
+ []string{"DATABASE ENGINE VERSION", d.DBs[i].ReadReplicas[j].DatabaseEngineVersion},
+ []string{"VPC ID", d.DBs[i].ReadReplicas[j].VPCID},
+ []string{"STATUS", d.DBs[i].ReadReplicas[j].Status},
+ []string{"LABEL", d.DBs[i].ReadReplicas[j].Label},
+ []string{"TAG", d.DBs[i].ReadReplicas[j].Tag},
+ []string{"DB NAME", d.DBs[i].ReadReplicas[j].DBName},
+ )
+
+ if d.DBs[i].ReadReplicas[j].DatabaseEngine == "ferretpg" {
+ data = append(data,
+ []string{" "},
+
+ []string{"FERRETDB CREDENTIALS"},
+ []string{"HOST", d.DBs[i].ReadReplicas[j].FerretDBCredentials.Host},
+ []string{"PORT", strconv.Itoa(d.DBs[i].ReadReplicas[j].FerretDBCredentials.Port)},
+ []string{"USER", d.DBs[i].ReadReplicas[j].FerretDBCredentials.User},
+ []string{"PASSWORD", d.DBs[i].ReadReplicas[j].FerretDBCredentials.Password},
+ []string{"PUBLIC IP", d.DBs[i].ReadReplicas[j].FerretDBCredentials.PublicIP},
+ )
+
+ if d.DBs[i].ReadReplicas[j].FerretDBCredentials.PrivateIP != "" {
+ data = append(data,
+ []string{"PRIVATE IP", d.DBs[i].ReadReplicas[j].FerretDBCredentials.PrivateIP},
+ )
+ }
+
+ data = append(data, []string{" "})
+ }
+
+ data = append(data, []string{"HOST", d.DBs[i].ReadReplicas[j].Host})
+
+ if d.DBs[i].ReadReplicas[j].PublicHost != "" {
+ data = append(data, []string{"PUBLIC HOST", d.DBs[i].ReadReplicas[j].PublicHost})
+ }
+
+ data = append(data,
+ []string{"USER", d.DBs[i].ReadReplicas[j].User},
+ []string{"PASSWORD", d.DBs[i].ReadReplicas[j].Password},
+ []string{"PORT", d.DBs[i].ReadReplicas[j].Port},
+ []string{"MAINTENANCE DOW", d.DBs[i].ReadReplicas[j].MaintenanceDOW},
+ []string{"MAINTENANCE TIME", d.DBs[i].ReadReplicas[j].MaintenanceTime},
+ []string{"LATEST BACKUP", d.DBs[i].ReadReplicas[j].LatestBackup},
+ []string{"TRUSTED IPS", printer.ArrayOfStringsToString(d.DBs[i].ReadReplicas[j].TrustedIPs)},
+ )
+
+ if d.DBs[i].ReadReplicas[j].DatabaseEngine == "mysql" {
+ data = append(data,
+ []string{"MYSQL SQL MODES", printer.ArrayOfStringsToString(d.DBs[i].ReadReplicas[j].MySQLSQLModes)},
+ []string{"MYSQL REQUIRE PRIMARY KEY", strconv.FormatBool(*d.DBs[i].ReadReplicas[j].MySQLRequirePrimaryKey)},
+ []string{"MYSQL SLOW QUERY LOG", strconv.FormatBool(*d.DBs[i].ReadReplicas[j].MySQLSlowQueryLog)},
+ )
+
+ if *d.DBs[i].ReadReplicas[j].MySQLSlowQueryLog {
+ data = append(data, []string{"MYSQL LONG QUERY TIME", strconv.Itoa(d.DBs[i].ReadReplicas[j].MySQLLongQueryTime)})
+ }
+ }
+
+ if d.DBs[i].ReadReplicas[j].DatabaseEngine == "pg" && len(d.DBs[i].ReadReplicas[j].PGAvailableExtensions) > 0 {
+ data = append(data,
+ []string{" "},
+ []string{"PG AVAILABLE EXTENSIONS"},
+ []string{"NAME", "VERSIONS"},
+ )
+
+ for k := range d.DBs[i].ReadReplicas[j].PGAvailableExtensions {
+ if len(d.DBs[i].ReadReplicas[j].PGAvailableExtensions[k].Versions) > 0 {
+ data = append(data, []string{
+ d.DBs[i].ReadReplicas[j].PGAvailableExtensions[k].Name,
+ printer.ArrayOfStringsToString(d.DBs[i].ReadReplicas[j].PGAvailableExtensions[k].Versions),
+ })
+ } else {
+ data = append(data, []string{d.DBs[i].ReadReplicas[j].PGAvailableExtensions[k].Name, ""})
+ }
+ }
+
+ data = append(data, []string{" "})
+ }
+
+ if d.DBs[i].ReadReplicas[j].DatabaseEngine == "redis" {
+ data = append(data, []string{"REDIS EVICTION POLICY", d.DBs[i].ReadReplicas[j].RedisEvictionPolicy})
+ }
+
+ data = append(data, []string{"CLUSTER TIME ZONE", d.DBs[i].ReadReplicas[j].ClusterTimeZone})
+ }
+ }
+
+ data = append(data, []string{"---------------------------"})
+ }
+
+ return data
+}
+
+// Paging ...
+func (d *DBsPrinter) Paging() [][]string {
+ paging := &printer.Total{Total: d.Meta.Total}
+ return paging.Compose()
+}
+
+// ======================================
+
+// DBPrinter ...
+type DBPrinter struct {
+ DB *govultr.Database `json:"database"`
+}
+
+// JSON ...
+func (d *DBPrinter) JSON() []byte {
+ return printer.MarshalObject(d, "json")
+}
+
+// YAML ...
+func (d *DBPrinter) YAML() []byte {
+ return printer.MarshalObject(d, "yaml")
+}
+
+// Columns ...
+func (d *DBPrinter) Columns() [][]string {
+ return nil
+}
+
+// Data ...
+func (d *DBPrinter) Data() [][]string { //nolint:funlen,gocyclo
+ var data [][]string
+ data = append(data,
+ []string{"ID", d.DB.ID},
+ []string{"DATE CREATED", d.DB.DateCreated},
+ []string{"PLAN", d.DB.Plan},
+ []string{"PLAN DISK", strconv.Itoa(d.DB.PlanDisk)},
+ []string{"PLAN RAM", strconv.Itoa(d.DB.PlanRAM)},
+ []string{"PLAN VCPUS", strconv.Itoa(d.DB.PlanVCPUs)},
+ []string{"PLAN REPLICAS", strconv.Itoa(d.DB.PlanReplicas)},
+ []string{"REGION", d.DB.Region},
+ []string{"DATABASE ENGINE", d.DB.DatabaseEngine},
+ []string{"DATABASE ENGINE VERSION", d.DB.DatabaseEngineVersion},
+ []string{"VPC ID", d.DB.VPCID},
+ []string{"STATUS", d.DB.Status},
+ []string{"LABEL", d.DB.Label},
+ []string{"TAG", d.DB.Tag},
+ []string{"DB NAME", d.DB.DBName},
+ )
+
+ if d.DB.DatabaseEngine == "ferretpg" {
+ data = append(data,
+ []string{" "},
+ []string{"FERRETDB CREDENTIALS"},
+ []string{"HOST", d.DB.FerretDBCredentials.Host},
+ []string{"PORT", strconv.Itoa(d.DB.FerretDBCredentials.Port)},
+ []string{"USER", d.DB.FerretDBCredentials.User},
+ []string{"PASSWORD", d.DB.FerretDBCredentials.Password},
+ []string{"PUBLIC IP", d.DB.FerretDBCredentials.PublicIP},
+ )
+
+ if d.DB.FerretDBCredentials.PrivateIP != "" {
+ data = append(data,
+ []string{"PRIVATE IP", d.DB.FerretDBCredentials.PrivateIP},
+ )
+ }
+
+ data = append(data, []string{" "})
+ }
+
+ data = append(data, []string{"HOST", d.DB.Host})
+
+ if d.DB.PublicHost != "" {
+ data = append(data, []string{"PUBLIC HOST", d.DB.PublicHost})
+ }
+
+ data = append(data,
+ []string{"USER", d.DB.User},
+ []string{"PASSWORD", d.DB.Password},
+ []string{"PORT", d.DB.Port},
+ []string{"MAINTENANCE DOW", d.DB.MaintenanceDOW},
+ []string{"MAINTENANCE TIME", d.DB.MaintenanceTime},
+ []string{"LATEST BACKUP", d.DB.LatestBackup},
+ []string{"TRUSTED IPS", printer.ArrayOfStringsToString(d.DB.TrustedIPs)},
+ )
+
+ if d.DB.DatabaseEngine == "mysql" {
+ data = append(data,
+ []string{"MYSQL SQL MODES", printer.ArrayOfStringsToString(d.DB.MySQLSQLModes)},
+ []string{"MYSQL REQUIRE PRIMARY KEY", strconv.FormatBool(*d.DB.MySQLRequirePrimaryKey)},
+ []string{"MYSQL SLOW QUERY LOG", strconv.FormatBool(*d.DB.MySQLSlowQueryLog)},
+ )
+
+ if *d.DB.MySQLSlowQueryLog {
+ data = append(data,
+ []string{"MYSQL LONG QUERY TIME", strconv.Itoa(d.DB.MySQLLongQueryTime)},
+ )
+ }
+ }
+
+ if d.DB.DatabaseEngine == "pg" && len(d.DB.PGAvailableExtensions) > 0 {
+ data = append(data,
+ []string{" "},
+ []string{"PG AVAILABLE EXTENSIONS"},
+ []string{"NAME", "VERSIONS"},
+ )
+
+ for i := range d.DB.PGAvailableExtensions {
+ if len(d.DB.PGAvailableExtensions[i].Versions) > 0 {
+ data = append(data, []string{
+ d.DB.PGAvailableExtensions[i].Name,
+ printer.ArrayOfStringsToString(d.DB.PGAvailableExtensions[i].Versions)})
+ } else {
+ data = append(data, []string{d.DB.PGAvailableExtensions[i].Name, ""})
+ }
+ }
+ data = append(data, []string{" "})
+ }
+
+ if d.DB.DatabaseEngine == "redis" {
+ data = append(data, []string{"REDIS EVICTION POLICY", d.DB.RedisEvictionPolicy})
+ }
+
+ data = append(data, []string{"CLUSTER TIME ZONE", d.DB.ClusterTimeZone})
+
+ if len(d.DB.ReadReplicas) > 0 {
+ data = append(data,
+ []string{" "},
+ []string{"READ REPLICAS"},
+ )
+
+ for i := range d.DB.ReadReplicas {
+ data = append(data,
+ []string{"ID", d.DB.ReadReplicas[i].ID},
+ []string{"DATE CREATED", d.DB.ReadReplicas[i].DateCreated},
+ []string{"PLAN", d.DB.ReadReplicas[i].Plan},
+ []string{"PLAN DISK", strconv.Itoa(d.DB.ReadReplicas[i].PlanDisk)},
+ []string{"PLAN RAM", strconv.Itoa(d.DB.ReadReplicas[i].PlanRAM)},
+ []string{"PLAN VCPUS", strconv.Itoa(d.DB.ReadReplicas[i].PlanVCPUs)},
+ []string{"PLAN REPLICAS", strconv.Itoa(d.DB.ReadReplicas[i].PlanReplicas)},
+ []string{"REGION", d.DB.ReadReplicas[i].Region},
+ []string{"DATABASE ENGINE", d.DB.ReadReplicas[i].DatabaseEngine},
+ []string{"DATABASE ENGINE VERSION", d.DB.ReadReplicas[i].DatabaseEngineVersion},
+ []string{"VPC ID", d.DB.ReadReplicas[i].VPCID},
+ []string{"STATUS", d.DB.ReadReplicas[i].Status},
+ []string{"LABEL", d.DB.ReadReplicas[i].Label},
+ []string{"TAG", d.DB.ReadReplicas[i].Tag},
+ []string{"DB NAME", d.DB.ReadReplicas[i].DBName},
+ )
+
+ if d.DB.ReadReplicas[i].DatabaseEngine == "ferretpg" {
+ data = append(data,
+ []string{" "},
+
+ []string{"FERRETDB CREDENTIALS"},
+ []string{"HOST", d.DB.ReadReplicas[i].FerretDBCredentials.Host},
+ []string{"PORT", strconv.Itoa(d.DB.ReadReplicas[i].FerretDBCredentials.Port)},
+ []string{"USER", d.DB.ReadReplicas[i].FerretDBCredentials.User},
+ []string{"PASSWORD", d.DB.ReadReplicas[i].FerretDBCredentials.Password},
+ []string{"PUBLIC IP", d.DB.ReadReplicas[i].FerretDBCredentials.PublicIP},
+ )
+
+ if d.DB.ReadReplicas[i].FerretDBCredentials.PrivateIP != "" {
+ data = append(data,
+ []string{"PRIVATE IP", d.DB.ReadReplicas[i].FerretDBCredentials.PrivateIP},
+ )
+ }
+
+ data = append(data, []string{" "})
+ }
+
+ data = append(data, []string{"HOST", d.DB.ReadReplicas[i].Host})
+
+ if d.DB.ReadReplicas[i].PublicHost != "" {
+ data = append(data, []string{"PUBLIC HOST", d.DB.ReadReplicas[i].PublicHost})
+ }
+
+ data = append(data,
+ []string{"USER", d.DB.ReadReplicas[i].User},
+ []string{"PASSWORD", d.DB.ReadReplicas[i].Password},
+ []string{"PORT", d.DB.ReadReplicas[i].Port},
+ []string{"MAINTENANCE DOW", d.DB.ReadReplicas[i].MaintenanceDOW},
+ []string{"MAINTENANCE TIME", d.DB.ReadReplicas[i].MaintenanceTime},
+ []string{"LATEST BACKUP", d.DB.ReadReplicas[i].LatestBackup},
+ []string{"TRUSTED IPS", printer.ArrayOfStringsToString(d.DB.ReadReplicas[i].TrustedIPs)},
+ )
+
+ if d.DB.ReadReplicas[i].DatabaseEngine == "mysql" {
+ data = append(data,
+ []string{"MYSQL SQL MODES", printer.ArrayOfStringsToString(d.DB.ReadReplicas[i].MySQLSQLModes)},
+ []string{"MYSQL REQUIRE PRIMARY KEY", strconv.FormatBool(*d.DB.ReadReplicas[i].MySQLRequirePrimaryKey)},
+ []string{"MYSQL SLOW QUERY LOG", strconv.FormatBool(*d.DB.ReadReplicas[i].MySQLSlowQueryLog)},
+ )
+
+ if *d.DB.ReadReplicas[i].MySQLSlowQueryLog {
+ data = append(data, []string{"MYSQL LONG QUERY TIME", strconv.Itoa(d.DB.ReadReplicas[i].MySQLLongQueryTime)})
+ }
+ }
+
+ if d.DB.ReadReplicas[i].DatabaseEngine == "pg" && len(d.DB.ReadReplicas[i].PGAvailableExtensions) > 0 {
+ data = append(data,
+ []string{" "},
+ []string{"PG AVAILABLE EXTENSIONS"},
+ []string{"NAME", "VERSIONS"},
+ )
+
+ for j := range d.DB.ReadReplicas[i].PGAvailableExtensions {
+ if len(d.DB.ReadReplicas[i].PGAvailableExtensions[j].Versions) > 0 {
+ data = append(data, []string{
+ d.DB.ReadReplicas[i].PGAvailableExtensions[j].Name,
+ printer.ArrayOfStringsToString(d.DB.ReadReplicas[i].PGAvailableExtensions[j].Versions),
+ })
+ } else {
+ data = append(data, []string{d.DB.ReadReplicas[i].PGAvailableExtensions[j].Name, ""})
+ }
+ }
+
+ data = append(data, []string{" "})
+ }
+
+ if d.DB.ReadReplicas[i].DatabaseEngine == "redis" {
+ data = append(data, []string{"REDIS EVICTION POLICY", d.DB.ReadReplicas[i].RedisEvictionPolicy})
+ }
+
+ data = append(data, []string{"CLUSTER TIME ZONE", d.DB.ReadReplicas[i].ClusterTimeZone})
+ }
+ }
+
+ return data
+}
+
+// Paging ...
+func (d *DBPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// DBsSummaryPrinter ...
+type DBsSummaryPrinter struct {
+ DBs []govultr.Database `json:"databases"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (d *DBsSummaryPrinter) JSON() []byte {
+ return printer.MarshalObject(d, "json")
+}
+
+// YAML ...
+func (d *DBsSummaryPrinter) YAML() []byte {
+ return printer.MarshalObject(d, "yaml")
+}
+
+// Columns ...
+func (d *DBsSummaryPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "REGION",
+ "LABEL",
+ "STATUS",
+ "ENGINE",
+ "VERSION",
+ }}
+}
+
+// Data ...
+func (d *DBsSummaryPrinter) Data() [][]string {
+ if len(d.DBs) == 0 {
+ return [][]string{0: {"---", "---", "---", "---", "---", "---"}}
+ }
+
+ var data [][]string
+ for i := range d.DBs {
+ data = append(data, []string{
+
+ d.DBs[i].ID,
+ d.DBs[i].Region,
+ d.DBs[i].Label,
+ d.DBs[i].Status,
+ d.DBs[i].DatabaseEngine,
+ d.DBs[i].DatabaseEngineVersion,
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (d *DBsSummaryPrinter) Paging() [][]string {
+ paging := &printer.Total{Total: d.Meta.Total}
+ return paging.Compose()
+}
+
+// ======================================
+
+// PlansPrinter ...
+type PlansPrinter struct {
+ Plans []govultr.DatabasePlan `json:"plans"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (p *PlansPrinter) JSON() []byte {
+ return printer.MarshalObject(p, "json")
+}
+
+// YAML ...
+func (p *PlansPrinter) YAML() []byte {
+ return printer.MarshalObject(p, "yaml")
+}
+
+// Columns ...
+func (p *PlansPrinter) Columns() [][]string {
+ return nil
+}
+
+// Data ...
+func (p *PlansPrinter) Data() [][]string {
+ if len(p.Plans) == 0 {
+ return [][]string{0: {"No database plans available"}}
+ }
+
+ var data [][]string
+ for i := range p.Plans {
+ data = append(data,
+ []string{"ID", p.Plans[i].ID},
+ []string{"NUMBER OF NODES", strconv.Itoa(p.Plans[i].NumberOfNodes)},
+ []string{"TYPE", p.Plans[i].Type},
+ []string{"VCPU COUNT", strconv.Itoa(p.Plans[i].VCPUCount)},
+ []string{"RAM", strconv.Itoa(p.Plans[i].RAM)},
+ []string{"DISK", strconv.Itoa(p.Plans[i].Disk)},
+ []string{"MONTHLY COST", strconv.Itoa(p.Plans[i].MonthlyCost)},
+
+ []string{" "},
+
+ []string{"SUPPORTED ENGINES"},
+ []string{"MYSQL", strconv.FormatBool(*p.Plans[i].SupportedEngines.MySQL)},
+ []string{"PG", strconv.FormatBool(*p.Plans[i].SupportedEngines.PG)},
+ []string{"REDIS", strconv.FormatBool(*p.Plans[i].SupportedEngines.Redis)},
+ )
+
+ if !*p.Plans[i].SupportedEngines.Redis {
+ data = append(data,
+ []string{" "},
+ []string{"MAX CONNECTIONS"},
+ []string{"MYSQL", strconv.Itoa(p.Plans[i].MaxConnections.MySQL)},
+ []string{"PG", strconv.Itoa(p.Plans[i].MaxConnections.PG)},
+ []string{" "},
+ )
+ }
+
+ data = append(data,
+ []string{"LOCATIONS", printer.ArrayOfStringsToString(p.Plans[i].Locations)},
+ []string{"---------------------------"},
+ )
+ }
+
+ return data
+}
+
+// Paging ...
+func (p *PlansPrinter) Paging() [][]string {
+ paging := &printer.Total{Total: p.Meta.Total}
+ return paging.Compose()
+}
+
+// ======================================
+
+// UsagePrinter ...
+type UsagePrinter struct {
+ Usage *govultr.DatabaseUsage `json:"usage"`
+}
+
+// JSON ...
+func (u *UsagePrinter) JSON() []byte {
+ return printer.MarshalObject(u, "json")
+}
+
+// YAML ...
+func (u *UsagePrinter) YAML() []byte {
+ return printer.MarshalObject(u, "yaml")
+}
+
+// Columns ...
+func (u *UsagePrinter) Columns() [][]string {
+ return nil
+}
+
+// Data ...
+func (u *UsagePrinter) Data() [][]string {
+ var data [][]string
+ data = append(data,
+ []string{"DISK USAGE"},
+ []string{"CURRENT (GB)", strconv.FormatFloat(
+ float64(u.Usage.Disk.CurrentGB),
+ 'f',
+ utils.FloatPrecision,
+ utils.FloatBitDepth,
+ )},
+ []string{"MAXIMUM (GB)", strconv.FormatFloat(
+ float64(u.Usage.Disk.MaxGB),
+ 'f',
+ utils.FloatPrecision,
+ utils.FloatBitDepth,
+ )},
+ []string{"PERCENTAGE", strconv.FormatFloat(
+ float64(u.Usage.Disk.Percentage),
+ 'f',
+ utils.FloatPrecision,
+ utils.FloatBitDepth,
+ )},
+ []string{" "},
+ []string{"MEMORY USAGE"},
+ []string{"CURRENT (MB)", strconv.FormatFloat(
+ float64(u.Usage.Memory.CurrentMB),
+ 'f',
+ utils.FloatPrecision,
+ utils.FloatBitDepth,
+ )},
+ []string{"MAXIMUM (MB)", strconv.FormatFloat(
+ float64(u.Usage.Memory.MaxMB),
+ 'f',
+ utils.FloatPrecision,
+ utils.FloatBitDepth,
+ )},
+ []string{"PERCENTAGE", strconv.FormatFloat(
+ float64(u.Usage.Memory.Percentage),
+ 'f',
+ utils.FloatPrecision,
+ utils.FloatBitDepth,
+ )},
+ []string{" "},
+ []string{"CPU USAGE"},
+ []string{"PERCENTAGE", strconv.FormatFloat(
+ float64(u.Usage.CPU.Percentage),
+ 'f',
+ utils.FloatPrecision,
+ utils.FloatBitDepth,
+ )},
+ )
+
+ return data
+}
+
+// Paging ...
+func (u *UsagePrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// UsersPrinter ...
+type UsersPrinter struct {
+ Users []govultr.DatabaseUser `json:"users"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (u *UsersPrinter) JSON() []byte {
+ return printer.MarshalObject(u, "json")
+}
+
+// YAML ...
+func (u *UsersPrinter) YAML() []byte {
+ return printer.MarshalObject(u, "yaml")
+}
+
+// Columns ...
+func (u *UsersPrinter) Columns() [][]string {
+ return nil
+}
+
+// Data ...
+func (u *UsersPrinter) Data() [][]string {
+ if len(u.Users) == 0 {
+ return [][]string{0: {"No database users"}}
+ }
+
+ var data [][]string
+ for i := range u.Users {
+ data = append(data,
+ []string{"USERNAME", u.Users[i].Username},
+ []string{"PASSWORD", u.Users[i].Password},
+ )
+
+ if u.Users[i].Encryption != "" {
+ data = append(data, []string{"ENCRYPTION", u.Users[i].Encryption})
+ }
+
+ if u.Users[i].AccessControl != nil {
+ data = append(data,
+ []string{"ACCESS CONTROL"},
+ []string{"REDIS ACL CATEGORIES", printer.ArrayOfStringsToString(u.Users[i].AccessControl.RedisACLCategories)},
+ []string{"REDIS ACL CHANNELS", printer.ArrayOfStringsToString(u.Users[i].AccessControl.RedisACLChannels)},
+ []string{"REDIS ACL COMMANDS", printer.ArrayOfStringsToString(u.Users[i].AccessControl.RedisACLCommands)},
+ []string{"REDIS ACL KEYS", printer.ArrayOfStringsToString(u.Users[i].AccessControl.RedisACLKeys)},
+ )
+ }
+
+ data = append(data, []string{"---------------------------"})
+ }
+
+ return data
+}
+
+// Paging ...
+func (u *UsersPrinter) Paging() [][]string {
+ paging := &printer.Total{Total: u.Meta.Total}
+ return paging.Compose()
+}
+
+// ======================================
+
+// UserPrinter ...
+type UserPrinter struct {
+ User *govultr.DatabaseUser `json:"user"`
+}
+
+// JSON ...
+func (u *UserPrinter) JSON() []byte {
+ return printer.MarshalObject(u, "json")
+}
+
+// YAML ...
+func (u *UserPrinter) YAML() []byte {
+ return printer.MarshalObject(u, "yaml")
+}
+
+// Columns ...
+func (u *UserPrinter) Columns() [][]string {
+ return nil
+}
+
+// Data ...
+func (u *UserPrinter) Data() [][]string {
+ var data [][]string
+ data = append(data,
+ []string{"USERNAME", u.User.Username},
+ []string{"PASSWORD", u.User.Password},
+ )
+
+ if u.User.Encryption != "" {
+ data = append(data, []string{"ENCRYPTION", u.User.Encryption})
+ }
+
+ if u.User.AccessControl != nil {
+ data = append(data,
+ []string{"ACCESS CONTROL"},
+ []string{"REDIS ACL CATEGORIES", printer.ArrayOfStringsToString(u.User.AccessControl.RedisACLCategories)},
+ []string{"REDIS ACL CHANNELS", printer.ArrayOfStringsToString(u.User.AccessControl.RedisACLChannels)},
+ []string{"REDIS ACL COMMANDS", printer.ArrayOfStringsToString(u.User.AccessControl.RedisACLCommands)},
+ []string{"REDIS ACL KEYS", printer.ArrayOfStringsToString(u.User.AccessControl.RedisACLKeys)},
+ )
+ }
+
+ return data
+}
+
+// Paging ...
+func (u *UserPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// LogicalDBsPrinter ...
+type LogicalDBsPrinter struct {
+ DBs []govultr.DatabaseDB `json:"dbs"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (l *LogicalDBsPrinter) JSON() []byte {
+ return printer.MarshalObject(l, "json")
+}
+
+// YAML ...
+func (l *LogicalDBsPrinter) YAML() []byte {
+ return printer.MarshalObject(l, "yaml")
+}
+
+// Columns ...
+func (l *LogicalDBsPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "NAME",
+ }}
+}
+
+// Data ...
+func (l *LogicalDBsPrinter) Data() [][]string {
+ if len(l.DBs) == 0 {
+ return [][]string{0: {"---"}}
+ }
+
+ var data [][]string
+ for i := range l.DBs {
+ data = append(data, []string{l.DBs[i].Name})
+ }
+
+ return data
+}
+
+// Paging ...
+func (l *LogicalDBsPrinter) Paging() [][]string {
+ paging := &printer.Total{Total: l.Meta.Total}
+ return paging.Compose()
+}
+
+// ======================================
+
+// LogicalDBPrinter ...
+type LogicalDBPrinter struct {
+ DB *govultr.DatabaseDB `json:"db"`
+}
+
+// JSON ...
+func (l *LogicalDBPrinter) JSON() []byte {
+ return printer.MarshalObject(l, "json")
+}
+
+// YAML ...
+func (l *LogicalDBPrinter) YAML() []byte {
+ return printer.MarshalObject(l, "yaml")
+}
+
+// Columns ...
+func (l *LogicalDBPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "NAME",
+ }}
+}
+
+// Data ...
+func (l *LogicalDBPrinter) Data() [][]string {
+ return [][]string{0: {l.DB.Name}}
+}
+
+// Paging ...
+func (l *LogicalDBPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// UpdatesPrinter ...
+type UpdatesPrinter struct {
+ Updates []string `json:"available_updates"`
+}
+
+// JSON ...
+func (u *UpdatesPrinter) JSON() []byte {
+ return printer.MarshalObject(u, "json")
+}
+
+// YAML ...
+func (u *UpdatesPrinter) YAML() []byte {
+ return printer.MarshalObject(u, "yaml")
+}
+
+// Columns ...
+func (u *UpdatesPrinter) Columns() [][]string {
+ return [][]string{0: {"AVAILABLE UPDATES"}}
+}
+
+// Data ...
+func (u *UpdatesPrinter) Data() [][]string {
+ var data [][]string
+
+ for i := range u.Updates {
+ data = append(data, []string{u.Updates[i]})
+ }
+
+ return data
+}
+
+// Paging ...
+func (u *UpdatesPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// AlertsPrinter ...
+type AlertsPrinter struct {
+ Alerts []govultr.DatabaseAlert `json:"alerts"`
+}
+
+// JSON ...
+func (a *AlertsPrinter) JSON() []byte {
+ return printer.MarshalObject(a, "json")
+}
+
+// YAML ...
+func (a *AlertsPrinter) YAML() []byte {
+ return printer.MarshalObject(a, "yaml")
+}
+
+// Columns ...
+func (a *AlertsPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "NAME",
+ }}
+}
+
+// Data ...
+func (a *AlertsPrinter) Data() [][]string {
+ if len(a.Alerts) == 0 {
+ return [][]string{0: {"No active database alerts"}}
+ }
+
+ var data [][]string
+ for i := range a.Alerts {
+ data = append(data,
+ []string{"TIMESTAMP", a.Alerts[i].Timestamp},
+ []string{"MESSAGE TYPE", a.Alerts[i].MessageType},
+ []string{"DESCRIPTION", a.Alerts[i].Description},
+ )
+
+ if a.Alerts[i].Recommendation != "" {
+ data = append(data, []string{"RECOMMENDATION", a.Alerts[i].Recommendation})
+ }
+
+ if a.Alerts[i].MaintenanceScheduled != "" {
+ data = append(data, []string{"MAINTENANCE SCHEDULED", a.Alerts[i].MaintenanceScheduled})
+ }
+
+ if a.Alerts[i].ResourceType != "" {
+ data = append(data, []string{"RESOURCE TYPE", a.Alerts[i].ResourceType})
+ }
+
+ if a.Alerts[i].TableCount != 0 {
+ data = append(data, []string{"TABLE COUNT", strconv.Itoa(a.Alerts[i].TableCount)})
+ }
+
+ data = append(data, []string{"---------------------------"})
+ }
+
+ return data
+}
+
+// Paging ...
+func (a *AlertsPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// MigrationPrinter ...
+type MigrationPrinter struct {
+ Migration *govultr.DatabaseMigration `json:"migration"`
+}
+
+// JSON ...
+func (m *MigrationPrinter) JSON() []byte {
+ return printer.MarshalObject(m, "json")
+}
+
+// YAML ...
+func (m *MigrationPrinter) YAML() []byte {
+ return printer.MarshalObject(m, "yaml")
+}
+
+// Columns ...
+func (m *MigrationPrinter) Columns() [][]string {
+ return nil
+}
+
+// Data ...
+func (m *MigrationPrinter) Data() [][]string {
+ var data [][]string
+ data = append(data, []string{"STATUS", m.Migration.Status})
+
+ if m.Migration.Method != "" {
+ data = append(data, []string{"METHOD", m.Migration.Method})
+ }
+
+ if m.Migration.Error != "" {
+ data = append(data, []string{"ERROR", m.Migration.Error})
+ }
+
+ data = append(data,
+ []string{" "},
+ []string{"CREDENTIALS"},
+ []string{"HOST", m.Migration.Credentials.Host},
+ []string{"PORT", strconv.Itoa(m.Migration.Credentials.Port)},
+ []string{"USERNAME", m.Migration.Credentials.Username},
+ []string{"PASSWORD", m.Migration.Credentials.Password},
+ )
+
+ if m.Migration.Credentials.Database != "" {
+ data = append(data, []string{"DATABASE", m.Migration.Credentials.Database})
+ }
+
+ if m.Migration.Credentials.IgnoredDatabases != "" {
+ data = append(data, []string{"IGNORED DATABASES", m.Migration.Credentials.IgnoredDatabases})
+ }
+
+ data = append(data, []string{"SSL", strconv.FormatBool(*m.Migration.Credentials.SSL)})
+
+ return data
+}
+
+// Paging ...
+func (m *MigrationPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// BackupPrinter ...
+type BackupPrinter struct {
+ Backup *govultr.DatabaseBackups `json:"backups"`
+}
+
+// JSON ...
+func (b *BackupPrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BackupPrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BackupPrinter) Columns() [][]string {
+ return nil
+}
+
+// Data ...
+func (b *BackupPrinter) Data() [][]string {
+ var data [][]string
+ data = append(data,
+ []string{"LATEST BACKUP"},
+ []string{"DATE", b.Backup.LatestBackup.Date},
+ []string{"TIME", b.Backup.LatestBackup.Time},
+ []string{" "},
+ []string{"OLDEST BACKUP"},
+ []string{"DATE", b.Backup.OldestBackup.Date},
+ []string{"TIME", b.Backup.OldestBackup.Time},
+ )
+
+ return data
+}
+
+// Paging ...
+func (b *BackupPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// ConnectionsPrinter ...
+type ConnectionsPrinter struct {
+ Connections *govultr.DatabaseConnections `json:"connections"`
+ ConnectionPools []govultr.DatabaseConnectionPool `json:"connection_pools"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (c *ConnectionsPrinter) JSON() []byte {
+ return printer.MarshalObject(c, "json")
+}
+
+// YAML ...
+func (c *ConnectionsPrinter) YAML() []byte {
+ return printer.MarshalObject(c, "yaml")
+}
+
+// Columns ...
+func (c *ConnectionsPrinter) Columns() [][]string {
+ return nil
+}
+
+// Data ...
+func (c *ConnectionsPrinter) Data() [][]string {
+ var data [][]string
+
+ data = append(data,
+ []string{"CONNECTIONS"},
+ []string{"USED", strconv.Itoa(c.Connections.Used)},
+ []string{"AVAILABLE", strconv.Itoa(c.Connections.Available)},
+ []string{"MAX", strconv.Itoa(c.Connections.Max)},
+
+ []string{" "},
+ []string{"CONNECTION POOLS"},
+ )
+
+ for i := range c.ConnectionPools {
+ data = append(data,
+ []string{"NAME", c.ConnectionPools[i].Name},
+ []string{"DATABASE", c.ConnectionPools[i].Database},
+ []string{"USERNAME", c.ConnectionPools[i].Username},
+ []string{"MODE", c.ConnectionPools[i].Mode},
+ []string{"SIZE", strconv.Itoa(c.ConnectionPools[i].Size)},
+ []string{"---------------------------"},
+ )
+ }
+
+ return data
+}
+
+// Paging ...
+func (c *ConnectionsPrinter) Paging() [][]string {
+ paging := &printer.Total{Total: c.Meta.Total}
+ return paging.Compose()
+}
+
+// ======================================
+
+// ConnectionPoolPrinter ...
+type ConnectionPoolPrinter struct {
+ ConnectionPool *govultr.DatabaseConnectionPool `json:"connection_pool"`
+}
+
+// JSON ...
+func (c *ConnectionPoolPrinter) JSON() []byte {
+ return printer.MarshalObject(c, "json")
+}
+
+// YAML ...
+func (c *ConnectionPoolPrinter) YAML() []byte {
+ return printer.MarshalObject(c, "yaml")
+}
+
+// Columns ...
+func (c *ConnectionPoolPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "NAME",
+ "DATABASE",
+ "USERNAME",
+ "MODE",
+ "SIZE",
+ }}
+}
+
+// Data ...
+func (c *ConnectionPoolPrinter) Data() [][]string {
+ return [][]string{0: {
+ c.ConnectionPool.Name,
+ c.ConnectionPool.Database,
+ c.ConnectionPool.Username,
+ c.ConnectionPool.Mode,
+ strconv.Itoa(c.ConnectionPool.Size),
+ }}
+}
+
+// Paging ...
+func (c *ConnectionPoolPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// AdvancedOptionsPrinter ...
+type AdvancedOptionsPrinter struct {
+ Configured *govultr.DatabaseAdvancedOptions `json:"configured_options"`
+ Available []govultr.AvailableOption `json:"available_options"`
+}
+
+// JSON ...
+func (a *AdvancedOptionsPrinter) JSON() []byte {
+ return printer.MarshalObject(a, "json")
+}
+
+// YAML ...
+func (a *AdvancedOptionsPrinter) YAML() []byte {
+ return printer.MarshalObject(a, "yaml")
+}
+
+// Columns ...
+func (a *AdvancedOptionsPrinter) Columns() [][]string {
+ return nil
+}
+
+// Data ...
+func (a *AdvancedOptionsPrinter) Data() [][]string {
+ var data [][]string
+
+ if a.Configured == (&govultr.DatabaseAdvancedOptions{}) {
+ data = append(data, []string{"CONFIGURED OPTIONS", "None"})
+ } else {
+ data = append(data, []string{"CONFIGURED OPTIONS"})
+ v := reflect.ValueOf(*a.Configured)
+ for i := 0; i < v.NumField(); i++ {
+ if !v.Field(i).IsZero() {
+ if v.Field(i).Kind() == reflect.Pointer {
+ data = append(data, []string{v.Type().Field(i).Name, v.Field(i).Elem().Interface().(string)})
+ } else {
+ data = append(data, []string{v.Type().Field(i).Name, v.Field(i).Interface().(string)})
+ }
+ }
+ }
+ }
+
+ data = append(data,
+ []string{" "},
+ []string{"AVAILABLE OPTIONS"},
+ )
+
+ for i := range a.Available {
+ data = append(data,
+ []string{"NAME", a.Available[i].Name},
+ []string{"TYPE", a.Available[i].Type},
+ )
+
+ if a.Available[i].Type == "enum" {
+ data = append(data,
+ []string{"ENUMERALS", printer.ArrayOfStringsToString(a.Available[i].Enumerals)},
+ )
+ }
+
+ if a.Available[i].Type == "int" || a.Available[i].Type == "float" {
+ data = append(data,
+ []string{"MIN VALUE", strconv.Itoa(*a.Available[i].MinValue)},
+ []string{"MAX VALUE", strconv.Itoa(*a.Available[i].MaxValue)},
+ )
+ }
+
+ if len(a.Available[i].AltValues) > 0 {
+ data = append(data, []string{"ALT VALUES", printer.ArrayOfIntsToString(a.Available[i].AltValues)})
+ }
+
+ if a.Available[i].Units != "" {
+ data = append(data, []string{"UNITS", a.Available[i].Units})
+ }
+
+ data = append(data, []string{"---------------------------"})
+ }
+
+ return data
+}
+
+// Paging ...
+func (a *AdvancedOptionsPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// VersionsPrinter ...
+type VersionsPrinter struct {
+ Versions []string `json:"available_versions"`
+}
+
+// JSON ...
+func (v *VersionsPrinter) JSON() []byte {
+ return printer.MarshalObject(v, "json")
+}
+
+// YAML ...
+func (v *VersionsPrinter) YAML() []byte {
+ return printer.MarshalObject(v, "yaml")
+}
+
+// Columns ...
+func (v *VersionsPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "AVAILABLE VERSIONS",
+ }}
+}
+
+// Data ...
+func (v *VersionsPrinter) Data() [][]string {
+ var data [][]string
+ for i := range v.Versions {
+ data = append(data, []string{v.Versions[i]})
+ }
+
+ return data
+}
+
+// Paging ...
+func (v *VersionsPrinter) Paging() [][]string {
+ return nil
+}
diff --git a/cmd/dns.go b/cmd/dns.go
deleted file mode 100644
index f34866b1..00000000
--- a/cmd/dns.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cmd
-
-import (
- "github.com/spf13/cobra"
-)
-
-// DNS represents the dns command
-func DNS() *cobra.Command {
- dnsCmd := &cobra.Command{
- Use: "dns",
- Short: "dns is used to access dns commands",
- Long: ``,
- }
-
- dnsCmd.AddCommand(DNSDomain())
- dnsCmd.AddCommand(DNSRecord())
- return dnsCmd
-}
diff --git a/cmd/dns/dns.go b/cmd/dns/dns.go
new file mode 100644
index 00000000..98359ca0
--- /dev/null
+++ b/cmd/dns/dns.go
@@ -0,0 +1,645 @@
+// Package dns provides the functionality for dns commands in the CLI
+package dns
+
+import (
+ "errors"
+ "fmt"
+ "os"
+
+ "github.com/spf13/cobra"
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+ "github.com/vultr/vultr-cli/v3/pkg/cli"
+)
+
+var (
+ dnsLong = ``
+ dnsExample = ``
+
+ createLong = ``
+ createExample = ``
+
+ domainLong = ``
+ domainExample = ``
+)
+
+// NewCmdDNS provides the CLI command functionality for DNS
+func NewCmdDNS(base *cli.Base) *cobra.Command { //nolint:funlen,gocyclo
+ o := &options{Base: base}
+
+ cmd := &cobra.Command{
+ Use: "dns",
+ Short: "Commands to control DNS records",
+ Long: dnsLong,
+ Example: dnsExample,
+ PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+ utils.SetOptions(o.Base, cmd, args)
+ if !o.Base.HasAuth {
+ return errors.New(utils.APIKeyError)
+ }
+ return nil
+ },
+ }
+
+ domain := &cobra.Command{
+ Use: "domain",
+ Short: "DNS domain commands",
+ Long: domainLong,
+ Example: domainExample,
+ }
+
+ // Domain List
+ domainList := &cobra.Command{
+ Use: "list",
+ Short: "Get list of domains",
+ Run: func(cmd *cobra.Command, args []string) {
+ o.Base.Options = utils.GetPaging(cmd)
+
+ dms, meta, err := o.domainList()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving domain list : %v", err))
+ os.Exit(1)
+ }
+
+ data := &DNSDomainsPrinter{Domains: dms, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ domainList.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
+ domainList.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ fmt.Sprintf("(optional) Number of items requested per page. Default is %d and Max is 500.", utils.PerPageDefault),
+ )
+
+ // Domain Get
+ domainGet := &cobra.Command{
+ Use: "get ",
+ Short: "Get a domain",
+ Long: ``,
+ Run: func(cmd *cobra.Command, args []string) {
+ dm, err := o.domainGet()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving domain : %v", err))
+ os.Exit(1)
+ }
+
+ data := &DNSDomainPrinter{Domain: *dm}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ // Domain Create
+ domainCreate := &cobra.Command{
+ Use: "create",
+ Short: "Create a domain",
+ Long: createLong,
+ Example: createExample,
+ Run: func(cmd *cobra.Command, args []string) {
+ domain, errDo := cmd.Flags().GetString("domain")
+ if errDo != nil {
+ printer.Error(fmt.Errorf("error parsing 'domain' flag for domain create : %v", errDo))
+ os.Exit(1)
+ }
+
+ ip, errIP := cmd.Flags().GetString("ip")
+ if errIP != nil {
+ printer.Error(fmt.Errorf("error parsing 'ip' flag for domain create : %v", errIP))
+ os.Exit(1)
+ }
+
+ o.DomainCreateReq = &govultr.DomainReq{
+ Domain: domain,
+ IP: ip,
+ }
+
+ dm, err := o.domainCreate()
+ if err != nil {
+ printer.Error(fmt.Errorf("error creating dns domain : %v", err))
+ os.Exit(1)
+ }
+
+ data := &DNSDomainPrinter{Domain: *dm}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ domainCreate.Flags().StringP("domain", "d", "", "name of the domain")
+ if err := domainCreate.MarkFlagRequired("domain"); err != nil {
+ printer.Error(fmt.Errorf("error marking domain create 'domain' flag required: %v", err))
+ os.Exit(1)
+ }
+ domainCreate.Flags().StringP("ip", "i", "", "instance ip you want to assign this domain to")
+
+ // Domain Delete
+ domainDelete := &cobra.Command{
+ Use: "delete ",
+ Short: "Delete a domain",
+ Aliases: []string{"destroy"},
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a domain name")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ if err := o.domainDelete(); err != nil {
+ printer.Error(fmt.Errorf("error delete dns domain : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("dns domain has been deleted"), nil)
+ },
+ }
+
+ // Domain DNSSEC Update
+ domainDNSSEC := &cobra.Command{
+ Use: "dnssec ",
+ Short: "enable/disable dnssec",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a domain name")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ enabled, errEn := cmd.Flags().GetBool("enabled")
+ if errEn != nil {
+ printer.Error(fmt.Errorf("error parsing 'enabled' flag for dnssec : %v", errEn))
+ os.Exit(1)
+ }
+
+ disabled, errDi := cmd.Flags().GetBool("disabled")
+ if errEn != nil {
+ printer.Error(fmt.Errorf("error parsing 'disabled' flag for dnssec : %v", errDi))
+ os.Exit(1)
+ }
+
+ if cmd.Flags().Changed("enabled") {
+ if enabled {
+ o.DomainDNSSECEnabled = "enabled"
+ } else {
+ o.DomainDNSSECEnabled = "disabled"
+ }
+ }
+
+ if cmd.Flags().Changed("disabled") {
+ if disabled {
+ o.DomainDNSSECEnabled = "disabled"
+ } else {
+ o.DomainDNSSECEnabled = "enabled"
+ }
+ }
+
+ if err := o.domainUpdate(); err != nil {
+ printer.Error(fmt.Errorf("error toggling dnssec : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("dns domain DNSSEC has been updated"), nil)
+ },
+ }
+
+ domainDNSSEC.Flags().BoolP("enabled", "e", true, "enable dnssec")
+ domainDNSSEC.Flags().BoolP("disabled", "d", true, "disable dnssec")
+ domainDNSSEC.MarkFlagsOneRequired("enabled", "disabled")
+ domainDNSSEC.MarkFlagsMutuallyExclusive("enabled", "disabled")
+
+ // Domain DNSSEC Info
+ domainDNSSECInfo := &cobra.Command{
+ Use: "dnssec-info ",
+ Short: "Get DNS SEC info",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a domain name")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ info, err := o.domainDNSSECGet()
+ if err != nil {
+ printer.Error(fmt.Errorf("error getting domain dnssec info : %v", err))
+ os.Exit(1)
+ }
+
+ data := &DNSSECPrinter{SEC: info}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ // Domain SOA Info
+ domainSOAInfo := &cobra.Command{
+ Use: "soa-info ",
+ Short: "Get DNS SOA info",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a domain name")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ info, err := o.domainSOAGet()
+ if err != nil {
+ printer.Error(fmt.Errorf("error getting domain soa info : %v", err))
+ os.Exit(1)
+ }
+
+ data := &DNSSOAPrinter{SOA: *info}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ // Domain SOA Update
+ domainSOAUpdate := &cobra.Command{
+ Use: "soa-update ",
+ Short: "Update SOA for a domain",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a domain name")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ ns, errNs := cmd.Flags().GetString("ns-primary")
+ if errNs != nil {
+ printer.Error(fmt.Errorf("error parsing 'ns-primary' flag for domain soa : %v", errNs))
+ os.Exit(1)
+ }
+
+ email, errEm := cmd.Flags().GetString("email")
+ if errEm != nil {
+ printer.Error(fmt.Errorf("error parsing 'email' flag for domain soa : %v", errEm))
+ os.Exit(1)
+ }
+
+ o.SOAUpdateReq = &govultr.Soa{
+ NSPrimary: ns,
+ Email: email,
+ }
+
+ if err := o.domainSOAUpdate(); err != nil {
+ printer.Error(fmt.Errorf("error updating domain soa : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("domain soa has been updated"), nil)
+ },
+ }
+
+ domainSOAUpdate.Flags().StringP("ns-primary", "n", "", "primary nameserver to store in the SOA record")
+ domainSOAUpdate.Flags().StringP("email", "e", "", "administrative email to store in the SOA record")
+
+ domain.AddCommand(
+ domainList,
+ domainGet,
+ domainCreate,
+ domainDelete,
+ domainDNSSEC,
+ domainDNSSECInfo,
+ domainSOAInfo,
+ domainSOAUpdate,
+ )
+
+ // Record
+ record := &cobra.Command{
+ Use: "record",
+ Short: "dns record",
+ }
+
+ // Record List
+ recordList := &cobra.Command{
+ Use: "list ",
+ Short: "List all DNS records",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a domain name")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ o.Base.Options = utils.GetPaging(cmd)
+
+ recs, meta, err := o.recordList()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieiving domain records : %v", err))
+ os.Exit(1)
+ }
+
+ data := &DNSRecordsPrinter{Records: recs, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ recordList.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
+ recordList.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ fmt.Sprintf("(optional) Number of items requested per page. Default is %d and Max is 500.", utils.PerPageDefault),
+ )
+
+ // Record Get
+ recordGet := &cobra.Command{
+ Use: "get ",
+ Short: "Get a DNS record",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 2 {
+ return errors.New("please provide a domain name and record ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ rec, err := o.recordGet()
+ if err != nil {
+ printer.Error(fmt.Errorf("error while getting domain record : %v", err))
+ os.Exit(1)
+ }
+
+ data := &DNSRecordPrinter{Record: *rec}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ // Record Create
+ recordCreate := &cobra.Command{
+ Use: "create ",
+ Short: "Create a dns record",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a domain name")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ rType, errTy := cmd.Flags().GetString("type")
+ if errTy != nil {
+ printer.Error(fmt.Errorf("error parsing 'type' flag for domain record create : %v", errTy))
+ os.Exit(1)
+ }
+
+ name, errNa := cmd.Flags().GetString("name")
+ if errNa != nil {
+ printer.Error(fmt.Errorf("error parsing 'name' flag for domain record create : %v", errNa))
+ os.Exit(1)
+ }
+
+ dt, errDa := cmd.Flags().GetString("data")
+ if errDa != nil {
+ printer.Error(fmt.Errorf("error parsing 'data' flag for domain record create : %v", errDa))
+ os.Exit(1)
+ }
+
+ ttl, errTt := cmd.Flags().GetInt("ttl")
+ if errTt != nil {
+ printer.Error(fmt.Errorf("error parsing 'ttl' flag for domain record create : %v", errTt))
+ os.Exit(1)
+ }
+
+ priority, errPr := cmd.Flags().GetInt("priority")
+ if errPr != nil {
+ printer.Error(fmt.Errorf("error parsing 'priority' flag for domain record create : %v", errPr))
+ os.Exit(1)
+ }
+
+ o.RecordReq = &govultr.DomainRecordReq{
+ Name: name,
+ Type: rType,
+ Data: dt,
+ TTL: ttl,
+ Priority: &priority,
+ }
+
+ rec, err := o.recordCreate()
+ if err != nil {
+ printer.Error(fmt.Errorf("error creating domain record : %v", err))
+ os.Exit(1)
+ }
+
+ data := &DNSRecordPrinter{Record: *rec}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ recordCreate.Flags().StringP("type", "t", "", "type for the record")
+ if err := recordCreate.MarkFlagRequired("type"); err != nil {
+ printer.Error(fmt.Errorf("error marking dns record create 'type' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ recordCreate.Flags().StringP("name", "n", "", "name of the record")
+ if err := recordCreate.MarkFlagRequired("name"); err != nil {
+ printer.Error(fmt.Errorf("error marking dns record create 'name' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ recordCreate.Flags().StringP("data", "d", "", "data for the record")
+ if err := recordCreate.MarkFlagRequired("data"); err != nil {
+ printer.Error(fmt.Errorf("error marking dns record create 'data' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ recordCreate.Flags().IntP("ttl", "l", 0, "ttl for the record")
+ if err := recordCreate.MarkFlagRequired("ttl"); err != nil {
+ printer.Error(fmt.Errorf("error marking dns record create 'ttl' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ recordCreate.Flags().IntP("priority", "p", 0, "only required for MX and SRV")
+ if err := recordCreate.MarkFlagRequired("priority"); err != nil {
+ printer.Error(fmt.Errorf("error marking dns record create 'priority' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ // Record Delete
+ recordDelete := &cobra.Command{
+ Use: "delete ",
+ Short: "Delete DNS record",
+ Aliases: []string{"destroy"},
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 2 {
+ return errors.New("please provide a domain name & record ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ if err := o.recordDelete(); err != nil {
+ printer.Error(fmt.Errorf("error deleting domain record : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("domain record has been deleted"), nil)
+ },
+ }
+
+ // Record Update
+ recordUpdate := &cobra.Command{
+ Use: "update ",
+ Short: "Update DNS record",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 2 {
+ return errors.New("please provide a domain name & record ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ name, errNa := cmd.Flags().GetString("name")
+ if errNa != nil {
+ printer.Error(fmt.Errorf("error parsing 'name' flag for domain record update : %v", errNa))
+ os.Exit(1)
+ }
+
+ dt, errDa := cmd.Flags().GetString("data")
+ if errDa != nil {
+ printer.Error(fmt.Errorf("error parsing 'data' flag for domain record update : %v", errDa))
+ os.Exit(1)
+ }
+
+ ttl, errTt := cmd.Flags().GetInt("ttl")
+ if errTt != nil {
+ printer.Error(fmt.Errorf("error parsing 'ttl' flag for domain record update : %v", errTt))
+ os.Exit(1)
+ }
+
+ priority, errPr := cmd.Flags().GetInt("priority")
+ if errPr != nil {
+ printer.Error(fmt.Errorf("error parsing 'priority' flag for domain record update : %v", errPr))
+ os.Exit(1)
+ }
+
+ o.RecordReq = &govultr.DomainRecordReq{}
+
+ if cmd.Flags().Changed("name") {
+ o.RecordReq.Name = name
+ }
+
+ if cmd.Flags().Changed("data") {
+ o.RecordReq.Data = dt
+ }
+
+ if cmd.Flags().Changed("ttl") {
+ o.RecordReq.TTL = ttl
+ }
+
+ if cmd.Flags().Changed("priority") {
+ o.RecordReq.Priority = govultr.IntToIntPtr(priority)
+ }
+
+ if err := o.recordUpdate(); err != nil {
+ printer.Error(fmt.Errorf("error updating domain record : %v", errPr))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("domain record has been updated"), nil)
+ },
+ }
+
+ recordUpdate.Flags().StringP("name", "n", "", "name of record")
+ recordUpdate.Flags().StringP("data", "d", "", "data for the record")
+ recordUpdate.Flags().IntP("ttl", "", 0, "time to live for the record")
+ recordUpdate.Flags().IntP("priority", "p", 0, "only required for MX and SRV")
+
+ record.AddCommand(
+ recordList,
+ recordGet,
+ recordCreate,
+ recordUpdate,
+ recordDelete,
+ )
+
+ cmd.AddCommand(
+ domain,
+ record,
+ )
+
+ return cmd
+}
+
+type options struct {
+ Base *cli.Base
+ DomainCreateReq *govultr.DomainReq
+ DomainDNSSECEnabled string
+ SOAUpdateReq *govultr.Soa
+ RecordReq *govultr.DomainRecordReq
+}
+
+// domainList ...
+func (o *options) domainList() ([]govultr.Domain, *govultr.Meta, error) {
+ dms, meta, _, err := o.Base.Client.Domain.List(o.Base.Context, o.Base.Options)
+ return dms, meta, err
+}
+
+// domainGet ...
+func (o *options) domainGet() (*govultr.Domain, error) {
+ dm, _, err := o.Base.Client.Domain.Get(o.Base.Context, o.Base.Args[0])
+ return dm, err
+}
+
+// domainCreate ...
+func (o *options) domainCreate() (*govultr.Domain, error) {
+ dm, _, err := o.Base.Client.Domain.Create(o.Base.Context, o.DomainCreateReq)
+ return dm, err
+}
+
+// domainUpdate ...
+func (o *options) domainUpdate() error {
+ return o.Base.Client.Domain.Update(o.Base.Context, o.Base.Args[0], o.DomainDNSSECEnabled)
+}
+
+// domainDelete ...
+func (o *options) domainDelete() error {
+ return o.Base.Client.Domain.Delete(o.Base.Context, o.Base.Args[0])
+}
+
+// domainDNSSECGet ...
+func (o *options) domainDNSSECGet() ([]string, error) {
+ sec, _, err := o.Base.Client.Domain.GetDNSSec(o.Base.Context, o.Base.Args[0])
+ return sec, err
+}
+
+// domainSOAGet ...
+func (o *options) domainSOAGet() (*govultr.Soa, error) {
+ soa, _, err := o.Base.Client.Domain.GetSoa(o.Base.Context, o.Base.Args[0])
+ return soa, err
+}
+
+// domainSOAUpdate ...
+func (o *options) domainSOAUpdate() error {
+ return o.Base.Client.Domain.UpdateSoa(o.Base.Context, o.Base.Args[0], o.SOAUpdateReq)
+}
+
+// recordList ...
+func (o *options) recordList() ([]govultr.DomainRecord, *govultr.Meta, error) {
+ rec, meta, _, err := o.Base.Client.DomainRecord.List(o.Base.Context, o.Base.Args[0], o.Base.Options)
+ return rec, meta, err
+}
+
+// recordGet ...
+func (o *options) recordGet() (*govultr.DomainRecord, error) {
+ rec, _, err := o.Base.Client.DomainRecord.Get(o.Base.Context, o.Base.Args[0], o.Base.Args[1])
+ return rec, err
+}
+
+// recordCreate ...
+func (o *options) recordCreate() (*govultr.DomainRecord, error) {
+ rec, _, err := o.Base.Client.DomainRecord.Create(o.Base.Context, o.Base.Args[0], o.RecordReq)
+ return rec, err
+}
+
+// recordUpdate ...
+func (o *options) recordUpdate() error {
+ return o.Base.Client.DomainRecord.Update(o.Base.Context, o.Base.Args[0], o.Base.Args[1], o.RecordReq)
+}
+
+// recordDelete ...
+func (o *options) recordDelete() error {
+ return o.Base.Client.DomainRecord.Delete(o.Base.Context, o.Base.Args[0], o.Base.Args[1])
+}
diff --git a/cmd/dns/printer.go b/cmd/dns/printer.go
new file mode 100644
index 00000000..4dea4dfd
--- /dev/null
+++ b/cmd/dns/printer.go
@@ -0,0 +1,279 @@
+package dns
+
+import (
+ "strconv"
+
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+)
+
+// DNSRecordsPrinter ...
+type DNSRecordsPrinter struct {
+ Records []govultr.DomainRecord `json:"records"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (d *DNSRecordsPrinter) JSON() []byte {
+ return printer.MarshalObject(d, "json")
+}
+
+// YAML ...
+func (d *DNSRecordsPrinter) YAML() []byte {
+ return printer.MarshalObject(d, "yaml")
+}
+
+// Columns ...
+func (d *DNSRecordsPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "TYPE",
+ "NAME",
+ "DATA",
+ "PRIORITY",
+ "TTL",
+ }}
+}
+
+// Data ...
+func (d *DNSRecordsPrinter) Data() [][]string {
+ if len(d.Records) == 0 {
+ return [][]string{0: {"---", "---", "---", "---", "---", "---"}}
+ }
+
+ var data [][]string
+ for i := range d.Records {
+ data = append(data, []string{
+ d.Records[i].ID,
+ d.Records[i].Type,
+ d.Records[i].Name,
+ d.Records[i].Data,
+ strconv.Itoa(d.Records[i].Priority),
+ strconv.Itoa(d.Records[i].TTL),
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (d *DNSRecordsPrinter) Paging() [][]string {
+ return printer.NewPaging(d.Meta.Total, &d.Meta.Links.Next, &d.Meta.Links.Prev).Compose()
+}
+
+// ======================================
+
+// DNSRecordPrinter ...
+type DNSRecordPrinter struct {
+ Record govultr.DomainRecord `json:"records"`
+}
+
+// JSON ...
+func (d *DNSRecordPrinter) JSON() []byte {
+ return printer.MarshalObject(d, "json")
+}
+
+// YAML ...
+func (d *DNSRecordPrinter) YAML() []byte {
+ return printer.MarshalObject(d, "yaml")
+}
+
+// Columns ...
+func (d *DNSRecordPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "TYPE",
+ "NAME",
+ "DATA",
+ "PRIORITY",
+ "TTL",
+ }}
+}
+
+// Data ...
+func (d *DNSRecordPrinter) Data() [][]string {
+ return [][]string{0: {
+ d.Record.ID,
+ d.Record.Type,
+ d.Record.Name,
+ d.Record.Data,
+ strconv.Itoa(d.Record.Priority),
+ strconv.Itoa(d.Record.TTL),
+ }}
+}
+
+// Paging ...
+func (d *DNSRecordPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// DNSDomainsPrinter ...
+type DNSDomainsPrinter struct {
+ Domains []govultr.Domain `json:"domains"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (d *DNSDomainsPrinter) JSON() []byte {
+ return printer.MarshalObject(d, "json")
+}
+
+// YAML ...
+func (d *DNSDomainsPrinter) YAML() []byte {
+ return printer.MarshalObject(d, "yaml")
+}
+
+// Columns ...
+func (d *DNSDomainsPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "DOMAIN",
+ "DATE CREATED",
+ "DNSSEC",
+ }}
+}
+
+// Data ...
+func (d *DNSDomainsPrinter) Data() [][]string {
+ if len(d.Domains) == 0 {
+ return [][]string{0: {"---", "---", "---"}}
+ }
+
+ var data [][]string
+ for i := range d.Domains {
+ data = append(data, []string{
+ d.Domains[i].Domain,
+ d.Domains[i].DateCreated,
+ d.Domains[i].DNSSec,
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (d *DNSDomainsPrinter) Paging() [][]string {
+ return printer.NewPaging(d.Meta.Total, &d.Meta.Links.Next, &d.Meta.Links.Prev).Compose()
+}
+
+// ======================================
+
+// DNSDomainPrinter ...
+type DNSDomainPrinter struct {
+ Domain govultr.Domain `json:"domain"`
+}
+
+// JSON ...
+func (d *DNSDomainPrinter) JSON() []byte {
+ return printer.MarshalObject(d, "json")
+}
+
+// YAML ...
+func (d *DNSDomainPrinter) YAML() []byte {
+ return printer.MarshalObject(d, "yaml")
+}
+
+// Columns ...
+func (d *DNSDomainPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "DOMAIN",
+ "DATE CREATED",
+ "DNS SEC",
+ }}
+}
+
+// Data ...
+func (d *DNSDomainPrinter) Data() [][]string {
+ return [][]string{0: {
+ d.Domain.Domain,
+ d.Domain.DateCreated,
+ d.Domain.DNSSec,
+ }}
+}
+
+// Paging ...
+func (d *DNSDomainPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// DNSSOAPrinter ...
+type DNSSOAPrinter struct {
+ SOA govultr.Soa `json:"dns_soa"`
+}
+
+// JSON ...
+func (d *DNSSOAPrinter) JSON() []byte {
+ return printer.MarshalObject(d, "json")
+}
+
+// YAML ...
+func (d *DNSSOAPrinter) YAML() []byte {
+ return printer.MarshalObject(d, "yaml")
+}
+
+// Columns ...
+func (d *DNSSOAPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "NS PRIMARY",
+ "EMAIL",
+ }}
+}
+
+// Data ...
+func (d *DNSSOAPrinter) Data() [][]string {
+ return [][]string{0: {
+ d.SOA.NSPrimary,
+ d.SOA.Email,
+ }}
+}
+
+// Paging ...
+func (d *DNSSOAPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// DNSSECPrinter ...
+type DNSSECPrinter struct {
+ SEC []string `json:"dns_sec"`
+}
+
+// JSON ...
+func (d *DNSSECPrinter) JSON() []byte {
+ return printer.MarshalObject(d, "json")
+}
+
+// YAML ...
+func (d *DNSSECPrinter) YAML() []byte {
+ return printer.MarshalObject(d, "yaml")
+}
+
+// Columns ...
+func (d *DNSSECPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "DNSSEC INFO",
+ }}
+}
+
+// Data ...
+func (d *DNSSECPrinter) Data() [][]string {
+ if len(d.SEC) == 0 {
+ return [][]string{0: {"---"}}
+ }
+
+ var data [][]string
+ for i := range d.SEC {
+ data = append(data, []string{d.SEC[i]})
+ }
+
+ return data
+}
+
+// Paging ...
+func (d *DNSSECPrinter) Paging() [][]string {
+ return nil
+}
diff --git a/cmd/dnsDomain.go b/cmd/dnsDomain.go
deleted file mode 100644
index 09b99c61..00000000
--- a/cmd/dnsDomain.go
+++ /dev/null
@@ -1,229 +0,0 @@
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cmd
-
-import (
- "context"
- "errors"
- "fmt"
- "os"
-
- "github.com/spf13/cobra"
- "github.com/vultr/govultr/v2"
- "github.com/vultr/vultr-cli/cmd/printer"
-)
-
-// DNSDomain represents the domain sub command
-func DNSDomain() *cobra.Command {
- dnsDomainCmd := &cobra.Command{
- Use: "domain",
- Short: "dns domain",
- Long: ``,
- }
-
- dnsDomainCmd.AddCommand(domainCreate, domainGet, domainDelete, secEnable, secInfo, domainList, soaInfo, soaUpdate)
-
- // Create
- domainCreate.Flags().StringP("domain", "d", "", "name of the domain")
- domainCreate.MarkFlagRequired("domain")
- domainCreate.Flags().StringP("ip", "i", "", "instance ip you want to assign this domain to")
-
- // Dns Sec
- secEnable.Flags().StringP("enabled", "e", "", "set whether dns sec is enabled or not. true or false")
- secEnable.MarkFlagRequired("enabled")
-
- // Soa Update
- soaUpdate.Flags().StringP("ns-primary", "n", "", "primary nameserver to store in the SOA record")
- soaUpdate.MarkFlagRequired("ns-primary")
- soaUpdate.Flags().StringP("email", "e", "", "administrative email to store in the SOA record")
-
- // List
- domainList.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
- domainList.Flags().IntP("per-page", "p", 100, "(optional) Number of items requested per page. Default is 100 and Max is 500.")
-
- return dnsDomainCmd
-}
-
-var domainCreate = &cobra.Command{
- Use: "create",
- Short: "create a domain",
- Long: ``,
- Run: func(cmd *cobra.Command, args []string) {
- domain, _ := cmd.Flags().GetString("domain")
- ip, _ := cmd.Flags().GetString("ip")
-
- options := &govultr.DomainReq{
- Domain: domain,
- IP: ip,
- }
-
- dns, err := client.Domain.Create(context.Background(), options)
- if err != nil {
- fmt.Printf("error creating dns domain : %v\n", err)
- os.Exit(1)
- }
-
- printer.Domain(dns)
- },
-}
-
-var domainDelete = &cobra.Command{
- Use: "delete ",
- Short: "delete a domain",
- Aliases: []string{"destroy"},
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a domain name")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- domain := args[0]
- if err := client.Domain.Delete(context.Background(), domain); err != nil {
- fmt.Printf("error delete dns domain : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("deleted dns domain")
- },
-}
-
-var secEnable = &cobra.Command{
- Use: "dnssec ",
- Short: "enable/disable dnssec",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a domain name")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- domain := args[0]
- enabled, _ := cmd.Flags().GetString("enabled")
- if err := client.Domain.Update(context.Background(), domain, enabled); err != nil {
- fmt.Printf("error toggling dnssec : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("toggled dns sec")
- },
-}
-
-var secInfo = &cobra.Command{
- Use: "dnssec-info ",
- Short: "get dns sec info",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a domain name")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- domain := args[0]
- info, err := client.Domain.GetDNSSec(context.Background(), domain)
- if err != nil {
- fmt.Printf("error getting dnssec info : %v\n", err)
- os.Exit(1)
- }
-
- printer.SecInfo(info)
- },
-}
-
-var domainGet = &cobra.Command{
- Use: "get ",
- Short: "get a domain",
- Long: ``,
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- domain, err := client.Domain.Get(context.Background(), id)
- if err != nil {
- fmt.Printf("error getting domain : %v\n", err)
- os.Exit(1)
- }
-
- printer.Domain(domain)
- },
-}
-
-var domainList = &cobra.Command{
- Use: "list",
- Short: "get list of domains",
- Long: ``,
- Run: func(cmd *cobra.Command, args []string) {
- options := getPaging(cmd)
- list, meta, err := client.Domain.List(context.Background(), options)
- if err != nil {
- fmt.Printf("error getting domains : %v\n", err)
- os.Exit(1)
- }
-
- printer.DomainList(list, meta)
- },
-}
-
-var soaInfo = &cobra.Command{
- Use: "soa-info ",
- Short: "get dns soa info",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a domain name")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- domain := args[0]
- info, err := client.Domain.GetSoa(context.Background(), domain)
- if err != nil {
- fmt.Printf("error toggling dnssec : %v\n", err)
- os.Exit(1)
- }
-
- printer.SoaInfo(info)
- },
-}
-
-var soaUpdate = &cobra.Command{
- Use: "soa-update ",
- Short: "update soa for a domain",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a domain name")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- domain := args[0]
- nsPrimary, _ := cmd.Flags().GetString("ns-primary")
- email, _ := cmd.Flags().GetString("email")
-
- soaUpdate := &govultr.Soa{
- NSPrimary: nsPrimary,
- Email: email,
- }
-
- if err := client.Domain.UpdateSoa(context.Background(), domain, soaUpdate); err != nil {
- fmt.Printf("error toggling dnssec : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("updated SOA")
- },
-}
diff --git a/cmd/dnsRecord.go b/cmd/dnsRecord.go
deleted file mode 100644
index f06e0c1f..00000000
--- a/cmd/dnsRecord.go
+++ /dev/null
@@ -1,223 +0,0 @@
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cmd
-
-import (
- "context"
- "errors"
- "fmt"
- "os"
- "regexp"
-
- "github.com/spf13/cobra"
- "github.com/vultr/govultr/v2"
- "github.com/vultr/vultr-cli/cmd/printer"
-)
-
-// DNSRecord represents the dnsRecord command
-func DNSRecord() *cobra.Command {
- dnsRecordCmd := &cobra.Command{
- Use: "record",
- Short: "dns record",
- Long: ``,
- }
-
- dnsRecordCmd.AddCommand(recordCreate, recordGet, recordList, recordDelete, recordUpdate)
-
- // Create
- recordCreate.Flags().StringP("domain", "m", "", "name of domain you want to create this record for")
- recordCreate.Flags().StringP("type", "t", "", "record type you want to create : Possible values A, AAAA, CNAME, NS, MX, SRV, TXT CAA, SSHFP")
- recordCreate.Flags().StringP("name", "n", "", "name of record")
- recordCreate.Flags().StringP("data", "d", "", "data for the record")
- recordCreate.MarkFlagRequired("domain")
- recordCreate.MarkFlagRequired("type")
- recordCreate.MarkFlagRequired("name")
- recordCreate.MarkFlagRequired("data")
- // Create Optional
- recordCreate.Flags().IntP("ttl", "", 0, "time to live for the record")
- recordCreate.Flags().IntP("priority", "p", 0, "only required for MX and SRV")
-
- // Update
- recordUpdate.Flags().StringP("name", "n", "", "name of record")
- recordUpdate.Flags().StringP("data", "d", "", "data for the record")
- recordUpdate.Flags().IntP("ttl", "", 0, "time to live for the record")
- recordUpdate.Flags().IntP("priority", "p", -1, "only required for MX and SRV")
-
- // List
- recordList.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
- recordList.Flags().IntP("per-page", "p", 100, "(optional) Number of items requested per page. Default is 100 and Max is 500.")
-
- return dnsRecordCmd
-}
-
-// Temporary solution to determine if the record type is TXT, in order to
-// add quotes around the value. The API does not accept TXT records without
-// quotes.
-var regRecordTxt = regexp.MustCompile("([A-Z]|=|_)")
-
-var recordCreate = &cobra.Command{
- Use: "create",
- Short: "create a dns record",
- Long: ``,
- Run: func(cmd *cobra.Command, args []string) {
- domain, _ := cmd.Flags().GetString("domain")
- rType, _ := cmd.Flags().GetString("type")
- name, _ := cmd.Flags().GetString("name")
- data, _ := cmd.Flags().GetString("data")
- // Record data for TXT must be enclosed in quotes
- if data[0] != '"' && data[len(data)-1] != '"' && regRecordTxt.Match([]byte(data)) {
- data = fmt.Sprintf("\"%s\"", data)
- }
- ttl, _ := cmd.Flags().GetInt("ttl")
- priority, _ := cmd.Flags().GetInt("priority")
-
- options := &govultr.DomainRecordReq{
- Name: name,
- Type: rType,
- Data: data,
- TTL: ttl,
- Priority: &priority,
- }
-
- record, err := client.DomainRecord.Create(context.Background(), domain, options)
- if err != nil {
- fmt.Printf("error while creating dns record : %v\n", err)
- os.Exit(1)
- }
-
- printer.DnsRecord(record)
- },
-}
-
-var recordGet = &cobra.Command{
- Use: "get ",
- Short: "get dns record",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 2 {
- return errors.New("please provide a domain name and recordID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- domain := args[0]
- id := args[1]
-
- record, err := client.DomainRecord.Get(context.Background(), domain, id)
- if err != nil {
- fmt.Printf("error while getting dns records : %v\n", err)
- os.Exit(1)
- }
-
- printer.DnsRecord(record)
- },
-}
-
-var recordList = &cobra.Command{
- Use: "list ",
- Short: "list all dns records",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a domain name")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- domain := args[0]
- options := getPaging(cmd)
-
- records, meta, err := client.DomainRecord.List(context.Background(), domain, options)
- if err != nil {
- fmt.Printf("error while getting dns records : %v\n", err)
- os.Exit(1)
- }
-
- printer.DnsRecordsList(records, meta)
- },
-}
-
-var recordDelete = &cobra.Command{
- Use: "delete ",
- Short: "delete dns record",
- Aliases: []string{"destroy"},
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 2 {
- return errors.New("please provide a domainName & recordID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- domain := args[0]
- id := args[1]
-
- if err := client.DomainRecord.Delete(context.Background(), domain, id); err != nil {
- fmt.Printf("error while deleting dns record : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("deleted dns record")
- },
-}
-
-var recordUpdate = &cobra.Command{
- Use: "update ",
- Short: "update dns record",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 2 {
- return errors.New("please provide a domainName & recordID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- domain := args[0]
- id := args[1]
- name, _ := cmd.Flags().GetString("name")
- data, _ := cmd.Flags().GetString("data")
- ttl, _ := cmd.Flags().GetInt("ttl")
- priority, _ := cmd.Flags().GetInt("priority")
-
- updates := &govultr.DomainRecordReq{}
-
- if name != "" {
- updates.Name = name
- }
-
- if data != "" {
- // Record data for TXT must be enclosed in quotes
- if data[0] != '"' && data[len(data)-1] != '"' && regRecordTxt.Match([]byte(data)) {
- data = fmt.Sprintf("\"%s\"", data)
- }
- updates.Data = data
- }
-
- if ttl != 0 {
- updates.TTL = ttl
- }
-
- if priority != -1 {
- updates.Priority = &priority
- }
-
- if err := client.DomainRecord.Update(context.Background(), domain, id, updates); err != nil {
- fmt.Printf("error updating dns record : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("updated dns record")
- },
-}
diff --git a/cmd/firewall.go b/cmd/firewall.go
deleted file mode 100644
index 23899c32..00000000
--- a/cmd/firewall.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cmd
-
-import (
- "github.com/spf13/cobra"
-)
-
-// Firewall represents the firewall command
-func Firewall() *cobra.Command {
- firewallCmd := &cobra.Command{
- Use: "firewall",
- Short: "firewall is used to access firewall commands",
- Long: ``,
- Aliases: []string{"fw"},
- }
-
- firewallCmd.AddCommand(FirewallGroup(), FirewallRule())
-
- return firewallCmd
-}
diff --git a/cmd/firewall/firewall.go b/cmd/firewall/firewall.go
new file mode 100644
index 00000000..06a3ca04
--- /dev/null
+++ b/cmd/firewall/firewall.go
@@ -0,0 +1,538 @@
+// Package firewall provides the functionality for firewall commands in the CLI
+package firewall
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "strconv"
+
+ "github.com/spf13/cobra"
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+ "github.com/vultr/vultr-cli/v3/pkg/cli"
+)
+
+var (
+ ruleLong = `Show commands available for firewall rules`
+ ruleExample = `
+ # Full example
+ vultr-cli firewall rule
+
+ # Shortened example with aliases
+ vultr-cli fw r
+ `
+ ruleCreateLong = `
+ Create a new firewall rule in the provided firewall group
+
+ If protocol is TCP or UDP, port must be provided.
+
+ An ip-type of v4 or v6 must be supplied for all rules.
+ `
+ ruleCreateExample = `
+ # Full examples
+ vultr-cli firewall rule create --id=f04ae5aa-ff6a-4078-900d-78cc17dca2d5 --ip-type=v4 --protocol=tcp --size=24 \
+ --subnet=127.0.0.0 --port=30000
+
+ vultr-cli firewall rule create --id=f04ae5aa-ff6a-4078-900d-78cc17dca2d5 --ip-type=v4 --protocol=icmp --size=24 --subnet=127.0.0.0
+
+ # Shortened example with aliases
+ vultr-cli fw r c -i=f04ae5aa-ff6a-4078-900d-78cc17dca2d5 -t=v4 -p=tcp -z=24 -s=127.0.0.0 -r=30000
+ `
+ ruleDeleteLong = `Delete a firewall rule in the provided firewall group`
+ ruleDeleteExample = `
+ # Full example
+ vultr-cli firewall rule delete 704ac064-4ff2-49ca-a6e6-88262cca8f8a f31ade4f-2308-4a58-82c6-2d1bae0837b3
+
+ # Shortened example with aliases
+ vultr-cli fw r d 704ac064-4ff2-49ca-a6e6-88262cca8f8a f31ade4f-2308-4a58-82c6-2d1bae0837b3
+ `
+ ruleGetLong = `Get a firewall rule in the provided firewall group`
+ ruleGetExample = `
+ # Full example
+ vultr-cli firewall rule get 704ac064-4ff2-49ca-a6e6-88262cca8f8a f31ade4f-2308-4a58-82c6-2d1bae0837b3
+
+ # Shortened example with aliases
+ vultr-cli fw r get 704ac064-4ff2-49ca-a6e6-88262cca8f8a f31ade4f-2308-4a58-82c6-2d1bae0837b3
+ `
+ ruleListLong = `List all firewall rules in the provided firewall group`
+ ruleListExample = `
+ # Full example
+ vultr-cli firewall rule list 704ac064-4ff2-49ca-a6e6-88262cca8f8a
+
+ # Shortened example with aliases
+ vultr-cli fw r l 704ac064-4ff2-49ca-a6e6-88262cca8f8a
+ `
+)
+
+// NewCmdFirewall provides the CLI command functionality for Firewall
+func NewCmdFirewall(base *cli.Base) *cobra.Command { //nolint:gocyclo
+ o := &options{Base: base}
+
+ cmd := &cobra.Command{
+ Use: "firewall",
+ Short: "Access firewall commands",
+ Aliases: []string{"fw"},
+ PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+ utils.SetOptions(o.Base, cmd, args)
+ if !o.Base.HasAuth {
+ return errors.New(utils.APIKeyError)
+ }
+ return nil
+ },
+ }
+
+ // Group
+ group := &cobra.Command{
+ Use: "group",
+ Short: "Commands to access firewall group functions",
+ Aliases: []string{"g"},
+ }
+
+ // Group List
+ groupList := &cobra.Command{
+ Use: "list",
+ Short: "List all firewall groups",
+ Aliases: []string{"l"},
+ Run: func(cmd *cobra.Command, args []string) {
+ o.Base.Options = utils.GetPaging(cmd)
+
+ groups, meta, err := o.listGroups()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving firewall group list : %v", err))
+ os.Exit(1)
+ }
+
+ data := &FirewallGroupsPrinter{Groups: groups, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ groupList.Flags().StringP("cursor", "c", "", "(optional) cursor for paging.")
+ groupList.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ fmt.Sprintf("(optional) Number of items requested per page. Default is %d and Max is 500.", utils.PerPageDefault),
+ )
+
+ // Group Get
+ groupGet := &cobra.Command{
+ Use: "get ",
+ Short: "Get firewall group",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a firewall group ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ group, err := o.getGroup()
+ if err != nil {
+ printer.Error(fmt.Errorf("error getting firewall group : %v", err))
+ os.Exit(1)
+ }
+
+ data := &FirewallGroupPrinter{Group: *group}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ // Group Create
+ groupCreate := &cobra.Command{
+ Use: "create",
+ Short: "create a firewall group",
+ Aliases: []string{"c"},
+ Run: func(cmd *cobra.Command, args []string) {
+ description, errDe := cmd.Flags().GetString("description")
+ if errDe != nil {
+ printer.Error(fmt.Errorf("error parsing 'description' flag for firewall group create: %v", errDe))
+ os.Exit(1)
+ }
+
+ o.GroupReq = &govultr.FirewallGroupReq{
+ Description: description,
+ }
+
+ grp, err := o.createGroup()
+ if err != nil {
+ printer.Error(fmt.Errorf("error creating firewall group : %v", err))
+ os.Exit(1)
+ }
+
+ data := &FirewallGroupPrinter{Group: *grp}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ groupCreate.Flags().StringP("description", "d", "", "(optional) Description of firewall group.")
+
+ // Group Update
+ groupUpdate := &cobra.Command{
+ Use: "update ",
+ Short: "Update firewall group description",
+ Aliases: []string{"u"},
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a firewall group ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ description, errDe := cmd.Flags().GetString("description")
+ if errDe != nil {
+ printer.Error(fmt.Errorf("error parsing 'description' flag for firewall group update : %v", errDe))
+ os.Exit(1)
+ }
+
+ o.GroupReq = &govultr.FirewallGroupReq{
+ Description: description,
+ }
+
+ if err := o.updateGroup(); err != nil {
+ printer.Error(fmt.Errorf("error updating firewall group : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("firewall group has been updated"), nil)
+ },
+ }
+
+ groupUpdate.Flags().StringP("description", "d", "", "Description of firewall group.")
+ if err := groupUpdate.MarkFlagRequired("description"); err != nil {
+ printer.Error(fmt.Errorf("error marking firewall group 'description' flag required: %v", err))
+ os.Exit(1)
+ }
+
+ // Group Delete
+ groupDelete := &cobra.Command{
+ Use: "delete ",
+ Short: "Delete a firewall group",
+ Aliases: []string{"d", "destroy"},
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a firewall group ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ if err := o.deleteGroup(); err != nil {
+ printer.Error(fmt.Errorf("error deleting firewall group : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("firewall group has been deleted"), nil)
+ },
+ }
+
+ group.AddCommand(
+ groupList,
+ groupGet,
+ groupCreate,
+ groupUpdate,
+ groupDelete,
+ )
+
+ // Rule
+ rule := &cobra.Command{
+ Use: "rule",
+ Short: "Commands to access firewall rules",
+ Aliases: []string{"r"},
+ Long: ruleLong,
+ Example: ruleExample,
+ }
+
+ // Rule List
+ ruleList := &cobra.Command{
+ Use: "list ",
+ Short: "List all firewall rules",
+ Aliases: []string{"l"},
+ Long: ruleListLong,
+ Example: ruleListExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a firewall group ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ o.Base.Options = utils.GetPaging(cmd)
+
+ rules, meta, err := o.listRules()
+ if err != nil {
+ printer.Error(fmt.Errorf("error retrieving firewall rule list : %v", err))
+ os.Exit(1)
+ }
+
+ data := &FirewallRulesPrinter{Rules: rules, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ ruleList.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
+ ruleList.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ "(optional) Number of items requested per page. Default is 100 and Max is 500.",
+ )
+
+ // Rule Get
+ ruleGet := &cobra.Command{
+ Use: "get ",
+ Short: "Get firewall rule",
+ Long: ruleGetLong,
+ Example: ruleGetExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 2 {
+ return errors.New("please provide a firewall group ID and firewall rule number")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ rule, err := o.getRule()
+ if err != nil {
+ printer.Error(fmt.Errorf("error getting firewall rule : %v", err))
+ os.Exit(1)
+ }
+
+ data := &FirewallRulePrinter{Rule: *rule}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ // Rule Create
+ ruleCreate := &cobra.Command{
+ Use: "create",
+ Short: "Create a firewall rule",
+ Aliases: []string{"c"},
+ Long: ruleCreateLong,
+ Example: ruleCreateExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a firewall group ID")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ protocol, errPr := cmd.Flags().GetString("protocol")
+ if errPr != nil {
+ printer.Error(fmt.Errorf("error parsing 'protocol' flag for firewall group create : %v", errPr))
+ os.Exit(1)
+ }
+
+ subnet, errSu := cmd.Flags().GetString("subnet")
+ if errSu != nil {
+ printer.Error(fmt.Errorf("error parsing 'subnet' flag for firewall group create : %v", errSu))
+ os.Exit(1)
+ }
+
+ ipType, errIP := cmd.Flags().GetString("ip-type")
+ if errIP != nil {
+ printer.Error(fmt.Errorf("error parsing 'ip-type' flag for firewall group create : %v", errIP))
+ os.Exit(1)
+ }
+
+ size, errSi := cmd.Flags().GetInt("size")
+ if errSi != nil {
+ printer.Error(fmt.Errorf("error parsing 'size' flag for firewall group create : %v", errSi))
+ os.Exit(1)
+ }
+
+ source, errSo := cmd.Flags().GetString("source")
+ if errSo != nil {
+ printer.Error(fmt.Errorf("error parsing 'source' flag for firewall group create : %v", errSo))
+ os.Exit(1)
+ }
+
+ port, errPo := cmd.Flags().GetString("port")
+ if errPo != nil {
+ printer.Error(fmt.Errorf("error parsing 'port' flag for firewall group create : %v", errPo))
+ os.Exit(1)
+ }
+
+ notes, errNo := cmd.Flags().GetString("notes")
+ if errNo != nil {
+ printer.Error(fmt.Errorf("error parsing 'notes' flag for firewall group create : %v", errNo))
+ os.Exit(1)
+ }
+
+ o.RuleReq = &govultr.FirewallRuleReq{
+ Protocol: protocol,
+ Subnet: subnet,
+ SubnetSize: size,
+ Notes: notes,
+ }
+
+ if port != "" {
+ o.RuleReq.Port = port
+ }
+
+ if source != "" {
+ o.RuleReq.Source = source
+ }
+
+ if ipType == "" {
+ printer.Error(fmt.Errorf("a firewall rule requires an IP type. Pass an --ip-type value of v4 or v6"))
+ os.Exit(1)
+ }
+
+ if ipType != "" {
+ o.RuleReq.IPType = ipType
+ }
+
+ rule, err := o.createRule()
+ if err != nil {
+ printer.Error(fmt.Errorf("error creating firewall rule : %v", err))
+ os.Exit(1)
+ }
+
+ data := &FirewallRulePrinter{Rule: *rule}
+ o.Base.Printer.Display(data, nil)
+ },
+ }
+
+ ruleCreate.Flags().StringP("protocol", "p", "", "Protocol type. Possible values: 'icmp', 'tcp', 'udp', 'gre'.")
+ if err := ruleCreate.MarkFlagRequired("protocol"); err != nil {
+ printer.Error(fmt.Errorf("error marking firewall rule create 'protocol' flag required : %v", err))
+ os.Exit(1)
+ }
+
+ ruleCreate.Flags().StringP("subnet", "s", "", "The IPv4 network in CIDR notation.")
+ if err := ruleCreate.MarkFlagRequired("subnet"); err != nil {
+ printer.Error(fmt.Errorf("error marking firewall rule create 'subnet' flag required : %v", err))
+ os.Exit(1)
+ }
+
+ ruleCreate.Flags().IntP("size", "z", 0, "The number of bits for the netmask in CIDR notation.")
+ if err := ruleCreate.MarkFlagRequired("size"); err != nil {
+ printer.Error(fmt.Errorf("error marking firewall rule create 'size' flag required : %v", err))
+ os.Exit(1)
+ }
+
+ ruleCreate.Flags().StringP(
+ "source",
+ "",
+ "",
+ "(optional) When empty, uses value from subnet and size. If \"cloudflare\", allows all Cloudflare IP space through firewall.",
+ )
+
+ ruleCreate.Flags().StringP("ip-type", "t", "", "The type of IP rule - v4 or v6.")
+ if err := ruleCreate.MarkFlagRequired("ip-type"); err != nil {
+ printer.Error(fmt.Errorf("error marking firewall rule create 'ip-type' flag required : %v", err))
+ os.Exit(1)
+ }
+
+ ruleCreate.Flags().StringP(
+ "port",
+ "r",
+ "",
+ "(optional) TCP/UDP only. This field can be an integer value specifying a port or a colon separated port range.",
+ )
+
+ ruleCreate.Flags().StringP("notes", "n", "", "(optional) This field supports notes up to 255 characters.")
+
+ // Rule Delete
+ ruleDelete := &cobra.Command{
+ Use: "delete ",
+ Short: "Delete a firewall rule",
+ Aliases: []string{"d", "destroy"},
+ Long: ruleDeleteLong,
+ Example: ruleDeleteExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 2 {
+ return errors.New("please provide a firewall group ID and firewall rule number")
+ }
+ return nil
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ if err := o.deleteRule(); err != nil {
+ printer.Error(fmt.Errorf("error deleting firewall rule : %v", err))
+ os.Exit(1)
+ }
+
+ o.Base.Printer.Display(printer.Info("firewall rule deleted"), nil)
+ },
+ }
+
+ rule.AddCommand(
+ ruleList,
+ ruleGet,
+ ruleCreate,
+ ruleDelete,
+ )
+
+ cmd.AddCommand(
+ group,
+ rule,
+ )
+
+ return cmd
+}
+
+type options struct {
+ Base *cli.Base
+ GroupReq *govultr.FirewallGroupReq
+ RuleReq *govultr.FirewallRuleReq
+}
+
+// listGroups ...
+func (o *options) listGroups() ([]govultr.FirewallGroup, *govultr.Meta, error) {
+ groups, meta, _, err := o.Base.Client.FirewallGroup.List(o.Base.Context, o.Base.Options)
+ return groups, meta, err
+}
+
+// getGroup ...
+func (o *options) getGroup() (*govultr.FirewallGroup, error) {
+ group, _, err := o.Base.Client.FirewallGroup.Get(o.Base.Context, o.Base.Args[0])
+ return group, err
+}
+
+// createGroup ...
+func (o *options) createGroup() (*govultr.FirewallGroup, error) {
+ group, _, err := o.Base.Client.FirewallGroup.Create(o.Base.Context, o.GroupReq)
+ return group, err
+}
+
+// updateGroup ...
+func (o *options) updateGroup() error {
+ return o.Base.Client.FirewallGroup.Update(o.Base.Context, o.Base.Args[0], o.GroupReq)
+}
+
+// deleteGroup ...
+func (o *options) deleteGroup() error {
+ return o.Base.Client.FirewallGroup.Delete(o.Base.Context, o.Base.Args[0])
+}
+
+// listRules ...
+func (o *options) listRules() ([]govultr.FirewallRule, *govultr.Meta, error) {
+ rules, meta, _, err := o.Base.Client.FirewallRule.List(o.Base.Context, o.Base.Args[0], o.Base.Options)
+ return rules, meta, err
+}
+
+// getRule ...
+func (o *options) getRule() (*govultr.FirewallRule, error) {
+ id, errIn := strconv.Atoi(o.Base.Args[1])
+ if errIn != nil {
+ return nil, fmt.Errorf("unable to convert int to string : %v", errIn)
+ }
+
+ rule, _, err := o.Base.Client.FirewallRule.Get(o.Base.Context, o.Base.Args[0], id)
+ return rule, err
+}
+
+// createRule ...
+func (o *options) createRule() (*govultr.FirewallRule, error) {
+ rule, _, err := o.Base.Client.FirewallRule.Create(o.Base.Context, o.Base.Args[0], o.RuleReq)
+ return rule, err
+}
+
+// deleteRule ...
+func (o *options) deleteRule() error {
+ id, err := strconv.Atoi(o.Base.Args[1])
+ if err != nil {
+ return fmt.Errorf("unable to convert int to string : %v", err)
+ }
+ return o.Base.Client.FirewallRule.Delete(o.Base.Context, o.Base.Args[0], id)
+}
diff --git a/cmd/firewall/printer.go b/cmd/firewall/printer.go
new file mode 100644
index 00000000..9fc1a53b
--- /dev/null
+++ b/cmd/firewall/printer.go
@@ -0,0 +1,223 @@
+package firewall
+
+import (
+ "strconv"
+
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+)
+
+// FirewallGroupsPrinter ...
+type FirewallGroupsPrinter struct {
+ Groups []govultr.FirewallGroup `json:"firewall_groups"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (f *FirewallGroupsPrinter) JSON() []byte {
+ return printer.MarshalObject(f, "json")
+}
+
+// YAML ...
+func (f *FirewallGroupsPrinter) YAML() []byte {
+ return printer.MarshalObject(f, "yaml")
+}
+
+// Columns ...
+func (f *FirewallGroupsPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "DATE CREATED",
+ "DATE MODIFIED",
+ "INSTANCE COUNT",
+ "RULE COUNT",
+ "MAX RULE COUNT",
+ "DESCRIPTION",
+ }}
+}
+
+// Data ...
+func (f *FirewallGroupsPrinter) Data() [][]string {
+ if len(f.Groups) == 0 {
+ return [][]string{0: {"---", "---", "---", "---", "---", "---", "---"}}
+ }
+
+ var data [][]string
+ for i := range f.Groups {
+ data = append(data, []string{
+ f.Groups[i].ID,
+ f.Groups[i].DateCreated,
+ f.Groups[i].DateModified,
+ strconv.Itoa(f.Groups[i].InstanceCount),
+ strconv.Itoa(f.Groups[i].RuleCount),
+ strconv.Itoa(f.Groups[i].MaxRuleCount),
+ f.Groups[i].Description,
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (f *FirewallGroupsPrinter) Paging() [][]string {
+ return printer.NewPaging(f.Meta.Total, &f.Meta.Links.Next, &f.Meta.Links.Prev).Compose()
+}
+
+// ======================================
+
+// FirewallGroupPrinter ...
+type FirewallGroupPrinter struct {
+ Group govultr.FirewallGroup `json:"firewall_group"`
+}
+
+// JSON ...
+func (f *FirewallGroupPrinter) JSON() []byte {
+ return printer.MarshalObject(f, "json")
+}
+
+// YAML ...
+func (f *FirewallGroupPrinter) YAML() []byte {
+ return printer.MarshalObject(f, "yaml")
+}
+
+// Columns ...
+func (f *FirewallGroupPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "DATE CREATED",
+ "DATE MODIFIED",
+ "INSTANCE COUNT",
+ "RULE COUNT",
+ "MAX RULE COUNT",
+ "DESCRIPTION",
+ }}
+}
+
+// Data ...
+func (f *FirewallGroupPrinter) Data() [][]string {
+ return [][]string{0: {
+ f.Group.ID,
+ f.Group.DateCreated,
+ f.Group.DateModified,
+ strconv.Itoa(f.Group.InstanceCount),
+ strconv.Itoa(f.Group.RuleCount),
+ strconv.Itoa(f.Group.MaxRuleCount),
+ f.Group.Description,
+ }}
+}
+
+// Paging ...
+func (f *FirewallGroupPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// FirewallRulesPrinter ...
+type FirewallRulesPrinter struct {
+ Rules []govultr.FirewallRule `json:"firewall_rules"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (f *FirewallRulesPrinter) JSON() []byte {
+ return printer.MarshalObject(f, "json")
+}
+
+// YAML ...
+func (f *FirewallRulesPrinter) YAML() []byte {
+ return printer.MarshalObject(f, "yaml")
+}
+
+// Columns ...
+func (f *FirewallRulesPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "RULE NUMBER",
+ "ACTION",
+ "TYPE",
+ "PROTOCOL",
+ "PORT",
+ "NETWORK",
+ "SOURCE",
+ "NOTES",
+ }}
+}
+
+// Data ...
+func (f *FirewallRulesPrinter) Data() [][]string {
+ if len(f.Rules) == 0 {
+ return [][]string{0: {"---", "---", "---", "---", "---", "---", "---", "---"}}
+ }
+
+ var data [][]string
+ for i := range f.Rules {
+ data = append(data, []string{
+ strconv.Itoa(f.Rules[i].ID),
+ f.Rules[i].Action,
+ f.Rules[i].IPType,
+ f.Rules[i].Protocol,
+ f.Rules[i].Port,
+ utils.FormatFirewallNetwork(f.Rules[i].Subnet, f.Rules[i].SubnetSize),
+ utils.GetFirewallSource(f.Rules[i].Source),
+ f.Rules[i].Notes,
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (f *FirewallRulesPrinter) Paging() [][]string {
+ return printer.NewPaging(f.Meta.Total, &f.Meta.Links.Next, &f.Meta.Links.Prev).Compose()
+}
+
+// ======================================
+
+// FirewallRulePrinter ...
+type FirewallRulePrinter struct {
+ Rule govultr.FirewallRule `json:"firewall_rule"`
+}
+
+// JSON ...
+func (f *FirewallRulePrinter) JSON() []byte {
+ return printer.MarshalObject(f, "json")
+}
+
+// YAML ...
+func (f *FirewallRulePrinter) YAML() []byte {
+ return printer.MarshalObject(f, "yaml")
+}
+
+// Columns ...
+func (f *FirewallRulePrinter) Columns() [][]string {
+ return [][]string{0: {
+ "RULE NUMBER",
+ "ACTION",
+ "TYPE",
+ "PROTOCOL",
+ "PORT",
+ "NETWORK",
+ "SOURCE",
+ "NOTES",
+ }}
+}
+
+// Data ...
+func (f *FirewallRulePrinter) Data() [][]string {
+ return [][]string{0: {
+ strconv.Itoa(f.Rule.ID),
+ f.Rule.Action,
+ f.Rule.IPType,
+ f.Rule.Protocol,
+ f.Rule.Port,
+ utils.FormatFirewallNetwork(f.Rule.Subnet, f.Rule.SubnetSize),
+ utils.GetFirewallSource(f.Rule.Source),
+ f.Rule.Notes,
+ }}
+}
+
+// Paging ...
+func (f *FirewallRulePrinter) Paging() [][]string {
+ return nil
+}
diff --git a/cmd/firewallGroup.go b/cmd/firewallGroup.go
deleted file mode 100644
index a83f5798..00000000
--- a/cmd/firewallGroup.go
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cmd
-
-import (
- "context"
- "errors"
- "fmt"
- "os"
-
- "github.com/spf13/cobra"
- "github.com/vultr/govultr/v2"
- "github.com/vultr/vultr-cli/cmd/printer"
-)
-
-// FirewallGroup represents the firewall group commands
-func FirewallGroup() *cobra.Command {
- firewallGroupCmd := &cobra.Command{
- Use: "group",
- Short: "group is used to access firewall group commands",
- Long: ``,
- Aliases: []string{"g"},
- }
-
- firewallGroupCmd.AddCommand(firewallGroupCreate, firewallGroupDelete, firewallGroupGet, firewallGroupUpdate, firewallGroupList)
-
- firewallGroupCreate.Flags().StringP("description", "d", "", "(optional) Description of firewall group.")
-
- firewallGroupList.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
- firewallGroupList.Flags().IntP("per-page", "p", 100, "(optional) Number of items requested per page. Default is 100 and Max is 500.")
-
- return firewallGroupCmd
-}
-
-var firewallGroupCreate = &cobra.Command{
- Use: "create",
- Short: "create a firewall group",
- Aliases: []string{"c"},
- Run: func(cmd *cobra.Command, args []string) {
- description, _ := cmd.Flags().GetString("description")
- options := &govultr.FirewallGroupReq{
- Description: description,
- }
-
- fwg, err := client.FirewallGroup.Create(context.Background(), options)
- if err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- printer.FirewallGroup(fwg)
- },
-}
-
-var firewallGroupDelete = &cobra.Command{
- Use: "delete ",
- Short: "Delete a firewall group",
- Aliases: []string{"d", "destroy"},
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a firewallGroupID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- if err := client.FirewallGroup.Delete(context.Background(), args[0]); err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Firewall group has been deleted")
- },
-}
-
-var firewallGroupUpdate = &cobra.Command{
- Use: "update ",
- Short: "Update firewall group description",
- Aliases: []string{"u"},
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 2 {
- return errors.New("please provide a firewallGroupID and description")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- description := args[1]
- options := &govultr.FirewallGroupReq{
- Description: description,
- }
-
- if err := client.FirewallGroup.Update(context.Background(), args[0], options); err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Firewall group has been updated")
- },
-}
-
-var firewallGroupGet = &cobra.Command{
- Use: "get ",
- Short: "Get firewall group",
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a firewallGroupID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- options := getPaging(cmd)
- list, meta, err := client.FirewallGroup.List(context.Background(), options)
- if err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- printer.FirewallGroups(list, meta)
- },
-}
-
-var firewallGroupList = &cobra.Command{
- Use: "list",
- Short: "List all firewall groups",
- Aliases: []string{"l"},
- Run: func(cmd *cobra.Command, args []string) {
- options := getPaging(cmd)
- list, meta, err := client.FirewallGroup.List(context.Background(), options)
- if err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- printer.FirewallGroups(list, meta)
- },
-}
diff --git a/cmd/firewallRule.go b/cmd/firewallRule.go
deleted file mode 100644
index ca9f1d52..00000000
--- a/cmd/firewallRule.go
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cmd
-
-import (
- "context"
- "errors"
- "fmt"
- "os"
- "strconv"
-
- "github.com/spf13/cobra"
- "github.com/vultr/govultr/v2"
- "github.com/vultr/vultr-cli/cmd/printer"
-)
-
-// FirewallRule represents the firewall rule commands
-func FirewallRule() *cobra.Command {
- firewallRuleCmd := &cobra.Command{
- Use: "rule",
- Short: "rule is used to access firewall rule commands",
- Aliases: []string{"r"},
- }
-
- firewallRuleCmd.AddCommand(firewallRuleCreate, firewallRuleDelete, firewallRuleGet, firewallRuleList)
-
- firewallRuleCreate.Flags().StringP("id", "i", "", "ID of the target firewall group.")
- firewallRuleCreate.Flags().StringP("protocol", "p", "", "Protocol type. Possible values: 'icmp', 'tcp', 'udp', 'gre'.")
- firewallRuleCreate.Flags().StringP("subnet", "s", "", "The IPv4 network in CIDR notation.")
- firewallRuleCreate.Flags().IntP("size", "z", 0, "The number of bits for the netmask in CIDR notation.")
- firewallRuleCreate.Flags().IntP("source", "o", 0, "(optional) When empty, uses value from subnet and size. If \"cloudflare\", allows all Cloudflare IP space through firewall.")
- firewallRuleCreate.Flags().StringP("type", "t", "", "The type of IP rule - v4 or v6.")
-
- firewallRuleCreate.Flags().StringP("port", "r", "", "(optional) TCP/UDP only. This field can be an integer value specifying a port or a colon separated port range.")
- firewallRuleCreate.Flags().StringP("notes", "n", "", "(optional) This field supports notes up to 255 characters.")
-
- firewallRuleCreate.MarkFlagRequired("id")
- firewallRuleCreate.MarkFlagRequired("protocol")
- firewallRuleCreate.MarkFlagRequired("subnet")
- firewallRuleCreate.MarkFlagRequired("size")
- firewallRuleCreate.MarkFlagRequired("type")
-
- firewallRuleList.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
- firewallRuleList.Flags().IntP("per-page", "p", 100, "(optional) Number of items requested per page. Default is 100 and Max is 500.")
-
- return firewallRuleCmd
-}
-
-var firewallRuleCreate = &cobra.Command{
- Use: "create",
- Short: "create a firewall rule",
- Aliases: []string{"c"},
- Run: func(cmd *cobra.Command, args []string) {
- id, _ := cmd.Flags().GetString("id")
- protocol, _ := cmd.Flags().GetString("protocol")
- subnet, _ := cmd.Flags().GetString("subnet")
- ipType, _ := cmd.Flags().GetString("type")
- size, _ := cmd.Flags().GetInt("size")
- source, _ := cmd.Flags().GetString("source")
- port, _ := cmd.Flags().GetString("port")
- notes, _ := cmd.Flags().GetString("notes")
-
- options := &govultr.FirewallRuleReq{
- Protocol: protocol,
- IPType: ipType,
- Subnet: subnet,
- SubnetSize: size,
- Notes: notes,
- }
-
- if port != "" {
- options.Port = port
- }
-
- if source != "" {
- options.Source = source
- }
-
- fwr, err := client.FirewallRule.Create(context.Background(), id, options)
- if err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- printer.FirewallRule(fwr)
- },
-}
-
-var firewallRuleDelete = &cobra.Command{
- Use: "delete ",
- Short: "Delete a firewall rule",
- Aliases: []string{"d", "destroy"},
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 2 {
- return errors.New("please provide a firewallGroupID and firewallRuleNumber")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- rule, _ := strconv.Atoi(args[1])
- if err := client.FirewallRule.Delete(context.Background(), args[0], rule); err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
- fmt.Println("Firewall rule has been deleted")
- },
-}
-
-var firewallRuleGet = &cobra.Command{
- Use: "get ",
- Short: "Get firewall rule",
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 2 {
- return errors.New("please provide a firewallGroupID and firewallRuleNumber")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- ruleNumber, _ := strconv.Atoi(args[1])
- fwRule, err := client.FirewallRule.Get(context.Background(), args[0], ruleNumber)
- if err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- printer.FirewallRule(fwRule)
- },
-}
-
-var firewallRuleList = &cobra.Command{
- Use: "list ",
- Short: "List all firewall rules",
- Aliases: []string{"l"},
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide a firewallGroupID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- options := getPaging(cmd)
- list, meta, err := client.FirewallRule.List(context.Background(), args[0], options)
- if err != nil {
- fmt.Printf("%v\n", err)
- os.Exit(1)
- }
-
- printer.FirewallRules(list, meta)
- },
-}
diff --git a/cmd/instance.go b/cmd/instance.go
deleted file mode 100644
index b82a5494..00000000
--- a/cmd/instance.go
+++ /dev/null
@@ -1,1153 +0,0 @@
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cmd
-
-import (
- "context"
- "encoding/base64"
- "errors"
- "fmt"
- "io/ioutil"
- "os"
-
- "github.com/spf13/cobra"
- "github.com/vultr/govultr/v2"
- "github.com/vultr/vultr-cli/cmd/printer"
-)
-
-// Instance represents the instance command
-func Instance() *cobra.Command {
- instanceCmd := &cobra.Command{
- Use: "instance",
- Short: "commands to interact with instances on vultr",
- Long: ``,
- }
-
- instanceCmd.AddCommand(instanceStart, instanceStop, instanceRestart, instanceReinstall, instanceTag, instanceDelete, instanceLabel, instanceBandwidth, instanceList, instanceInfo, updateFwgGroup, instanceRestore, instanceCreate)
-
- instanceTag.Flags().StringP("tag", "t", "", "tag you want to set for a given instance")
- instanceTag.MarkFlagRequired("tag")
-
- instanceLabel.Flags().StringP("label", "l", "", "label you want to set for a given instance")
- instanceLabel.MarkFlagRequired("label")
-
- updateFwgGroup.Flags().StringP("instance-id", "i", "", "instance id of the instance you want to use")
- updateFwgGroup.Flags().StringP("firewall-group-id", "f", "", "firewall group id that you want to assign. 0 Value will unset the firewall-group")
- updateFwgGroup.MarkFlagRequired("instance-id")
- updateFwgGroup.MarkFlagRequired("firewall-group-id")
-
- instanceRestore.Flags().StringP("backup", "b", "", "id of backup you wish to restore the instance with")
- instanceRestore.Flags().StringP("snapshot", "s", "", "id of snapshot you wish to restore the instance with")
-
- instanceCreate.Flags().StringP("region", "r", "", "region id you wish to have the instance created in")
- instanceCreate.Flags().StringP("plan", "p", "", "plan id you wish the instance to have")
- instanceCreate.Flags().IntP("operatingSystems", "o", 0, "operatingSystems id you wish the instance to have")
- instanceCreate.MarkFlagRequired("region")
- instanceCreate.MarkFlagRequired("plan")
-
- // Optional Params
- instanceCreate.Flags().StringP("ipxe", "", "", "if you've selected the 'custom' operating system, this can be set to chainload the specified URL on bootup")
- instanceCreate.Flags().StringP("iso", "", "", "iso ID you want to create the instance with")
- instanceCreate.Flags().StringP("snapshot", "", "", "snapshot ID you want to create the instance with")
- instanceCreate.Flags().StringP("script-id", "", "", "script id of the startup script")
- instanceCreate.Flags().BoolP("ipv6", "", false, "enable ipv6 | true or false")
- instanceCreate.Flags().BoolP("private-network", "", false, "enable private network | true or false")
- instanceCreate.Flags().StringArrayP("network", "", []string{}, "network IDs you want to assign to the instance")
- instanceCreate.Flags().StringP("label", "l", "", "label you want to give this instance")
- instanceCreate.Flags().StringArrayP("ssh-keys", "s", []string{}, "ssh keys you want to assign to the instance")
- instanceCreate.Flags().BoolP("auto-backup", "b", false, "enable auto backups | true or false")
- instanceCreate.Flags().IntP("app", "a", 0, "application ID you want this instance to have")
- instanceCreate.Flags().StringP("userdata", "u", "", "plain text userdata you want to give this instance which the CLI will base64 encode")
- instanceCreate.Flags().BoolP("notify", "n", true, "notify when instance has been created | true or false")
- instanceCreate.Flags().BoolP("ddos", "d", false, "enable ddos protection | true or false")
- instanceCreate.Flags().StringP("reserved-ipv4", "", "", "ip address of the floating IP to use as the main IP for this instance")
- instanceCreate.Flags().StringP("host", "", "", "The hostname to assign to this instance")
- instanceCreate.Flags().StringP("tag", "t", "", "The tag to assign to this instance")
- instanceCreate.Flags().StringP("firewall-group", "", "", "The firewall group to assign to this instance")
-
- instanceList.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
- instanceList.Flags().IntP("per-page", "p", 100, "(optional) Number of items requested per page. Default is 100 and Max is 500.")
-
- instanceIPV4List.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
- instanceIPV4List.Flags().IntP("per-page", "p", 100, "(optional) Number of items requested per page. Default is 100 and Max is 500.")
-
- instanceIPV6List.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
- instanceIPV6List.Flags().IntP("per-page", "p", 100, "(optional) Number of items requested per page. Default is 100 and Max is 500.")
-
- // Sub commands for OS
- osCmd := &cobra.Command{
- Use: "operatingSystems",
- Short: "update operating system for an instance",
- Long: ``,
- }
-
- osCmd.AddCommand(osUpdate, osUpdateList)
- osUpdate.Flags().IntP("operatingSystems", "o", 0, "operating system ID you wish to use")
- osUpdate.MarkFlagRequired("operatingSystems")
- instanceCmd.AddCommand(osCmd)
-
- // Sub commands for App
- appCMD := &cobra.Command{
- Use: "app",
- Short: "update application for an instance",
- Long: ``,
- }
- appCMD.AddCommand(appUpdate, appUpdateList)
- appUpdate.Flags().IntP("app", "a", 0, "application ID you wish to use")
- appUpdate.MarkFlagRequired("app")
- instanceCmd.AddCommand(appCMD)
-
- // Sub commands for Backup
- backupCMD := &cobra.Command{
- Use: "backup",
- Short: "list and create backup schedules for an instance",
- Long: ``,
- }
- backupCMD.AddCommand(backupGet, backupCreate)
- backupCreate.Flags().StringP("type", "t", "", "type string Backup cron type. Can be one of 'daily', 'weekly', 'monthly', 'daily_alt_even', or 'daily_alt_odd'.")
- backupCreate.MarkFlagRequired("type")
- backupCreate.Flags().IntP("hour", "o", 0, "Hour value (0-23). Applicable to crons: 'daily', 'weekly', 'monthly', 'daily_alt_even', 'daily_alt_odd'")
- backupCreate.Flags().IntP("dow", "w", 0, "Day-of-week value (0-6). Applicable to crons: 'weekly'")
- backupCreate.Flags().IntP("dom", "m", 0, "Day-of-month value (1-28). Applicable to crons: 'monthly'")
- instanceCmd.AddCommand(backupCMD)
-
- // IPV4 Subcommands
- isoCmd := &cobra.Command{
- Use: "iso",
- Short: "attach/detach ISOs to a given instance",
- Long: ``,
- }
- isoCmd.AddCommand(isoStatus, isoAttach, isoDetach)
- isoAttach.Flags().StringP("iso-id", "i", "", "id of the ISO you wish to attach")
- isoAttach.MarkFlagRequired("iso-id")
- instanceCmd.AddCommand(isoCmd)
-
- ipv4Cmd := &cobra.Command{
- Use: "ipv4",
- Short: "list/create/delete ipv4 on instance",
- Long: ``,
- }
- ipv4Cmd.AddCommand(instanceIPV4List, createIpv4, deleteIpv4)
- createIpv4.Flags().Bool("reboot", false, "whether to reboot instance after adding ipv4 address")
- deleteIpv4.Flags().StringP("ipv4", "i", "", "ipv4 address you wish to delete")
- deleteIpv4.MarkFlagRequired("ipv4")
- instanceCmd.AddCommand(ipv4Cmd)
-
- // IPV6 Subcommands
- ipv6Cmd := &cobra.Command{
- Use: "ipv6",
- Short: "commands for ipv6 on instance",
- Long: ``,
- }
- ipv6Cmd.AddCommand(instanceIPV6List)
- instanceCmd.AddCommand(ipv6Cmd)
-
- // Plans SubCommands
- plansCmd := &cobra.Command{
- Use: "plan",
- Short: "update/list plans for an instance",
- Long: ``,
- }
- plansCmd.AddCommand(upgradePlan, upgradePlanList)
- upgradePlan.Flags().StringP("plan", "p", "", "plan id that you wish to upgrade to")
- upgradePlan.MarkFlagRequired("plan")
- instanceCmd.AddCommand(plansCmd)
-
- // ReverseDNS SubCommands
- reverseCmd := &cobra.Command{
- Use: "reverse-dns",
- Short: "commands to handle reverse-dns on an instance",
- Long: ``,
- }
- reverseCmd.AddCommand(defaultIpv4, listIpv6, deleteIpv6, setIpv4, setIpv6)
- defaultIpv4.Flags().StringP("ip", "i", "", "iPv4 address used in the reverse DNS update")
- defaultIpv4.MarkFlagRequired("ip")
- deleteIpv6.Flags().StringP("ip", "i", "", "ipv6 address you wish to delete")
-
- defaultIpv4.MarkFlagRequired("ip")
- setIpv4.Flags().StringP("ip", "i", "", "ip address you wish to set a reverse DNS on")
- setIpv4.Flags().StringP("entry", "e", "", "reverse dns entry")
- setIpv4.MarkFlagRequired("ip")
- setIpv4.MarkFlagRequired("entry")
-
- setIpv6.Flags().StringP("ip", "i", "", "ip address you wish to set a reverse DNS on")
- setIpv6.Flags().StringP("entry", "e", "", "reverse dns entry")
- setIpv6.MarkFlagRequired("ip")
- setIpv6.MarkFlagRequired("entry")
- instanceCmd.AddCommand(reverseCmd)
-
- userdataCmd := &cobra.Command{
- Use: "user-data",
- Short: "commands to handle userdata on an instance",
- Long: ``,
- }
- userdataCmd.AddCommand(setUserData, getUserData)
- setUserData.Flags().StringP("userdata", "d", "/dev/stdin", "file to read userdata from")
- instanceCmd.AddCommand(userdataCmd)
-
- return instanceCmd
-}
-
-var instanceStart = &cobra.Command{
- Use: "start ",
- Short: "starts an instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- if err := client.Instance.Start(context.Background(), id); err != nil {
- fmt.Printf("error starting instance : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Started up instance")
- },
-}
-
-var instanceStop = &cobra.Command{
- Use: "stop ",
- Short: "stops an instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- if err := client.Instance.Halt(context.Background(), id); err != nil {
- fmt.Printf("error stopping instance : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Stopped the instance")
- },
-}
-
-var instanceRestart = &cobra.Command{
- Use: "restart ",
- Short: "restart an instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- if err := client.Instance.Reboot(context.Background(), id); err != nil {
- fmt.Printf("error rebooting instance : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Rebooted instance")
- },
-}
-
-var instanceReinstall = &cobra.Command{
- Use: "reinstall ",
- Short: "reinstall an instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- if err := client.Instance.Reinstall(context.Background(), id); err != nil {
- fmt.Printf("error reinstalling instance : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Reinstalled instance")
- },
-}
-
-var instanceTag = &cobra.Command{
- Use: "tag ",
- Short: "add/modify tag on instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- tag, _ := cmd.Flags().GetString("tag")
- options := &govultr.InstanceUpdateReq{
- Tag: tag,
- }
-
- if err := client.Instance.Update(context.Background(), id, options); err != nil {
- fmt.Printf("error adding tag to instance : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Printf("Tagged instance with : %s\n", tag)
- },
-}
-
-var instanceDelete = &cobra.Command{
- Use: "delete ",
- Short: "delete/destroy an instance",
- Aliases: []string{"destroy"},
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- if err := client.Instance.Delete(context.Background(), id); err != nil {
- fmt.Printf("error deleting instance : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Deleted instance")
- },
-}
-
-var instanceLabel = &cobra.Command{
- Use: "label ",
- Short: "label an instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- label, _ := cmd.Flags().GetString("label")
- options := &govultr.InstanceUpdateReq{
- Label: label,
- }
-
- if err := client.Instance.Update(context.Background(), id, options); err != nil {
- fmt.Printf("error labeling instance : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Printf("Labeled instance with : %s\n", label)
- },
-}
-
-var instanceBandwidth = &cobra.Command{
- Use: "bandwidth ",
- Short: "bandwidth for instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- bw, err := client.Instance.GetBandwidth(context.Background(), id)
- if err != nil {
- fmt.Printf("error getting bandwidth for instance : %v\n", err)
- os.Exit(1)
- }
-
- printer.InstanceBandwidth(bw)
- },
-}
-
-var instanceIPV4List = &cobra.Command{
- Use: "list ",
- Aliases: []string{"v4"},
- Short: "list ipv4 for an instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- options := getPaging(cmd)
- v4, meta, err := client.Instance.ListIPv4(context.Background(), id, options)
- if err != nil {
- fmt.Printf("error getting ipv4 info : %v\n", err)
- os.Exit(1)
- }
-
- printer.InstanceIPV4(v4, meta)
- },
-}
-
-var instanceIPV6List = &cobra.Command{
- Use: "list ",
- Aliases: []string{"v6"},
- Short: "list ipv6 for an instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- options := getPaging(cmd)
- v6, meta, err := client.Instance.ListIPv6(context.TODO(), id, options)
- if err != nil {
- fmt.Printf("error getting ipv6 info : %v\n", err)
- os.Exit(1)
- }
-
- printer.InstanceIPV6(v6, meta)
- },
-}
-
-var instanceList = &cobra.Command{
- Use: "list",
- Aliases: []string{"l"},
- Short: "list all available instances",
- Long: ``,
- Run: func(cmd *cobra.Command, args []string) {
- options := getPaging(cmd)
- s, meta, err := client.Instance.List(context.TODO(), options)
- if err != nil {
- fmt.Printf("error getting list of instances : %v\n", err)
- os.Exit(1)
- }
-
- printer.InstanceList(s, meta)
- },
-}
-
-var instanceInfo = &cobra.Command{
- Use: "get ",
- Short: "get info about a specific instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- s, err := client.Instance.Get(context.TODO(), id)
- if err != nil {
- fmt.Printf("error getting instance : %v\n", err)
- os.Exit(1)
- }
-
- printer.Instance(s)
- },
-}
-
-var updateFwgGroup = &cobra.Command{
- Use: "update-firewall-group",
- Short: "assign a firewall group to instance",
- Long: ``,
- Run: func(cmd *cobra.Command, args []string) {
- id, _ := cmd.Flags().GetString("instance-id")
- fwgID, _ := cmd.Flags().GetString("firewall-group-id")
-
- options := &govultr.InstanceUpdateReq{
- FirewallGroupID: fwgID,
- }
-
- if err := client.Instance.Update(context.TODO(), id, options); err != nil {
- fmt.Printf("error setting firewall group : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Updated firewall group")
- },
-}
-
-var osUpdate = &cobra.Command{
- Use: "change ",
- Short: "changes operating system",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- osID, _ := cmd.Flags().GetInt("operatingSystems")
-
- options := &govultr.InstanceUpdateReq{
- OsID: osID,
- }
-
- if err := client.Instance.Update(context.TODO(), id, options); err != nil {
- fmt.Printf("error updating operatingSystems : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Updated OS")
- },
-}
-
-var osUpdateList = &cobra.Command{
- Use: "list ",
- Short: "available operating systems an instance can change to.",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- list, err := client.Instance.GetUpgrades(context.TODO(), id)
-
- if err != nil {
- fmt.Printf("error listing available operatingSystems : %v\n", err)
- os.Exit(1)
- }
-
- printer.OsList(list.OS)
- },
-}
-
-var appUpdate = &cobra.Command{
- Use: "change ",
- Short: "changes application",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- appID, _ := cmd.Flags().GetInt("app")
-
- options := &govultr.InstanceUpdateReq{
- AppID: appID,
- }
-
- if err := client.Instance.Update(context.TODO(), id, options); err != nil {
- fmt.Printf("error updating application : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Updated Application")
- },
-}
-
-var appUpdateList = &cobra.Command{
- Use: "list ",
- Short: "available apps an instance can change to.",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- list, err := client.Instance.GetUpgrades(context.TODO(), id)
-
- if err != nil {
- fmt.Printf("error listing available applications : %v\n", err)
- os.Exit(1)
- }
-
- printer.AppList(list.Applications)
- },
-}
-
-var backupGet = &cobra.Command{
- Use: "get ",
- Short: "get backup schedules on a given instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- info, err := client.Instance.GetBackupSchedule(context.TODO(), id)
- if err != nil {
- fmt.Printf("error getting application info : %v\n", err)
- os.Exit(1)
- }
-
- printer.BackupsGet(info)
- },
-}
-
-var backupCreate = &cobra.Command{
- Use: "create ",
- Short: "create backup schedule on a given instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
-
- crontType, _ := cmd.Flags().GetString("type")
- hour, _ := cmd.Flags().GetInt("hour")
- dow, _ := cmd.Flags().GetInt("dow")
- dom, _ := cmd.Flags().GetInt("dom")
-
- backup := &govultr.BackupScheduleReq{
- Type: crontType,
- Hour: hour,
- Dow: dow,
- Dom: dom,
- }
-
- if err := client.Instance.SetBackupSchedule(context.TODO(), id, backup); err != nil {
- fmt.Printf("error creating backup schedule : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Created backup schedule")
- },
-}
-
-var isoStatus = &cobra.Command{
- Use: "status ",
- Short: "current ISO state",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- info, err := client.Instance.ISOStatus(context.TODO(), id)
- if err != nil {
- fmt.Printf("error getting iso state info : %v\n", err)
- os.Exit(1)
- }
-
- printer.IsoStatus(info)
- },
-}
-
-var isoAttach = &cobra.Command{
- Use: "attach ",
- Short: "attach ISO to instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- iso, _ := cmd.Flags().GetString("iso-id")
- if err := client.Instance.AttachISO(context.TODO(), id, iso); err != nil {
- fmt.Printf("error attaching iso : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("ISO has been attached")
- },
-}
-
-var isoDetach = &cobra.Command{
- Use: "detach ",
- Short: "detach ISO from instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- if err := client.Instance.DetachISO(context.TODO(), id); err != nil {
- fmt.Printf("error detaching iso : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("ISO has been detached")
- },
-}
-
-var instanceRestore = &cobra.Command{
- Use: "restore ",
- Short: "restore instance from backup/snapshot",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
-
- backup, _ := cmd.Flags().GetString("backup")
- snapshot, _ := cmd.Flags().GetString("snapshot")
- options := &govultr.RestoreReq{}
-
- if backup == "" && snapshot == "" {
- fmt.Println("at least one flag must be provided (snapshot or backup)")
- os.Exit(1)
- } else if backup != "" && snapshot != "" {
- fmt.Println("one flag must be provided not both (snapshot or backup)")
- os.Exit(1)
- }
-
- if snapshot != "" {
- options.SnapshotID = snapshot
- } else {
- options.BackupID = backup
- }
-
- if err := client.Instance.Restore(context.TODO(), id, options); err != nil {
- fmt.Printf("error restoring instance : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Instance has been restored")
- },
-}
-
-var createIpv4 = &cobra.Command{
- Use: "create ",
- Short: "create ipv4 for instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- reboot, _ := cmd.Flags().GetBool("reboot")
-
- _, err := client.Instance.CreateIPv4(context.TODO(), id, govultr.BoolToBoolPtr(reboot))
- if err != nil {
- fmt.Printf("error creating ipv4 : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("IPV4 has been created")
- },
-}
-
-var deleteIpv4 = &cobra.Command{
- Use: "delete ",
- Short: "delete ipv4 for instance",
- Aliases: []string{"destroy"},
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- ip, _ := cmd.Flags().GetString("ipv4")
-
- if err := client.Instance.DeleteIPv4(context.TODO(), id, ip); err != nil {
- fmt.Printf("error deleting ipv4 : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("IPV4 has been deleted")
- },
-}
-
-var upgradePlan = &cobra.Command{
- Use: "upgrade ",
- Short: "upgrade plan for instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- plan, _ := cmd.Flags().GetString("plan")
-
- options := &govultr.InstanceUpdateReq{
- Plan: plan,
- }
-
- if err := client.Instance.Update(context.TODO(), id, options); err != nil {
- fmt.Printf("error upgrading plans : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Upgraded plan")
- },
-}
-
-var upgradePlanList = &cobra.Command{
- Use: "list ",
- Short: "available plans an instance can upgrade to.",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- list, err := client.Instance.GetUpgrades(context.TODO(), id)
-
- if err != nil {
- fmt.Printf("error listing available plans : %v\n", err)
- os.Exit(1)
- }
-
- printer.PlansList(list.Plans)
- },
-}
-
-var defaultIpv4 = &cobra.Command{
- Use: "default-ipv4 ",
- Short: "Set a reverse DNS entry for an IPv4 address of an instance to the original setting",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- ip, _ := cmd.Flags().GetString("ip")
-
- if err := client.Instance.DefaultReverseIPv4(context.TODO(), id, ip); err != nil {
- fmt.Printf("error setting default reverse dns : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Set default reserve dns")
- },
-}
-
-var listIpv6 = &cobra.Command{
- Use: "list-ipv6 ",
- Short: "List the IPv6 reverse DNS entries for an instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- rip, err := client.Instance.ListReverseIPv6(context.TODO(), id)
- if err != nil {
- fmt.Printf("error getting the reverse ipv6 list: %v\n", err)
- os.Exit(1)
- }
- printer.ReverseIpv6(rip)
- },
-}
-
-var deleteIpv6 = &cobra.Command{
- Use: "delete-ipv6 ",
- Short: "Remove a reverse DNS entry for an IPv6 address for an instance",
- Aliases: []string{"destroy-ipv6"},
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- ip, _ := cmd.Flags().GetString("ip")
- if err := client.Instance.DeleteReverseIPv6(context.TODO(), id, ip); err != nil {
- fmt.Printf("error deleting reverse ipv6 entry : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Deleted reverse DNS IPV6 entry")
- },
-}
-
-var setIpv4 = &cobra.Command{
- Use: "set-ipv4 ",
- Short: "Set a reverse DNS entry for an IPv4 address for an instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- ip, _ := cmd.Flags().GetString("ip")
- entry, _ := cmd.Flags().GetString("entry")
-
- options := &govultr.ReverseIP{
- IP: ip,
- Reverse: entry,
- }
-
- if err := client.Instance.CreateReverseIPv4(context.TODO(), id, options); err != nil {
- fmt.Printf("error setting reverse dns ipv4 entry : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Set reverse DNS entry for ipv4 address")
- },
-}
-
-var setIpv6 = &cobra.Command{
- Use: "set-ipv6 ",
- Short: "Set a reverse DNS entry for an IPv6 address for an instance",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- ip, _ := cmd.Flags().GetString("ip")
- entry, _ := cmd.Flags().GetString("entry")
-
- options := &govultr.ReverseIP{
- IP: ip,
- Reverse: entry,
- }
-
- if err := client.Instance.CreateReverseIPv6(context.TODO(), id, options); err != nil {
- fmt.Printf("error setting reverse dns ipv6 entry : %v\n", err)
- os.Exit(1)
- }
- fmt.Println("Set reverse DNS entry for ipv6 address")
- },
-}
-
-var instanceCreate = &cobra.Command{
- Use: "create",
- Short: "Create an instance",
- Long: ``,
- Run: func(cmd *cobra.Command, args []string) {
- region, _ := cmd.Flags().GetString("region")
- plan, _ := cmd.Flags().GetString("plan")
- osID, _ := cmd.Flags().GetInt("operatingSystems")
-
- // Optional
- ipxe, _ := cmd.Flags().GetString("ipxe")
- iso, _ := cmd.Flags().GetString("iso")
- snapshot, _ := cmd.Flags().GetString("snapshot")
- script, _ := cmd.Flags().GetString("script-id")
- ipv6, _ := cmd.Flags().GetBool("ipv6")
- privateNetwork, _ := cmd.Flags().GetBool("private-network")
- networks, _ := cmd.Flags().GetStringArray("network")
- label, _ := cmd.Flags().GetString("label")
- ssh, _ := cmd.Flags().GetStringArray("ssh-keys")
- backup, _ := cmd.Flags().GetBool("auto-backup")
- app, _ := cmd.Flags().GetInt("app")
- userData, _ := cmd.Flags().GetString("userdata")
- notify, _ := cmd.Flags().GetBool("notify")
- ddos, _ := cmd.Flags().GetBool("ddos")
- ipv4, _ := cmd.Flags().GetString("reserved-ipv4")
- host, _ := cmd.Flags().GetString("host")
- tag, _ := cmd.Flags().GetString("tag")
- fwg, _ := cmd.Flags().GetString("firewall-group")
-
- osOptions := map[string]interface{}{"iso_id": iso, "os_id": osID, "app_id": app, "snapshot_id": snapshot}
-
- if iso != "" {
- osOptions["iso_id"] = iso
- }
-
- osOption, err := optionCheck(osOptions)
- if err != nil {
- fmt.Printf("error creating instance : %v\n", err)
- os.Exit(1)
- }
-
- opt := &govultr.InstanceCreateReq{
- Plan: plan,
- Region: region,
- IPXEChainURL: ipxe,
- ISOID: iso,
- SnapshotID: snapshot,
- ScriptID: script,
- AttachPrivateNetwork: networks,
- Label: label,
- SSHKeys: ssh,
- AppID: app,
- UserData: userData,
- ReservedIPv4: ipv4,
- Hostname: host,
- Tag: tag,
- FirewallGroupID: fwg,
- EnableIPv6: govultr.BoolToBoolPtr(false),
- DDOSProtection: govultr.BoolToBoolPtr(false),
- ActivationEmail: govultr.BoolToBoolPtr(false),
- Backups: "disabled",
- EnablePrivateNetwork: govultr.BoolToBoolPtr(false),
- }
-
- // If no osOptions were selected and osID has a real value then set the osOptions to os_id
- if osOption == "os_id" && osID != 0 {
- opt.OsID = osID
- } else if osOption == "" && osID == 0 {
- fmt.Printf("error creating instance: an os_id, snapshot_id, iso_id, or app_id must be provided\n")
- os.Exit(1)
- }
-
- if ipv6 {
- opt.EnableIPv6 = govultr.BoolToBoolPtr(true)
- }
- if ddos {
- opt.DDOSProtection = govultr.BoolToBoolPtr(true)
- }
- if notify {
- opt.ActivationEmail = govultr.BoolToBoolPtr(true)
- }
- if backup {
- opt.Backups = "enabled"
- }
- if privateNetwork {
- opt.EnablePrivateNetwork = govultr.BoolToBoolPtr(true)
- }
-
- if userData != "" {
- opt.UserData = base64.StdEncoding.EncodeToString([]byte(userData))
- }
-
- //region, plan, osOpt, opt
- instance, err := client.Instance.Create(context.TODO(), opt)
- if err != nil {
- fmt.Printf("error creating instance : %v\n", err)
- os.Exit(1)
- }
-
- printer.Instance(instance)
- },
-}
-
-var setUserData = &cobra.Command{
- Use: "set ",
- Short: "Set the plain text user-data of an instance",
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- userData, _ := cmd.Flags().GetString("userdata")
-
- rawData, err := ioutil.ReadFile(userData)
- if err != nil {
- fmt.Printf("error reading user-data : %v\n", err)
- os.Exit(1)
- }
-
- options := &govultr.InstanceUpdateReq{
- UserData: base64.StdEncoding.EncodeToString(rawData),
- }
-
- if err = client.Instance.Update(context.TODO(), args[0], options); err != nil {
- fmt.Printf("error setting user-data : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("Set user-data for instance")
- },
-}
-
-var getUserData = &cobra.Command{
- Use: "get ",
- Short: "Get the user-data of an instance",
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an instanceID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- userData, err := client.Instance.GetUserData(context.TODO(), args[0])
- if err != nil {
- fmt.Printf("error getting user-data : %v\n", err)
- os.Exit(1)
- }
-
- printer.UserData(userData)
- },
-}
-
-func optionCheck(options map[string]interface{}) (string, error) {
- var result []string
- for k, v := range options {
- switch v.(type) {
- case int:
- if v != 0 {
- result = append(result, k)
- }
- case string:
- if v != "" {
- result = append(result, k)
- }
- }
- }
-
- if len(result) > 1 {
- return "", fmt.Errorf("too many options have been selected : %v : please select one", result)
- }
-
- // Return back an empty slice so we can possibly add in osID
- if len(result) == 0 {
- return "", nil
- }
-
- return result[0], nil
-}
diff --git a/cmd/instance/instance.go b/cmd/instance/instance.go
new file mode 100644
index 00000000..e06fff9f
--- /dev/null
+++ b/cmd/instance/instance.go
@@ -0,0 +1,1777 @@
+// Package instance provides the command for the CLI to control instances
+package instance
+
+import (
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "github.com/spf13/cobra"
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/ip"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/userdata"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+ "github.com/vultr/vultr-cli/v3/pkg/cli"
+)
+
+var (
+ long = `Get commands available to instance`
+ example = `
+ # Full example
+ vultr-cli instance
+ `
+ listLong = ``
+ listExample = ``
+ getLong = ``
+ getExample = ``
+ createLong = `Create a new instance with specified plan, region and os (from image, snapshot, app or ISO)`
+ createExample = `
+ # Full example
+ vultr-cli instance create --region="ewr" --plan="vc2-2c-4gb" --os=1743
+
+ You must pass one of these in addition to the required --region and --plan flags:
+ --os
+ --snapshot
+ --iso
+ --app
+ --image
+
+ # Shortened example with aliases
+ vultr-cli instance c -r="ewr" -p="vc2-2c-4gb" -o=1743
+
+ # Full example with attached VPCs
+ vultr-cli instance create --region="ewr" --plan="vc2-2c-4gb" --os=1743 \
+ --vpc-ids="08422775-5be0-4371-afba-64b03f9ad22d,13a45caa-9c06-4b5d-8f76-f5281ab172b7"
+
+ # Full example with assigned ssh keys
+ vultr-cli instance create --region="ewr" --plan="vc2-2c-4gb" --os=1743 \
+ --ssh-keys="a14b6539-5583-41e8-a035-c07a76897f2b,be624232-56c7-4d5c-bf87-9bdaae7a1fbd"
+ `
+ deleteLong = ``
+ deleteExample = ``
+ tagsLong = `Modify the tags of the specified instance`
+ tagsExample = `
+ # Full example
+ vultr-cli instance tags --tags="example-tag-1,example-tag-2"
+
+ # Shortened example with aliases
+ vultr-cli instance tags -t="example-tag-1,example-tag-2"
+ `
+
+ userDataSetLong = ``
+ userDataSetExample = ``
+ userDataGetLong = ``
+ userDataGetExample = ``
+ vpcAttachLong = `Attaches an existing VPC to the specified instance`
+ vpcAttachExample = `
+ # Full example
+ vultr-cli instance vpc attach --vpc-id="2126b7d9-5e2a-491e-8840-838aa6b5f294"
+ `
+ vpcDetachLong = `Detaches an existing VPC from the specified instance`
+ vpcDetachExample = `
+ # Full example
+ vultr-cli instance vpc detach --vpc-id="2126b7d9-5e2a-491e-8840-838aa6b5f294"
+ `
+
+ vpc2AttachLong = `Attaches an existing VPC 2.0 network to the specified instance`
+ vpc2AttachExample = `
+ # Full example
+ vultr-cli instance vpc2 attach --vpc-id="2126b7d9-5e2a-491e-8840-838aa6b5f294"
+ `
+ vpc2DetachLong = `Detaches an existing VPC 2.0 network from the specified instance`
+ vpc2DetachExample = `
+ # Full example
+ vultr-cli instance vpc2 detach --vpc-id="2126b7d9-5e2a-491e-8840-838aa6b5f294"
+ `
+)
+
+// NewCmdInstance ...
+func NewCmdInstance(base *cli.Base) *cobra.Command { //nolint:funlen,gocyclo
+ o := &options{Base: base}
+
+ cmd := &cobra.Command{
+ Use: "instance",
+ Short: "commands to interact with instances on vultr",
+ Long: long,
+ Example: example,
+ PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+ utils.SetOptions(o.Base, cmd, args)
+ if !o.Base.HasAuth {
+ return errors.New(utils.APIKeyError)
+ }
+ return nil
+ },
+ }
+
+ // List
+ list := &cobra.Command{
+ Use: "list",
+ Aliases: []string{"l"},
+ Short: "List all instances",
+ Long: listLong,
+ Example: listExample,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ o.Base.Options = utils.GetPaging(cmd)
+
+ instances, meta, err := o.list()
+ if err != nil {
+ return fmt.Errorf("error getting instance list : %v", err)
+ }
+
+ data := &InstancesPrinter{Instances: instances, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ list.Flags().StringP("cursor", "c", "", "(optional) cursor for paging.")
+ list.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ fmt.Sprintf("(optional) Number of items requested per page. Default is %d and Max is 500.", utils.PerPageDefault),
+ )
+
+ // Get
+ get := &cobra.Command{
+ Use: "get ",
+ Short: "Get info on an instance",
+ Long: getLong,
+ Example: getExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ instance, err := o.get()
+ if err != nil {
+ return fmt.Errorf("error getting instance : %v", err)
+ }
+
+ data := &InstancePrinter{Instance: instance}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Create
+ create := &cobra.Command{
+ Use: "create",
+ Short: "Create an instance",
+ Aliases: []string{"c"},
+ Long: createLong,
+ Example: createExample,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ region, errRe := cmd.Flags().GetString("region")
+ if errRe != nil {
+ return fmt.Errorf("error parsing flag 'region' for instance create : %v", errRe)
+ }
+
+ plan, errPl := cmd.Flags().GetString("plan")
+ if errPl != nil {
+ return fmt.Errorf("error parsing flag 'plan' for instance create : %v", errPl)
+ }
+
+ osID, errOs := cmd.Flags().GetInt("os")
+ if errOs != nil {
+ return fmt.Errorf("error parsing flag 'os' for instance create : %v", errOs)
+ }
+
+ ipxe, errIP := cmd.Flags().GetString("ipxe")
+ if errIP != nil {
+ return fmt.Errorf("error parsing flag 'ipxe' for instance create : %v", errIP)
+ }
+
+ iso, errIs := cmd.Flags().GetString("iso")
+ if errIs != nil {
+ return fmt.Errorf("error parsing flag 'iso' for instance create : %v", errIs)
+ }
+
+ snapshot, errSn := cmd.Flags().GetString("snapshot")
+ if errSn != nil {
+ return fmt.Errorf("error parsing flag 'snapshot' for instance create : %v", errSn)
+ }
+
+ script, errSc := cmd.Flags().GetString("script-id")
+ if errSc != nil {
+ return fmt.Errorf("error parsing flag 'script' for instance create : %v", errSc)
+ }
+
+ ipv6, errIv := cmd.Flags().GetBool("ipv6")
+ if errIv != nil {
+ return fmt.Errorf("error parsing flag 'ipv6' for instance create : %v", errIv)
+ }
+
+ vpcEnable, errVp := cmd.Flags().GetBool("vpc-enable")
+ if errVp != nil {
+ return fmt.Errorf("error parsing flag 'vpc-enable' for instance create : %v", errVp)
+ }
+
+ vpcAttach, errVp := cmd.Flags().GetStringSlice("vpc-ids")
+ if errVp != nil {
+ return fmt.Errorf("error parsing flag 'vpc-ids' for instance create : %v", errVp)
+ }
+
+ label, errLa := cmd.Flags().GetString("label")
+ if errLa != nil {
+ return fmt.Errorf("error parsing flag 'label' for instance create : %v", errLa)
+ }
+
+ ssh, errSs := cmd.Flags().GetStringSlice("ssh-keys")
+ if errSs != nil {
+ return fmt.Errorf("error parsing flag 'ssh-keys' for instance create : %v", errSs)
+ }
+
+ backup, errBa := cmd.Flags().GetBool("auto-backup")
+ if errBa != nil {
+ return fmt.Errorf("error parsing flag 'auto-backup' for instance create : %v", errBa)
+ }
+
+ app, errAp := cmd.Flags().GetInt("app")
+ if errAp != nil {
+ return fmt.Errorf("error parsing flag 'app' for instance create : %v", errAp)
+ }
+
+ image, errIm := cmd.Flags().GetString("image")
+ if errIm != nil {
+ return fmt.Errorf("error parsing flag 'image' for instance create : %v", errIm)
+ }
+
+ userData, errUs := cmd.Flags().GetString("userdata")
+ if errUs != nil {
+ return fmt.Errorf("error parsing flag 'userData' for instance create : %v", errUs)
+ }
+
+ notify, errNo := cmd.Flags().GetBool("notify")
+ if errNo != nil {
+ return fmt.Errorf("error parsing flag 'notify' for instance create : %v", errNo)
+ }
+
+ ddos, errDd := cmd.Flags().GetBool("ddos")
+ if errDd != nil {
+ return fmt.Errorf("error parsing flag 'ddos' for instance create : %v", errDd)
+ }
+
+ ipv4, errIi := cmd.Flags().GetString("reserved-ipv4")
+ if errIi != nil {
+ return fmt.Errorf("error parsing flag 'reserved-ipv4' for instance create : %v", errIi)
+ }
+
+ host, errHo := cmd.Flags().GetString("host")
+ if errHo != nil {
+ return fmt.Errorf("error parsing flag 'host' for instance create : %v", errHo)
+ }
+
+ tags, errTa := cmd.Flags().GetStringSlice("tags")
+ if errTa != nil {
+ return fmt.Errorf("error parsing flag 'tags' for instance create : %v", errTa)
+ }
+
+ fwg, errFw := cmd.Flags().GetString("firewall-group")
+ if errFw != nil {
+ return fmt.Errorf("error parsing flag 'firewall-group' for instance create : %v", errFw)
+ }
+
+ o.CreateReq = &govultr.InstanceCreateReq{
+ Plan: plan,
+ Region: region,
+ OsID: osID,
+ ISOID: iso,
+ SnapshotID: snapshot,
+ AppID: app,
+ ImageID: image,
+ IPXEChainURL: ipxe,
+ ScriptID: script,
+ Label: label,
+ SSHKeys: ssh,
+ UserData: userData,
+ ReservedIPv4: ipv4,
+ Hostname: host,
+ Tags: tags,
+ FirewallGroupID: fwg,
+ EnableIPv6: govultr.BoolToBoolPtr(ipv6),
+ DDOSProtection: govultr.BoolToBoolPtr(ddos),
+ ActivationEmail: govultr.BoolToBoolPtr(notify),
+ Backups: "disabled",
+ EnableVPC: govultr.BoolToBoolPtr(vpcEnable),
+ AttachVPC: vpcAttach,
+ }
+
+ if backup {
+ o.CreateReq.Backups = "enabled"
+ }
+
+ if userData != "" {
+ o.CreateReq.UserData = base64.StdEncoding.EncodeToString([]byte(userData))
+ }
+
+ instance, err := o.create()
+ if err != nil {
+ return fmt.Errorf("error creating instance : %v", err)
+ }
+
+ data := &InstancePrinter{Instance: instance}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ create.Flags().StringP("region", "r", "", "The ID of the region in which to create the instance")
+ if err := create.MarkFlagRequired("region"); err != nil {
+ fmt.Printf("error marking instance create 'region' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ create.Flags().StringP("plan", "p", "", "The plan ID with which to create the instance")
+ if err := create.MarkFlagRequired("plan"); err != nil {
+ fmt.Printf("error marking instance create 'plan' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ create.Flags().IntP("os", "", 0, "os id you wish the instance to have")
+ create.Flags().StringP("iso", "", "", "iso ID you want to create the instance with")
+ create.Flags().StringP("snapshot", "", "", "snapshot ID you want to create the instance with")
+ create.Flags().IntP("app", "a", 0, "application ID you want this instance to have")
+ create.Flags().StringP("image", "", "", "image ID of the application that will be installed on the server.")
+ create.MarkFlagsMutuallyExclusive("os", "iso", "snapshot", "app", "image")
+ create.MarkFlagsOneRequired("os", "iso", "snapshot", "app", "image")
+
+ create.Flags().StringP(
+ "ipxe",
+ "",
+ "",
+ "if you've selected the 'custom' operating system, this can be set to chainload the specified URL on bootup",
+ )
+ create.Flags().StringP("script-id", "", "", "script id of the startup script")
+ create.Flags().BoolP("ipv6", "", false, "enable ipv6 | true or false")
+ create.Flags().BoolP("vpc-enable", "", false, "enable VPC | true or false")
+ create.Flags().StringSliceP("vpc-ids", "", []string{}, "VPC IDs you want to assign to the instance")
+ create.Flags().StringP("label", "l", "", "label you want to give this instance")
+ create.Flags().StringSliceP("ssh-keys", "s", []string{}, "ssh keys you want to assign to the instance")
+ create.Flags().BoolP("auto-backup", "b", false, "enable auto backups | true or false")
+ create.Flags().StringP("userdata", "u", "", "plain text userdata you want to give this instance which the CLI will base64 encode")
+ create.Flags().BoolP("notify", "n", false, "notify when instance has been created | true or false")
+ create.Flags().BoolP("ddos", "d", false, "enable ddos protection | true or false")
+ create.Flags().StringP("reserved-ipv4", "", "", "ID of the floating IP to use as the main IP for this instance")
+ create.Flags().StringP("host", "", "", "The hostname to assign to this instance")
+ create.Flags().StringSliceP("tags", "", []string{}, "A comma-separated list of tags to assign to this instance")
+ create.Flags().StringP("firewall-group", "", "", "The firewall group to assign to this instance")
+
+ // Update
+ // update := &cobra.Command{}
+
+ // Delete
+ del := &cobra.Command{
+ Use: "delete ",
+ Short: "Delete an instance",
+ Aliases: []string{"destroy"},
+ Long: deleteLong,
+ Example: deleteExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.del(); err != nil {
+ return fmt.Errorf("error deleting instance : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Instance has been deleted"), nil)
+
+ return nil
+ },
+ }
+
+ // Label
+ label := &cobra.Command{
+ Use: "label ",
+ Short: "Label an instance",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ label, errLa := cmd.Flags().GetString("label")
+ if errLa != nil {
+ return fmt.Errorf("error parsing flag 'label' for instance update : %v", errLa)
+ }
+
+ o.UpdateReq = &govultr.InstanceUpdateReq{
+ Label: label,
+ }
+
+ instance, err := o.update()
+ if err != nil {
+ return fmt.Errorf("error updating instance label : %v", err)
+ }
+
+ data := &InstancePrinter{Instance: instance}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ label.Flags().StringP("label", "l", "", "The label you want to set on an instance")
+ if err := label.MarkFlagRequired("label"); err != nil {
+ fmt.Printf("error marking instance label 'label' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ // Tags
+ tags := &cobra.Command{
+ Use: "tags ",
+ Short: "Update tags on an instance",
+ Long: tagsLong,
+ Example: tagsExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ tags, errTa := cmd.Flags().GetStringSlice("tags")
+ if errTa != nil {
+ return fmt.Errorf("error parsing flag 'tags' for instance update : %v", errTa)
+ }
+
+ o.UpdateReq = &govultr.InstanceUpdateReq{
+ Tags: tags,
+ }
+
+ instance, err := o.update()
+ if err != nil {
+ return fmt.Errorf("error updating instance tags : %v", err)
+ }
+
+ data := &InstancePrinter{Instance: instance}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ tags.Flags().StringSliceP("tags", "t", []string{}, "A comma separated list of tags to apply to the instance")
+ if err := tags.MarkFlagRequired("tags"); err != nil {
+ fmt.Printf("error marking instance tags 'tags' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ // User Data
+ userData := &cobra.Command{
+ Use: "user-data",
+ Short: "Commands to handle user data on an instance",
+ }
+
+ // User Data Get
+ userDataGet := &cobra.Command{
+ Use: "get ",
+ Short: "Get the user data on an instance",
+ Long: userDataGetLong,
+ Example: userDataGetExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ ud, err := o.userData()
+ if err != nil {
+ return fmt.Errorf("error getting instance user data : %v", err)
+ }
+
+ data := &userdata.UserDataPrinter{UserData: *ud}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // User Data Set
+ userDataSet := &cobra.Command{
+ Use: "set ",
+ Short: "Update user-data on an instance",
+ Long: userDataSetLong,
+ Example: userDataSetExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ userDataPath, errPa := cmd.Flags().GetString("userdata")
+ if errPa != nil {
+ return fmt.Errorf("error parsing flag 'userdata' for instance update : %v", errPa)
+ }
+
+ userDataPath = filepath.Clean(userDataPath)
+
+ rawData, errRe := os.ReadFile(userDataPath)
+ if errRe != nil {
+ return fmt.Errorf("error reading user-data : %v", errRe)
+ }
+
+ o.UpdateReq = &govultr.InstanceUpdateReq{
+ UserData: base64.StdEncoding.EncodeToString(rawData),
+ }
+
+ _, err := o.update()
+ if err != nil {
+ return fmt.Errorf("error updating instance user data : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Instance user data has been updated"), nil)
+
+ return nil
+ },
+ }
+
+ userDataSet.Flags().StringP("userdata", "d", "/dev/stdin", "The file to read userdata from")
+
+ userData.AddCommand(
+ userDataGet,
+ userDataSet,
+ )
+
+ // Start
+ start := &cobra.Command{
+ Use: "start ",
+ Short: "Start an instance",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.start(); err != nil {
+ return fmt.Errorf("error starting instance : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Instance started"), nil)
+
+ return nil
+ },
+ }
+
+ // Stop
+ stop := &cobra.Command{
+ Use: "stop ",
+ Short: "Stop an instance",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.stop(); err != nil {
+ return fmt.Errorf("error stopping instance : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Instance stopped"), nil)
+
+ return nil
+ },
+ }
+
+ // Restart
+ restart := &cobra.Command{
+ Use: "restart ",
+ Short: "Restart an instance",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.restart(); err != nil {
+ return fmt.Errorf("error restarting instance : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Instance restarted"), nil)
+
+ return nil
+ },
+ }
+
+ // ISO
+ iso := &cobra.Command{
+ Use: "iso",
+ Short: "Manage ISOs on an instance",
+ }
+
+ // ISO Status
+ isoStatus := &cobra.Command{
+ Use: "status ",
+ Short: "Get ISO status",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ iso, err := o.isoStatus()
+ if err != nil {
+ return fmt.Errorf("error getting instance iso status : %v", err)
+ }
+
+ data := &ISOPrinter{ISO: *iso}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // ISO Attach
+ isoAttach := &cobra.Command{
+ Use: "attach ",
+ Short: "Attach ISO to an instance",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ iso, errIs := cmd.Flags().GetString("iso-id")
+ if errIs != nil {
+ return fmt.Errorf("error parsing flag 'iso' for instance iso attach: %v", errIs)
+ }
+
+ o.ISOAttachID = iso
+
+ if err := o.isoAttach(); err != nil {
+ return fmt.Errorf("error attaching iso to instance : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("ISO attached to instance"), nil)
+
+ return nil
+ },
+ }
+
+ isoAttach.Flags().StringP("iso-id", "i", "", "id of the ISO you wish to attach")
+ if err := isoAttach.MarkFlagRequired("iso-id"); err != nil {
+ fmt.Printf("error marking instance iso attach 'iso-id' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ iso.AddCommand(
+ isoStatus,
+ isoAttach,
+ )
+
+ // Backup
+ backup := &cobra.Command{
+ Use: "backup",
+ Short: "List and create backup schedules for an instance",
+ }
+
+ // Backup Get
+ backupGet := &cobra.Command{
+ Use: "get ",
+ Short: "Get the backup schedule for an instance",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ bk, err := o.backups()
+ if err != nil {
+ return fmt.Errorf("error getting instance backups : %v", err)
+ }
+
+ data := &BackupPrinter{Backup: *bk}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Backup Create
+ backupCreate := &cobra.Command{
+ Use: "create ",
+ Short: "Create a backup schedule for an instance",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ crontType, errCr := cmd.Flags().GetString("type")
+ if errCr != nil {
+ return fmt.Errorf("error parsing flag 'crontType' for instance backup create : %v", errCr)
+ }
+
+ hour, errHo := cmd.Flags().GetInt("hour")
+ if errHo != nil {
+ return fmt.Errorf("error parsing flag 'hour' for instance backup create : %v", errHo)
+ }
+
+ dow, errDo := cmd.Flags().GetInt("dow")
+ if errDo != nil {
+ return fmt.Errorf("error parsing flag 'dow' for instance backup create : %v", errDo)
+ }
+
+ dom, errDo := cmd.Flags().GetInt("dom")
+ if errDo != nil {
+ return fmt.Errorf("error parsing flag 'dom' for instance backup create : %v", errDo)
+ }
+
+ o.BackupCreateReq = &govultr.BackupScheduleReq{
+ Type: crontType,
+ Hour: govultr.IntToIntPtr(hour),
+ Dow: govultr.IntToIntPtr(dow),
+ Dom: dom,
+ }
+
+ if err := o.backupCreate(); err != nil {
+ return fmt.Errorf("error getting instance backups : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Instance backup created"), nil)
+
+ return nil
+ },
+ }
+
+ backupCreate.Flags().StringP(
+ "type",
+ "t",
+ "",
+ "type string Backup cron type. Can be one of 'daily', 'weekly', 'monthly', 'daily_alt_even', or 'daily_alt_odd'.",
+ )
+ if err := backupCreate.MarkFlagRequired("type"); err != nil {
+ fmt.Printf("error marking instance backup create 'type' flag required: %v", err)
+ os.Exit(1)
+ }
+ backupCreate.Flags().IntP(
+ "hour",
+ "",
+ 0,
+ "Hour value (0-23). Applicable to crons: 'daily', 'weekly', 'monthly', 'daily_alt_even', 'daily_alt_odd'",
+ )
+ backupCreate.Flags().IntP("dow", "w", 0, "Day-of-week value (0-6). Applicable to crons: 'weekly'")
+ backupCreate.Flags().IntP("dom", "m", 0, "Day-of-month value (1-28). Applicable to crons: 'monthly'")
+
+ backup.AddCommand(
+ backupGet,
+ backupCreate,
+ )
+
+ // Restore
+ restore := &cobra.Command{
+ Use: "restore ",
+ Short: "Restore instance from backup or snapshot",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ backup, errBa := cmd.Flags().GetString("backup")
+ if errBa != nil {
+ return fmt.Errorf("error parsing flag 'backup' for instance restore : %v", errBa)
+ }
+
+ snapshot, errSn := cmd.Flags().GetString("snapshot")
+ if errSn != nil {
+ return fmt.Errorf("error parsing flag 'snapshot' for instance restore : %v", errSn)
+ }
+
+ o.RestoreReq = &govultr.RestoreReq{
+ SnapshotID: snapshot,
+ BackupID: backup,
+ }
+
+ if err := o.restore(); err != nil {
+ return fmt.Errorf("error restoring instance : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Instance restored"), nil)
+
+ return nil
+ },
+ }
+
+ restore.Flags().StringP("backup", "b", "", "id of backup you wish to restore the instance with")
+ restore.Flags().StringP("snapshot", "s", "", "id of snapshot you wish to restore the instance with")
+ restore.MarkFlagsOneRequired("backup", "snapshot")
+ restore.MarkFlagsMutuallyExclusive("backup", "snapshot")
+
+ // Reinstall
+ reinstall := &cobra.Command{
+ Use: "reinstall ",
+ Short: "reinstall an instance",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ hostname, errHo := cmd.Flags().GetString("host")
+ if errHo != nil {
+ return fmt.Errorf("error parsing flag 'host' for instance reinstall : %v", errHo)
+ }
+
+ o.ReinstallReq = &govultr.ReinstallReq{}
+ if cmd.Flags().Changed("host") {
+ o.ReinstallReq.Hostname = hostname
+ }
+
+ if err := o.reinstall(); err != nil {
+ return fmt.Errorf("error reinstalling instance : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Instance reinstalled"), nil)
+
+ return nil
+ },
+ }
+
+ reinstall.Flags().StringP("host", "", "", "The hostname to assign to this instance")
+
+ // Operating System
+ operatingSystem := &cobra.Command{
+ Use: "os",
+ Short: "Operating system commands for an instance",
+ }
+
+ // OS List
+ osList := &cobra.Command{
+ Use: "list ",
+ Short: "List available operating systems",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ upgrades, err := o.upgrades()
+ if err != nil {
+ return fmt.Errorf("error getting instance os list : %v", err)
+ }
+
+ data := &OSsPrinter{OSs: upgrades.OS}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // OS Change
+ osChange := &cobra.Command{
+ Use: "change ",
+ Short: "Change operating system",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ osID, errOs := cmd.Flags().GetInt("os")
+ if errOs != nil {
+ return fmt.Errorf("error parsing flag 'osID' for instance os change : %v", errOs)
+ }
+
+ o.UpdateReq = &govultr.InstanceUpdateReq{
+ OsID: osID,
+ }
+
+ _, err := o.update()
+ if err != nil {
+ return fmt.Errorf("error updating instance os : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("OS change complete"), nil)
+
+ return nil
+ },
+ }
+
+ osChange.Flags().IntP("os", "", 0, "operating system ID you wish to use")
+ if err := osChange.MarkFlagRequired("os"); err != nil {
+ fmt.Printf("error marking instance os update 'os' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ operatingSystem.AddCommand(
+ osList,
+ osChange,
+ )
+
+ // Application
+ app := &cobra.Command{
+ Use: "app",
+ Aliases: []string{"image"},
+ Short: "Application commands for an instance",
+ }
+
+ // App List
+ appList := &cobra.Command{
+ Use: "list ",
+ Short: "List available applications",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ upgrades, err := o.upgrades()
+ if err != nil {
+ return fmt.Errorf("error getting instance applications list : %v", err)
+ }
+
+ data := &AppsPrinter{Apps: upgrades.Applications}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // App Change
+ appChange := &cobra.Command{
+ Use: "change ",
+ Short: "Change application",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ appID, errAp := cmd.Flags().GetInt("app")
+ if errAp != nil {
+ return fmt.Errorf("error parsing flag 'app' for instance application change : %v", errAp)
+ }
+
+ o.UpdateReq = &govultr.InstanceUpdateReq{
+ AppID: appID,
+ }
+
+ _, err := o.update()
+ if err != nil {
+ return fmt.Errorf("error updating instance application : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Application change complete"), nil)
+
+ return nil
+ },
+ }
+
+ appChange.Flags().IntP("app", "", 0, "Application ID you wish to use")
+ if err := appChange.MarkFlagRequired("app"); err != nil {
+ fmt.Printf("error marking instance app update 'app' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ app.AddCommand(
+ appList,
+ appChange,
+ )
+
+ // Plan
+ plan := &cobra.Command{
+ Use: "plan",
+ Short: "Plan commands for an instance",
+ }
+
+ // Plan List
+ planList := &cobra.Command{
+ Use: "list ",
+ Short: "List available plans",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ upgrades, err := o.upgrades()
+ if err != nil {
+ return fmt.Errorf("error getting instance applications list : %v", err)
+ }
+
+ data := &PlansPrinter{Plans: upgrades.Plans}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Plan Upgrade
+ planUpgrade := &cobra.Command{
+ Use: "upgrade ",
+ Short: "Upgrade instance plan",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ plan, errPl := cmd.Flags().GetString("plan")
+ if errPl != nil {
+ return fmt.Errorf("error parsing flag 'plan' for instance plan upgrade : %v", errPl)
+ }
+
+ o.UpdateReq = &govultr.InstanceUpdateReq{
+ Plan: plan,
+ }
+
+ _, err := o.update()
+ if err != nil {
+ return fmt.Errorf("error upgrading plan on instance : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Plan upgrade complete"), nil)
+
+ return nil
+ },
+ }
+
+ planUpgrade.Flags().String("plan", "", "The plan ID you wish to use")
+ if err := planUpgrade.MarkFlagRequired("plan"); err != nil {
+ fmt.Printf("error marking instance plan upgrade 'plan' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ plan.AddCommand(
+ planList,
+ planUpgrade,
+ )
+
+ // IPv4
+ ipv4 := &cobra.Command{
+ Use: "ipv4",
+ Short: "IPv4 instance commands",
+ }
+
+ // IPv4 List
+ ipv4List := &cobra.Command{
+ Use: "list ",
+ Aliases: []string{"v4"},
+ Short: "List IPv4 for an instance",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ o.Base.Options = utils.GetPaging(cmd)
+
+ v4s, meta, err := o.ipv4s()
+ if err != nil {
+ return fmt.Errorf("error getting ipv4 list for instance : %v", err)
+ }
+
+ data := &ip.IPv4sPrinter{IPv4s: v4s, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ ipv4List.Flags().StringP("cursor", "c", "", "(optional) cursor for paging.")
+ ipv4List.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ fmt.Sprintf("(optional) Number of items requested per page. Default is %d and Max is 500.", utils.PerPageDefault),
+ )
+
+ // IPv4 Create
+ ipv4Create := &cobra.Command{
+ Use: "create ",
+ Short: "Create IPv4 for instance",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ reboot, errRe := cmd.Flags().GetBool("reboot")
+ if errRe != nil {
+ return fmt.Errorf("error parsing flag 'reboot' for instance ipv4 create: %v", errRe)
+ }
+
+ if cmd.Flags().Changed("reboot") {
+ o.Reboot = &reboot
+ }
+
+ if err := o.ipv4Create(); err != nil {
+ return fmt.Errorf("error creating instance ipv4 : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("IPv4 has been created"), nil)
+
+ return nil
+ },
+ }
+
+ ipv4Create.Flags().Bool("reboot", false, "whether to reboot instance after adding ipv4 address")
+
+ // IPv4 Delete
+ ipv4Delete := &cobra.Command{
+ Use: "delete ",
+ Short: "Delete IPv4 on an instance",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 2 {
+ return errors.New("please provide an instance ID and the IP address")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.ipv4Delete(); err != nil {
+ return fmt.Errorf("error deleting ipv4 : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("IPv4 has been deleted"), nil)
+
+ return nil
+ },
+ }
+
+ ipv4.AddCommand(
+ ipv4List,
+ ipv4Create,
+ ipv4Delete,
+ )
+
+ // IPv6
+ ipv6 := &cobra.Command{
+ Use: "ipv6",
+ Short: "IPv6 instance commands",
+ }
+
+ // IPv6 List
+ ipv6List := &cobra.Command{
+ Use: "list ",
+ Aliases: []string{"v6"},
+ Short: "List IPv6 for an instance",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ o.Base.Options = utils.GetPaging(cmd)
+
+ v6s, meta, err := o.ipv6s()
+ if err != nil {
+ return fmt.Errorf("error getting ipv6 list for instance : %v", err)
+ }
+
+ data := &ip.IPv6sPrinter{IPv6s: v6s, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ ipv6List.Flags().StringP("cursor", "c", "", "(optional) cursor for paging.")
+ ipv6List.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ fmt.Sprintf("(optional) Number of items requested per page. Default is %d and Max is 500.", utils.PerPageDefault),
+ )
+
+ ipv6.AddCommand(
+ ipv6List,
+ )
+
+ // Reverse DNS
+ reverseDNS := &cobra.Command{
+ Use: "reverse-dns",
+ Short: "Commands to handle reverse DNS on an instance",
+ }
+
+ rDNSIPv4Default := &cobra.Command{
+ Use: "default-ipv4 ",
+ Short: "Set a reverse DNS entry for an IPv4 address of an instance to the original setting",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 2 {
+ return errors.New("please provide an instance ID and IP address")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.reverseDNSDefault(); err != nil {
+ return fmt.Errorf("error setting default reverse dns ipv4 : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Reverse DNS defaulse IPv4 has been set"), nil)
+
+ return nil
+ },
+ }
+
+ // Reverse DNS IPv4 Set
+ rDNSIPv4Set := &cobra.Command{
+ Use: "set-ipv4 ",
+ Short: "Set a reverse DNS IPv4 address entry for an instance",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 2 {
+ return errors.New("please provide an instance ID and an IPv4 address")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ entry, errEn := cmd.Flags().GetString("entry")
+ if errEn != nil {
+ return fmt.Errorf("error parsing flag 'entry' for instance reverse dns ipv4 set : %v", errEn)
+ }
+
+ o.ReverseDNSReq = &govultr.ReverseIP{
+ IP: o.Base.Args[1],
+ Reverse: entry,
+ }
+
+ if err := o.reverseDNSIPv4Create(); err != nil {
+ return fmt.Errorf("error creating reverse dns ipv4 : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Reverse DNS IPv4 has been set"), nil)
+
+ return nil
+ },
+ }
+
+ rDNSIPv4Set.Flags().StringP("entry", "e", "", "reverse dns entry")
+ if err := rDNSIPv4Set.MarkFlagRequired("entry"); err != nil {
+ fmt.Printf("error marking instance reverse-dns set-ipv4 'entry' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ // Reverse DNS IPv6 List
+ rDNSIPv6List := &cobra.Command{
+ Use: "list-ipv6 ",
+ Short: "List the IPv6 reverse DNS entries for an instance",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ ips, err := o.reverseDNSIPv6List()
+ if err != nil {
+ return fmt.Errorf("error retrieving list of reverse dns ipv6 : %v", err)
+ }
+
+ data := &ReverseIPsPrinter{ReverseIPs: ips}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Reverse DNS IPv6 Set
+ rDNSIPv6Set := &cobra.Command{
+ Use: "set-ipv6 ",
+ Short: "Set a reverse DNS IPv6 address entry for an instance",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 2 {
+ return errors.New("please provide an instance ID and an IPv6 address")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ entry, errEn := cmd.Flags().GetString("entry")
+ if errEn != nil {
+ return fmt.Errorf("error parsing flag 'entry' for instance reverse dns ipv6 set : %v", errEn)
+ }
+
+ o.ReverseDNSReq = &govultr.ReverseIP{
+ IP: o.Base.Args[1],
+ Reverse: entry,
+ }
+
+ if err := o.reverseDNSIPv6Create(); err != nil {
+ return fmt.Errorf("error creating reverse dns ipv6 : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Reverse DNS IPv6 has been set"), nil)
+
+ return nil
+ },
+ }
+
+ rDNSIPv6Set.Flags().StringP("entry", "e", "", "reverse dns entry")
+ if err := rDNSIPv6Set.MarkFlagRequired("entry"); err != nil {
+ fmt.Printf("error marking instance reverse-dns set-ipv6 'entry' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ // Reverse DNS IPv6 Delete
+ rDNSIPv6Delete := &cobra.Command{
+ Use: "delete-ipv6 , ",
+ Short: "Remove a reverse DNS IPv6 address entry for an instance",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID and an IPv6 address")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.reverseDNSIPv6Delete(); err != nil {
+ return fmt.Errorf("error deleting reverse dns ipv6 : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Reverse DNS IPv6 has been deleted"), nil)
+
+ return nil
+ },
+ }
+
+ reverseDNS.AddCommand(
+ rDNSIPv4Default,
+ rDNSIPv4Set,
+ rDNSIPv6List,
+ rDNSIPv6Delete,
+ rDNSIPv6Set,
+ )
+
+ // Firewall Group
+ firewallGroup := &cobra.Command{
+ Use: "update-firewall-group",
+ Short: "Assign a firewall group to instance",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ fwgID, errID := cmd.Flags().GetString("firewall-group-id")
+ if errID != nil {
+ return fmt.Errorf("error parsing flag 'firewall-group-id' for instance firewall group assignment : %v", errID)
+ }
+
+ o.UpdateReq = &govultr.InstanceUpdateReq{
+ FirewallGroupID: fwgID,
+ }
+
+ if _, err := o.update(); err != nil {
+ return fmt.Errorf("error updating fire wall group on instance : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("Firewall group assigned to instance"), nil)
+
+ return nil
+ },
+ }
+
+ firewallGroup.Flags().StringP(
+ "firewall-group-id",
+ "f",
+ "",
+ "firewall group id that you want to assign. 0 Value will unset the firewall-group",
+ )
+ if err := firewallGroup.MarkFlagRequired("firewall-group-id"); err != nil {
+ fmt.Printf("error marking instance firewall group 'firewall-group-id' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ // VPC
+ vpc := &cobra.Command{
+ Use: "vpc",
+ Short: "Commands to handle vpcs on an instance",
+ }
+
+ // VPC Attach
+ vpcAttach := &cobra.Command{
+ Use: "attach ",
+ Short: "Attach a VPC to an instance",
+ Long: vpcAttachLong,
+ Example: vpcAttachExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 2 {
+ return errors.New("please provide an instance ID and a VPC ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.vpcAttach(); err != nil {
+ return fmt.Errorf("error attaching vpc to instance : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("VPC attached to instance"), nil)
+
+ return nil
+ },
+ }
+
+ // VPC Detach
+ vpcDetach := &cobra.Command{
+ Use: "detach ",
+ Short: "Detach a VPC from an instance",
+ Long: vpcDetachLong,
+ Example: vpcDetachExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 2 {
+ return errors.New("please provide an instance ID and a VPC ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.vpcDetach(); err != nil {
+ return fmt.Errorf("error detaching vpc from instance : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("VPC detached from instance"), nil)
+
+ return nil
+ },
+ }
+
+ vpc.AddCommand(
+ vpcAttach,
+ vpcDetach,
+ )
+
+ // VPC2
+ vpc2 := &cobra.Command{
+ Use: "vpc2",
+ Short: "Commands to handle vpc2s on an instance",
+ }
+
+ // VPC List
+ vpc2List := &cobra.Command{
+ Use: "list ",
+ Aliases: []string{"l"},
+ Short: "List all VPC2 networks attached to an instance",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ o.Base.Options = utils.GetPaging(cmd)
+
+ vpc2s, meta, err := o.vpc2s()
+ if err != nil {
+ return fmt.Errorf("error getting vpc2 list for instance : %v", err)
+ }
+
+ data := &VPC2sPrinter{VPC2s: vpc2s, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // VPC2 Attach
+ vpc2Attach := &cobra.Command{
+ Use: "attach , ",
+ Short: "Attach a VPC2 to an instance",
+ Long: vpc2AttachLong,
+ Example: vpc2AttachExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 2 {
+ return errors.New("please provide an instance ID and a VPC ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ ip, errIP := cmd.Flags().GetString("ip-address")
+ if errIP != nil {
+ return fmt.Errorf("error parsing flag 'ip-address' for vpc2 instance attach : %v", errIP)
+ }
+
+ o.VPC2Req = &govultr.AttachVPC2Req{
+ VPCID: o.Base.Args[1],
+ IPAddress: &ip,
+ }
+
+ if err := o.vpc2Attach(); err != nil {
+ return fmt.Errorf("error attaching vpc2 to instance : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("VPC2 attached to instance"), nil)
+
+ return nil
+ },
+ }
+
+ vpc2Attach.Flags().StringP(
+ "ip-address",
+ "i",
+ "",
+ "the IP address to use for this instance on the attached VPC 2.0 network",
+ )
+
+ // VPC2 Detach
+ vpc2Detach := &cobra.Command{
+ Use: "detach ",
+ Short: "Detach a VPC2 from an instance",
+ Long: vpc2DetachLong,
+ Example: vpc2DetachExample,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 2 {
+ return errors.New("please provide an instance ID and a VPC2 ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.vpc2Detach(); err != nil {
+ return fmt.Errorf("error detaching vpc2 from instance : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("VPC2 detached from instance"), nil)
+
+ return nil
+ },
+ }
+
+ vpc2.AddCommand(
+ vpc2List,
+ vpc2Attach,
+ vpc2Detach,
+ )
+
+ // Bandwidth
+ bandwidth := &cobra.Command{
+ Use: "bandwidth ",
+ Short: "Get bandwidth usage ",
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an instance ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ bw, err := o.bandwidth()
+ if err != nil {
+ return fmt.Errorf("error getting bandwidth details : %v", err)
+ }
+
+ data := &BandwidthPrinter{Bandwidth: *bw}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ cmd.AddCommand(
+ list,
+ get,
+ create,
+ del,
+ label,
+ tags,
+ userData,
+ start,
+ stop,
+ restart,
+ iso,
+ backup,
+ restore,
+ reinstall,
+ operatingSystem,
+ app,
+ plan,
+ ipv4,
+ ipv6,
+ reverseDNS,
+ firewallGroup,
+ vpc,
+ vpc2,
+ bandwidth,
+ )
+
+ return cmd
+}
+
+type options struct {
+ Base *cli.Base
+ CreateReq *govultr.InstanceCreateReq
+ UpdateReq *govultr.InstanceUpdateReq
+ BackupCreateReq *govultr.BackupScheduleReq
+ RestoreReq *govultr.RestoreReq
+ ReinstallReq *govultr.ReinstallReq
+ ISOAttachID string
+ Reboot *bool
+ ReverseDNSReq *govultr.ReverseIP
+ VPC2Req *govultr.AttachVPC2Req
+}
+
+func (o *options) list() ([]govultr.Instance, *govultr.Meta, error) {
+ insts, meta, _, err := o.Base.Client.Instance.List(o.Base.Context, o.Base.Options)
+ return insts, meta, err
+}
+
+func (o *options) get() (*govultr.Instance, error) {
+ inst, _, err := o.Base.Client.Instance.Get(o.Base.Context, o.Base.Args[0])
+ return inst, err
+}
+
+func (o *options) create() (*govultr.Instance, error) {
+ inst, _, err := o.Base.Client.Instance.Create(o.Base.Context, o.CreateReq)
+ return inst, err
+}
+
+func (o *options) update() (*govultr.Instance, error) {
+ inst, _, err := o.Base.Client.Instance.Update(o.Base.Context, o.Base.Args[0], o.UpdateReq)
+ return inst, err
+}
+
+func (o *options) del() error {
+ return o.Base.Client.Instance.Delete(o.Base.Context, o.Base.Args[0])
+}
+
+func (o *options) userData() (*govultr.UserData, error) {
+ ud, _, err := o.Base.Client.Instance.GetUserData(o.Base.Context, o.Base.Args[0])
+ return ud, err
+}
+
+func (o *options) start() error {
+ return o.Base.Client.Instance.Start(o.Base.Context, o.Base.Args[0])
+}
+
+func (o *options) stop() error {
+ return o.Base.Client.Instance.Halt(o.Base.Context, o.Base.Args[0])
+}
+
+func (o *options) restart() error {
+ return o.Base.Client.Instance.Reboot(o.Base.Context, o.Base.Args[0])
+}
+
+func (o *options) backups() (*govultr.BackupSchedule, error) {
+ bk, _, err := o.Base.Client.Instance.GetBackupSchedule(o.Base.Context, o.Base.Args[0])
+ return bk, err
+}
+
+func (o *options) backupCreate() error {
+ _, err := o.Base.Client.Instance.SetBackupSchedule(o.Base.Context, o.Base.Args[0], o.BackupCreateReq)
+ return err
+}
+
+func (o *options) restore() error {
+ _, err := o.Base.Client.Instance.Restore(o.Base.Context, o.Base.Args[0], o.RestoreReq)
+ return err
+}
+
+func (o *options) reinstall() error {
+ _, _, err := o.Base.Client.Instance.Reinstall(o.Base.Context, o.Base.Args[0], o.ReinstallReq)
+ return err
+}
+
+func (o *options) isoStatus() (*govultr.Iso, error) {
+ iso, _, err := o.Base.Client.Instance.ISOStatus(o.Base.Context, o.Base.Args[0])
+ return iso, err
+}
+
+func (o *options) isoAttach() error {
+ _, err := o.Base.Client.Instance.AttachISO(o.Base.Context, o.Base.Args[0], o.ISOAttachID)
+ return err
+}
+
+func (o *options) upgrades() (*govultr.Upgrades, error) {
+ oss, _, err := o.Base.Client.Instance.GetUpgrades(o.Base.Context, o.Base.Args[0])
+ return oss, err
+}
+
+func (o *options) ipv4s() ([]govultr.IPv4, *govultr.Meta, error) {
+ ips, meta, _, err := o.Base.Client.Instance.ListIPv4(o.Base.Context, o.Base.Args[0], o.Base.Options)
+ return ips, meta, err
+}
+
+func (o *options) ipv4Create() error {
+ _, _, err := o.Base.Client.Instance.CreateIPv4(o.Base.Context, o.Base.Args[0], o.Reboot)
+ return err
+}
+
+func (o *options) ipv4Delete() error {
+ return o.Base.Client.Instance.DeleteIPv4(o.Base.Context, o.Base.Args[0], o.Base.Args[1])
+}
+
+func (o *options) ipv6s() ([]govultr.IPv6, *govultr.Meta, error) {
+ ips, meta, _, err := o.Base.Client.Instance.ListIPv6(o.Base.Context, o.Base.Args[0], o.Base.Options)
+ return ips, meta, err
+}
+
+func (o *options) reverseDNSDefault() error {
+ return o.Base.Client.Instance.DefaultReverseIPv4(o.Base.Context, o.Base.Args[0], o.Base.Args[1])
+}
+
+func (o *options) reverseDNSIPv4Create() error {
+ return o.Base.Client.Instance.CreateReverseIPv4(o.Base.Context, o.Base.Args[0], o.ReverseDNSReq)
+}
+
+func (o *options) reverseDNSIPv6List() ([]govultr.ReverseIP, error) {
+ ips, _, err := o.Base.Client.Instance.ListReverseIPv6(o.Base.Context, o.Base.Args[0])
+ return ips, err
+}
+
+func (o *options) reverseDNSIPv6Create() error {
+ return o.Base.Client.Instance.CreateReverseIPv6(o.Base.Context, o.Base.Args[0], o.ReverseDNSReq)
+}
+
+func (o *options) reverseDNSIPv6Delete() error {
+ return o.Base.Client.Instance.DeleteReverseIPv6(o.Base.Context, o.Base.Args[0], o.Base.Args[1])
+}
+
+func (o *options) vpcAttach() error {
+ return o.Base.Client.Instance.AttachVPC(o.Base.Context, o.Base.Args[0], o.Base.Args[1])
+}
+
+func (o *options) vpcDetach() error {
+ return o.Base.Client.Instance.DetachVPC(o.Base.Context, o.Base.Args[0], o.Base.Args[1])
+}
+
+func (o *options) vpc2s() ([]govultr.VPC2Info, *govultr.Meta, error) {
+ vpc2s, meta, _, err := o.Base.Client.Instance.ListVPC2Info(o.Base.Context, o.Base.Args[0], o.Base.Options)
+ return vpc2s, meta, err
+}
+
+func (o *options) vpc2Attach() error {
+ return o.Base.Client.Instance.AttachVPC2(o.Base.Context, o.Base.Args[0], o.VPC2Req)
+}
+
+func (o *options) vpc2Detach() error {
+ return o.Base.Client.Instance.DetachVPC2(o.Base.Context, o.Base.Args[0], o.Base.Args[1])
+}
+
+func (o *options) bandwidth() (*govultr.Bandwidth, error) {
+ bw, _, err := o.Base.Client.Instance.GetBandwidth(o.Base.Context, o.Base.Args[0])
+ return bw, err
+}
diff --git a/cmd/instance/printer.go b/cmd/instance/printer.go
new file mode 100644
index 00000000..b232694d
--- /dev/null
+++ b/cmd/instance/printer.go
@@ -0,0 +1,513 @@
+package instance
+
+import (
+ "strconv"
+
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+)
+
+// InstancesPrinter ...
+type InstancesPrinter struct {
+ Instances []govultr.Instance `json:"instances"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (i *InstancesPrinter) JSON() []byte {
+ return printer.MarshalObject(i, "json")
+}
+
+// YAML ...
+func (i *InstancesPrinter) YAML() []byte {
+ return printer.MarshalObject(i, "yaml")
+}
+
+// Columns ...
+func (i *InstancesPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "IP",
+ "LABEL",
+ "OS",
+ "STATUS",
+ "REGION",
+ "CPU",
+ "RAM",
+ "DISK",
+ "BANDWIDTH",
+ "TAGS",
+ }}
+}
+
+// Data ...
+func (i *InstancesPrinter) Data() [][]string {
+ if len(i.Instances) == 0 {
+ return [][]string{0: {"---", "---", "---", "---", "---", "---", "---", "---", "---", "---", "---"}}
+ }
+
+ var data [][]string
+ for j := range i.Instances {
+ data = append(data, []string{
+ i.Instances[j].ID,
+ i.Instances[j].MainIP,
+ i.Instances[j].Label,
+ i.Instances[j].Os,
+ i.Instances[j].Status,
+ i.Instances[j].Region,
+ strconv.Itoa(i.Instances[j].VCPUCount),
+ strconv.Itoa(i.Instances[j].RAM),
+ strconv.Itoa(i.Instances[j].Disk),
+ strconv.Itoa(i.Instances[j].AllowedBandwidth),
+ printer.ArrayOfStringsToString(i.Instances[j].Tags),
+ })
+ }
+ return data
+}
+
+// Paging ...
+func (i *InstancesPrinter) Paging() [][]string {
+ return printer.NewPaging(i.Meta.Total, &i.Meta.Links.Next, &i.Meta.Links.Prev).Compose()
+}
+
+// ======================================
+
+// InstancePrinter ...
+type InstancePrinter struct {
+ Instance *govultr.Instance `json:"instance"`
+}
+
+// JSON ...
+func (i *InstancePrinter) JSON() []byte {
+ return printer.MarshalObject(i, "json")
+}
+
+// YAML ...
+func (i *InstancePrinter) YAML() []byte {
+ return printer.MarshalObject(i, "yaml")
+}
+
+// Columns ...
+func (i *InstancePrinter) Columns() [][]string {
+ return [][]string{0: {"INSTANCE INFO"}}
+}
+
+// Data ...
+func (i *InstancePrinter) Data() [][]string {
+ var data [][]string
+ data = append(data,
+ []string{"ID", i.Instance.ID},
+ []string{"OS", i.Instance.Os},
+ []string{"OS ID", strconv.Itoa(i.Instance.OsID)},
+ []string{"APP ID", strconv.Itoa(i.Instance.AppID)},
+ []string{"RAM", strconv.Itoa(i.Instance.RAM)},
+ []string{"DISK", strconv.Itoa(i.Instance.Disk)},
+ []string{"MAIN IP", i.Instance.MainIP},
+ []string{"VCPU COUNT", strconv.Itoa(i.Instance.VCPUCount)},
+ []string{"REGION", i.Instance.Region},
+ []string{"DATE CREATED", i.Instance.DateCreated},
+ []string{"STATUS", i.Instance.Status},
+ []string{"ALLOWED BANDWIDTH", strconv.Itoa(i.Instance.AllowedBandwidth)},
+ []string{"NETMASK V4", i.Instance.NetmaskV4},
+ []string{"GATEWAY V4", i.Instance.GatewayV4},
+ []string{"POWER STATUS", i.Instance.PowerStatus},
+ []string{"SERVER STATE", i.Instance.ServerStatus},
+ []string{"PLAN", i.Instance.Plan},
+ []string{"LABEL", i.Instance.Label},
+ []string{"INTERNAL IP", i.Instance.InternalIP},
+ []string{"KVM URL", i.Instance.KVM},
+ []string{"FIREWALL GROUP ID", i.Instance.FirewallGroupID},
+ []string{"V6 MAIN IP", i.Instance.V6MainIP},
+ []string{"V6 NETWORK", i.Instance.V6Network},
+ []string{"V6 NETWORK SIZE", strconv.Itoa(i.Instance.V6NetworkSize)},
+ []string{"FEATURES", printer.ArrayOfStringsToString(i.Instance.Features)},
+ []string{"TAGS", printer.ArrayOfStringsToString(i.Instance.Tags)},
+ )
+
+ return data
+}
+
+// Paging ...
+func (i *InstancePrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// BandwidthPrinter ...
+type BandwidthPrinter struct {
+ Bandwidth govultr.Bandwidth `json:"bandwidth"`
+}
+
+// JSON ...
+func (b *BandwidthPrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BandwidthPrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BandwidthPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "DATE",
+ "INCOMING BYTES",
+ "OUTGOING BYTES",
+ }}
+}
+
+// Data ...
+func (b *BandwidthPrinter) Data() [][]string {
+ var data [][]string
+ for i := range b.Bandwidth.Bandwidth {
+ data = append(data, []string{
+ i,
+ strconv.Itoa(b.Bandwidth.Bandwidth[i].IncomingBytes),
+ strconv.Itoa(b.Bandwidth.Bandwidth[i].OutgoingBytes),
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (b *BandwidthPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// BackupPrinter ...
+type BackupPrinter struct {
+ Backup govultr.BackupSchedule `json:"backup_schedule"`
+}
+
+// JSON ...
+func (b *BackupPrinter) JSON() []byte {
+ return printer.MarshalObject(b, "json")
+}
+
+// YAML ...
+func (b *BackupPrinter) YAML() []byte {
+ return printer.MarshalObject(b, "yaml")
+}
+
+// Columns ...
+func (b *BackupPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ENABLED",
+ "CRON TYPE",
+ "NEXT RUN",
+ "HOUR",
+ "DOW",
+ "DOM",
+ }}
+}
+
+// Data ...
+func (b *BackupPrinter) Data() [][]string {
+ return [][]string{0: {
+ strconv.FormatBool(*b.Backup.Enabled),
+ b.Backup.Type,
+ b.Backup.NextScheduleTimeUTC,
+ strconv.Itoa(b.Backup.Hour),
+ strconv.Itoa(b.Backup.Dow),
+ strconv.Itoa(b.Backup.Dom),
+ }}
+}
+
+// Paging ...
+func (b *BackupPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// ISOPrinter ...
+type ISOPrinter struct {
+ ISO govultr.Iso `json:"iso_status"`
+}
+
+// JSON ...
+func (i *ISOPrinter) JSON() []byte {
+ return printer.MarshalObject(i, "json")
+}
+
+// YAML ...
+func (i *ISOPrinter) YAML() []byte {
+ return printer.MarshalObject(i, "yaml")
+}
+
+// Columns ...
+func (i *ISOPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ISO ID",
+ "STATE",
+ }}
+}
+
+// Data ...
+func (i *ISOPrinter) Data() [][]string {
+ return [][]string{0: {
+ i.ISO.IsoID,
+ i.ISO.State,
+ }}
+}
+
+// Paging ...
+func (i *ISOPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// OSsPrinter ...
+type OSsPrinter struct {
+ OSs []govultr.OS `json:"operating_systems"`
+}
+
+// JSON ...
+func (o *OSsPrinter) JSON() []byte {
+ return printer.MarshalObject(o, "json")
+}
+
+// YAML ...
+func (o *OSsPrinter) YAML() []byte {
+ return printer.MarshalObject(o, "yaml")
+}
+
+// Columns ...
+func (o *OSsPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "NAME",
+ "ARCH",
+ "FAMILY",
+ }}
+}
+
+// Data ...
+func (o *OSsPrinter) Data() [][]string {
+ if len(o.OSs) == 0 {
+ return [][]string{0: {"---", "---", "---", "---"}}
+ }
+
+ var data [][]string
+ for i := range o.OSs {
+ data = append(data, []string{
+ strconv.Itoa(o.OSs[i].ID),
+ o.OSs[i].Name,
+ o.OSs[i].Arch,
+ o.OSs[i].Family,
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (o *OSsPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// AppsPrinter ...
+type AppsPrinter struct {
+ Apps []govultr.Application `json:"applications"`
+}
+
+// JSON ...
+func (a *AppsPrinter) JSON() []byte {
+ return printer.MarshalObject(a, "json")
+}
+
+// YAML ...
+func (a *AppsPrinter) YAML() []byte {
+ return printer.MarshalObject(a, "yaml")
+}
+
+// Columns ...
+func (a *AppsPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "NAME",
+ "SHORT NAME",
+ "DEPLOY NAME",
+ "TYPE",
+ "VENDOR",
+ "IMAGE ID",
+ }}
+}
+
+// Data ...
+func (a *AppsPrinter) Data() [][]string {
+ if len(a.Apps) == 0 {
+ return [][]string{0: {"---", "---", "---", "---", "---", "---", "---"}}
+ }
+
+ var data [][]string
+ for i := range a.Apps {
+ data = append(data, []string{
+ strconv.Itoa(a.Apps[i].ID),
+ a.Apps[i].Name,
+ a.Apps[i].ShortName,
+ a.Apps[i].DeployName,
+ a.Apps[i].Type,
+ a.Apps[i].Vendor,
+ a.Apps[i].ImageID,
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (a *AppsPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// PlansPrinter ...
+type PlansPrinter struct {
+ Plans []string `json:"plans"`
+}
+
+// JSON ...
+func (p *PlansPrinter) JSON() []byte {
+ return printer.MarshalObject(p, "json")
+}
+
+// YAML ...
+func (p *PlansPrinter) YAML() []byte {
+ return printer.MarshalObject(p, "yaml")
+}
+
+// Columns ...
+func (p *PlansPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "PLAN NAME",
+ }}
+}
+
+// Data ...
+func (p *PlansPrinter) Data() [][]string {
+ if len(p.Plans) == 0 {
+ return [][]string{0: {"---"}}
+ }
+
+ var data [][]string
+ for i := range p.Plans {
+ data = append(data, []string{
+ p.Plans[i],
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (p *PlansPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// ReverseIPsPrinter ...
+type ReverseIPsPrinter struct {
+ ReverseIPs []govultr.ReverseIP `json:"reverse_ips"`
+}
+
+// JSON ...
+func (r *ReverseIPsPrinter) JSON() []byte {
+ return printer.MarshalObject(r, "json")
+}
+
+// YAML ...
+func (r *ReverseIPsPrinter) YAML() []byte {
+ return printer.MarshalObject(r, "yaml")
+}
+
+// Columns ...
+func (r *ReverseIPsPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "IP",
+ "REVERSE",
+ }}
+}
+
+// Data ...
+func (r *ReverseIPsPrinter) Data() [][]string {
+ if len(r.ReverseIPs) == 0 {
+ return [][]string{0: {"---", "---"}}
+ }
+
+ var data [][]string
+ for j := range r.ReverseIPs {
+ data = append(data, []string{
+ r.ReverseIPs[j].IP,
+ r.ReverseIPs[j].Reverse,
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (r *ReverseIPsPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// VPC2sPrinter ...
+type VPC2sPrinter struct {
+ VPC2s []govultr.VPC2Info `json:"vpcs"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (v *VPC2sPrinter) JSON() []byte {
+ return printer.MarshalObject(v, "json")
+}
+
+// YAML ...
+func (v *VPC2sPrinter) YAML() []byte {
+ return printer.MarshalObject(v, "yaml")
+}
+
+// Columns ...
+func (v *VPC2sPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "MAC ADDRESS",
+ "IP ADDRESS",
+ }}
+}
+
+// Data ...
+func (v *VPC2sPrinter) Data() [][]string {
+ var data [][]string
+
+ if len(v.VPC2s) == 0 {
+ return [][]string{0: {"---", "---", "---"}}
+ }
+
+ for i := range v.VPC2s {
+ data = append(data, []string{
+ v.VPC2s[i].ID,
+ v.VPC2s[i].MacAddress,
+ v.VPC2s[i].IPAddress,
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (v *VPC2sPrinter) Paging() [][]string {
+ return printer.NewPaging(v.Meta.Total, &v.Meta.Links.Next, &v.Meta.Links.Prev).Compose()
+}
diff --git a/cmd/ip/printer.go b/cmd/ip/printer.go
new file mode 100644
index 00000000..f05a5272
--- /dev/null
+++ b/cmd/ip/printer.go
@@ -0,0 +1,103 @@
+// Package ip provides printers for server network addresses
+package ip
+
+import (
+ "strconv"
+
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+)
+
+// IPv4sPrinter ...
+type IPv4sPrinter struct {
+ IPv4s []govultr.IPv4 `json:"ipv4s"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (i *IPv4sPrinter) JSON() []byte {
+ return printer.MarshalObject(i, "json")
+}
+
+// YAML ...
+func (i *IPv4sPrinter) YAML() []byte {
+ return printer.MarshalObject(i, "yaml")
+}
+
+// Columns ...
+func (i *IPv4sPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "IP",
+ "NETMASK",
+ "GATEWAY",
+ "TYPE",
+ }}
+}
+
+// Data ...
+func (i *IPv4sPrinter) Data() [][]string {
+ var data [][]string
+ for j := range i.IPv4s {
+ data = append(data, []string{
+ i.IPv4s[j].IP,
+ i.IPv4s[j].Netmask,
+ i.IPv4s[j].Gateway,
+ i.IPv4s[j].Type,
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (i *IPv4sPrinter) Paging() [][]string {
+ return printer.NewPaging(i.Meta.Total, &i.Meta.Links.Next, &i.Meta.Links.Prev).Compose()
+}
+
+// ======================================
+
+// IPv6sPrinter ...
+type IPv6sPrinter struct {
+ IPv6s []govultr.IPv6 `json:"ipv6s"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (i *IPv6sPrinter) JSON() []byte {
+ return printer.MarshalObject(i, "json")
+}
+
+// YAML ...
+func (i *IPv6sPrinter) YAML() []byte {
+ return printer.MarshalObject(i, "yaml")
+}
+
+// Columns ...
+func (i *IPv6sPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "IP",
+ "NETWORK",
+ "NETWORK SIZE",
+ "TYPE",
+ }}
+}
+
+// Data ...
+func (i *IPv6sPrinter) Data() [][]string {
+ var data [][]string
+ for j := range i.IPv6s {
+ data = append(data, []string{
+ i.IPv6s[j].IP,
+ i.IPv6s[j].Network,
+ strconv.Itoa(i.IPv6s[j].NetworkSize),
+ i.IPv6s[j].Type,
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (i *IPv6sPrinter) Paging() [][]string {
+ return printer.NewPaging(i.Meta.Total, &i.Meta.Links.Next, &i.Meta.Links.Prev).Compose()
+}
diff --git a/cmd/iso.go b/cmd/iso.go
deleted file mode 100644
index d472a851..00000000
--- a/cmd/iso.go
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright © 2019 The Vultr-cli Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cmd
-
-import (
- "context"
- "errors"
- "fmt"
- "os"
-
- "github.com/vultr/govultr/v2"
- "github.com/vultr/vultr-cli/cmd/printer"
-
- "github.com/spf13/cobra"
-)
-
-// ISO represents the iso command
-func ISO() *cobra.Command {
- isoCmd := &cobra.Command{
- Use: "iso",
- Short: "iso is used to access iso commands",
- Long: ``,
- }
-
- isoCmd.AddCommand(isoCreate, isoDelete, isoPrivateGet, isoPrivateList, isoPublic)
- isoCreate.Flags().StringP("url", "u", "", "url from where the ISO will be downloaded")
- isoCreate.MarkFlagRequired("url")
-
- isoPrivateList.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
- isoPrivateList.Flags().IntP("per-page", "p", 100, "(optional) Number of items requested per page. Default is 100 and Max is 500.")
-
- isoPublic.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
- isoPublic.Flags().IntP("per-page", "p", 100, "(optional) Number of items requested per page. Default is 100 and Max is 500.")
-
- return isoCmd
-}
-
-var isoPrivateGet = &cobra.Command{
- Use: "get ",
- Short: "get private ISO ",
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an ISO id")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- iso, err := client.ISO.Get(context.Background(), id)
- if err != nil {
- fmt.Printf("error getting ISO : %v\n", err)
- os.Exit(1)
- }
-
- printer.IsoPrivate(iso)
- },
-}
-
-var isoPrivateList = &cobra.Command{
- Use: "list",
- Short: "list all private ISOs available",
- Long: ``,
- Run: func(cmd *cobra.Command, args []string) {
- options := getPaging(cmd)
- isos, meta, err := client.ISO.List(context.Background(), options)
- if err != nil {
- fmt.Printf("error getting private ISOs : %v\n", err)
- os.Exit(1)
- }
-
- printer.IsoPrivates(isos, meta)
- },
-}
-
-var isoPublic = &cobra.Command{
- Use: "public",
- Short: "list all public ISOs available",
- Long: ``,
- Run: func(cmd *cobra.Command, args []string) {
- options := getPaging(cmd)
- isos, meta, err := client.ISO.ListPublic(context.Background(), options)
- if err != nil {
- fmt.Printf("error getting public ISOs : %v\n", err)
- os.Exit(1)
- }
-
- printer.IsoPublic(isos, meta)
- },
-}
-
-var isoCreate = &cobra.Command{
- Use: "create",
- Short: "create iso from url",
- Long: ``,
- Run: func(cmd *cobra.Command, args []string) {
- url, _ := cmd.Flags().GetString("url")
- options := &govultr.ISOReq{
- URL: url,
- }
-
- iso, err := client.ISO.Create(context.Background(), options)
- if err != nil {
- fmt.Printf("error creating ISOs : %v\n", err)
- os.Exit(1)
- }
-
- printer.IsoPrivate(iso)
- },
-}
-
-var isoDelete = &cobra.Command{
- Use: "delete ",
- Short: "delete a private iso",
- Aliases: []string{"destroy"},
- Long: ``,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) < 1 {
- return errors.New("please provide an isoID")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- id := args[0]
- if err := client.ISO.Delete(context.Background(), id); err != nil {
- fmt.Printf("error deleting ISOs : %v\n", err)
- os.Exit(1)
- }
-
- fmt.Println("ISO has been deleted")
- },
-}
diff --git a/cmd/iso/iso.go b/cmd/iso/iso.go
new file mode 100644
index 00000000..cf7d4936
--- /dev/null
+++ b/cmd/iso/iso.go
@@ -0,0 +1,190 @@
+// Package iso provides the ISO related commands to the CLI
+package iso
+
+import (
+ "errors"
+ "fmt"
+ "os"
+
+ "github.com/spf13/cobra"
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+ "github.com/vultr/vultr-cli/v3/pkg/cli"
+)
+
+// NewCmdISO provides the CLI command for ISO functions
+func NewCmdISO(base *cli.Base) *cobra.Command {
+ o := &options{Base: base}
+
+ cmd := &cobra.Command{
+ Use: "iso",
+ Short: "iso is used to access iso commands",
+ Long: ``,
+ PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+ utils.SetOptions(o.Base, cmd, args)
+ if !o.Base.HasAuth {
+ return errors.New(utils.APIKeyError)
+ }
+ return nil
+ },
+ }
+
+ // List
+ list := &cobra.Command{
+ Use: "list",
+ Short: "list all private ISOs available",
+ Long: ``,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ o.Base.Options = utils.GetPaging(cmd)
+
+ isos, meta, err := o.list()
+ if err != nil {
+ return fmt.Errorf("error retrieving private ISO list : %v", err)
+ }
+
+ data := &ISOsPrinter{ISOs: isos, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ list.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.")
+ list.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ "(optional) Number of items requested per page. Default is 100 and Max is 500.",
+ )
+
+ // Get
+ get := &cobra.Command{
+ Use: "get ",
+ Short: "get private ISO by ID",
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an ISO ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ iso, err := o.get()
+ if err != nil {
+ return fmt.Errorf("error getting ISO : %v", err)
+ }
+
+ data := &ISOPrinter{ISO: *iso}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Create
+ create := &cobra.Command{
+ Use: "create",
+ Short: "create ISO from url",
+ Long: ``,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ url, errUR := cmd.Flags().GetString("url")
+ if errUR != nil {
+ return fmt.Errorf("error parsing flag 'url' for ISO create : %v", errUR)
+ }
+
+ o.CreateReq = &govultr.ISOReq{URL: url}
+
+ iso, err := o.create()
+ if err != nil {
+ return fmt.Errorf("error creating ISO : %v", err)
+ }
+
+ data := &ISOPrinter{ISO: *iso}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ create.Flags().StringP("url", "u", "", "url from where the ISO will be downloaded")
+ if err := create.MarkFlagRequired("url"); err != nil {
+ printer.Error(fmt.Errorf("error marking iso create 'url' flag required : %v", err))
+ os.Exit(1)
+ }
+
+ // Delete
+ del := &cobra.Command{
+ Use: "delete ",
+ Short: "delete a private ISO",
+ Aliases: []string{"destroy"},
+ Long: ``,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide an ISO ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ if err := o.del(); err != nil {
+ return fmt.Errorf("error deleting ISO : %v", err)
+ }
+
+ o.Base.Printer.Display(printer.Info("ISO has been deleted"), nil)
+ return nil
+ },
+ }
+
+ // Public ISOs
+ public := &cobra.Command{
+ Use: "public",
+ Short: "list all public ISOs available",
+ Long: ``,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ o.Base.Options = utils.GetPaging(cmd)
+
+ isos, meta, err := o.listPublic()
+ if err != nil {
+ return fmt.Errorf("error retrieving public ISO list : %v", err)
+ }
+
+ data := &PublicISOsPrinter{ISOs: isos, Meta: meta}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ cmd.AddCommand(list, get, create, del, public)
+
+ return cmd
+}
+
+type options struct {
+ Base *cli.Base
+ CreateReq *govultr.ISOReq
+}
+
+func (o *options) list() ([]govultr.ISO, *govultr.Meta, error) {
+ isos, meta, _, err := o.Base.Client.ISO.List(o.Base.Context, o.Base.Options)
+ return isos, meta, err
+}
+
+func (o *options) get() (*govultr.ISO, error) {
+ iso, _, err := o.Base.Client.ISO.Get(o.Base.Context, o.Base.Args[0])
+ return iso, err
+}
+
+func (o *options) create() (*govultr.ISO, error) {
+ iso, _, err := o.Base.Client.ISO.Create(o.Base.Context, o.CreateReq)
+ return iso, err
+}
+
+func (o *options) del() error {
+ return o.Base.Client.ISO.Delete(o.Base.Context, o.Base.Args[0])
+}
+
+func (o *options) listPublic() ([]govultr.PublicISO, *govultr.Meta, error) {
+ isos, meta, _, err := o.Base.Client.ISO.ListPublic(o.Base.Context, o.Base.Options)
+ return isos, meta, err
+}
diff --git a/cmd/iso/printer.go b/cmd/iso/printer.go
new file mode 100644
index 00000000..ccb36b3a
--- /dev/null
+++ b/cmd/iso/printer.go
@@ -0,0 +1,158 @@
+package iso
+
+import (
+ "strconv"
+
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+)
+
+// ISOsPrinter ...
+type ISOsPrinter struct {
+ ISOs []govultr.ISO `json:"isos"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (i *ISOsPrinter) JSON() []byte {
+ return printer.MarshalObject(i, "json")
+}
+
+// YAML ...
+func (i *ISOsPrinter) YAML() []byte {
+ return printer.MarshalObject(i, "yaml")
+}
+
+// Columns ...
+func (i *ISOsPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "FILE NAME",
+ "SIZE",
+ "STATUS",
+ "MD5SUM",
+ "SHA512SUM",
+ "DATE CREATED",
+ }}
+}
+
+// Data ...
+func (i *ISOsPrinter) Data() [][]string {
+ if len(i.ISOs) == 0 {
+ return [][]string{0: {"---", "---", "---", "---", "---", "---", "---"}}
+ }
+
+ var data [][]string
+ for n := range i.ISOs {
+ data = append(data, []string{
+ i.ISOs[n].ID,
+ i.ISOs[n].FileName,
+ strconv.Itoa(i.ISOs[n].Size),
+ i.ISOs[n].Status,
+ i.ISOs[n].MD5Sum,
+ i.ISOs[n].SHA512Sum,
+ i.ISOs[n].DateCreated,
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (i *ISOsPrinter) Paging() [][]string {
+ return printer.NewPaging(i.Meta.Total, &i.Meta.Links.Next, &i.Meta.Links.Prev).Compose()
+}
+
+// ======================================
+
+// ISOPrinter ...
+type ISOPrinter struct {
+ ISO govultr.ISO `json:"iso"`
+}
+
+// JSON ...
+func (i *ISOPrinter) JSON() []byte {
+ return printer.MarshalObject(i, "json")
+}
+
+// YAML ...
+func (i *ISOPrinter) YAML() []byte {
+ return printer.MarshalObject(i, "yaml")
+}
+
+// Columns ...
+func (i *ISOPrinter) Columns() [][]string {
+ return [][]string{0: {
+ "ID",
+ "FILE NAME",
+ "SIZE",
+ "STATUS",
+ "MD5SUM",
+ "SHA512SUM",
+ "DATE CREATED",
+ }}
+}
+
+// Data ...
+func (i *ISOPrinter) Data() [][]string {
+ return [][]string{0: {
+ i.ISO.ID,
+ i.ISO.FileName,
+ strconv.Itoa(i.ISO.Size),
+ i.ISO.Status,
+ i.ISO.MD5Sum,
+ i.ISO.SHA512Sum,
+ i.ISO.DateCreated,
+ }}
+}
+
+// Paging ...
+func (i *ISOPrinter) Paging() [][]string {
+ return nil
+}
+
+// ======================================
+
+// PublicISOsPrinter ...
+type PublicISOsPrinter struct {
+ ISOs []govultr.PublicISO `json:"public_isos"`
+ Meta *govultr.Meta `json:"meta"`
+}
+
+// JSON ...
+func (i *PublicISOsPrinter) JSON() []byte {
+ return printer.MarshalObject(i, "json")
+}
+
+// YAML ...
+func (i *PublicISOsPrinter) YAML() []byte {
+ return printer.MarshalObject(i, "yaml")
+}
+
+// Columns ...
+func (i *PublicISOsPrinter) Columns() [][]string {
+ return [][]string{0: {"ID", "NAME", "DESCRIPTION"}}
+}
+
+// Data ...
+func (i *PublicISOsPrinter) Data() [][]string {
+ if len(i.ISOs) == 0 {
+ return [][]string{0: {"---", "---", "---"}}
+ }
+
+ var data [][]string
+ for n := range i.ISOs {
+ data = append(data, []string{
+ i.ISOs[n].ID,
+ i.ISOs[n].Name,
+ i.ISOs[n].Description,
+ })
+ }
+
+ return data
+}
+
+// Paging ...
+func (i *PublicISOsPrinter) Paging() [][]string {
+ return printer.NewPaging(i.Meta.Total, &i.Meta.Links.Next, &i.Meta.Links.Prev).Compose()
+}
diff --git a/cmd/kubernetes/kubernetes.go b/cmd/kubernetes/kubernetes.go
new file mode 100644
index 00000000..8b06a038
--- /dev/null
+++ b/cmd/kubernetes/kubernetes.go
@@ -0,0 +1,1143 @@
+// Package kubernetes provides functionality for the CLI to control VKE clusters
+package kubernetes
+
+import (
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "github.com/spf13/cobra"
+ "github.com/vultr/govultr/v3"
+ "github.com/vultr/vultr-cli/v3/cmd/printer"
+ "github.com/vultr/vultr-cli/v3/cmd/utils"
+ "github.com/vultr/vultr-cli/v3/pkg/cli"
+)
+
+var (
+ long = `Get all available commands for Kubernetes`
+ example = `
+ # Full example
+ vultr-cli kubernetes
+ `
+
+ createLong = `Create kubernetes cluster on your Vultr account`
+ createExample = `
+ # Full Example
+ vultr-cli kubernetes create --label="my-cluster" --region="ewr" --version="v1.29.1+1" \
+ --node-pools="quantity:3,plan:vc2-2c-4gb,label:my-nodepool,tag:my-tag"
+
+ # Shortened with alias commands
+ vultr-cli k c -l="my-cluster" -r="ewr" -v="v1.29.1+1" -n="quantity:3,plan:vc2-2c-4gb,label:my-nodepool,tag:my-tag"
+ `
+
+ getLong = `Get a single kubernetes cluster from your account`
+ getExample = `
+ # Full example
+ vultr-cli kubernetes get ffd31f18-5f77-454c-9064-212f942c3c34
+
+ # Shortened with alias commands
+ vultr-cli k g ffd31f18-5f77-454c-9064-212f942c3c34
+ `
+
+ listLong = `Get all kubernetes clusters available on your Vultr account`
+ listExample = `
+ # Full example
+ vultr-cli kubernetes list
+
+ # Full example with paging
+ vultr-cli kubernetes list --per-page=1 --cursor="bmV4dF9fQU1T"
+
+ # Shortened with alias commands
+ vultr-cli k l
+
+ # Summarized view
+ vultr-cli kubernetes list --summarize
+ `
+
+ updateLong = `Update a specific kubernetes cluster on your Vultr Account`
+ updateExample = `
+ # Full example
+ vultr-cli kubernetes update ffd31f18-5f77-454c-9065-212f942c3c35 --label="updated-label"
+
+ # Shortened with alias commands
+ vultr-cli k u ffd31f18-5f77-454c-9065-212f942c3c35 -l="updated-label"
+ `
+
+ deleteLong = `Delete a specific kubernetes cluster off your Vultr Account`
+ deleteExample = `
+ # Full example
+ vultr-cli kubernetes delete ffd31f18-5f77-454c-9065-212f942c3c35
+
+ # Shortened with alias commands
+ vultr-cli k d ffd31f18-5f77-454c-9065-212f942c3c35'
+
+ # Delete a specific kubernetes cluster and all linked load balancers and block storages off your Vultr Account
+ vultr-cli kubernetes delete-with-resources ffd31f18-5f77-454c-9065-212f942c3c35
+ `
+ getConfigLong = `Returns a base64 encoded config of a specified kubernetes cluster on your Vultr Account`
+ getConfigExample = `
+
+ # Full example
+ vultr-cli kubernetes config ffd31f18-5f77-454c-9065-212f942c3c35
+ vultr-cli kubernetes config ffd31f18-5f77-454c-9065-212f942c3c35 --output-file /your/path/
+
+ # Shortened with alias commands
+ vultr-cli k config ffd31f18-5f77-454c-9065-212f942c3c35
+ vultr-cli k config ffd31f18-5f77-454c-9065-212f942c3c35 -o /your/path/
+ `
+
+ getVersionsLong = `Returns a list of supported kubernetes versions you can deploy`
+ getVersionsExample = `
+ # Full example
+ vultr-cli kubernetes versions
+
+ # Shortened with alias commands
+ vultr-cli k v
+ `
+
+ upgradesLong = `Display available kubernetes upgrade commands`
+ upgradesExample = `
+ # Full example
+ vultr-cli kubernetes upgrades
+
+ # Shortened example with aliases
+ vultr-cli k e
+ `
+
+ getUpgradesLong = `Returns a list of available kubernetes version the cluster can be upgraded to`
+ getUpgradesExample = `
+ # Full example
+ vultr-cli kubernetes upgrades list d4908765-b82a-4e7d-83d9-c0bc4c6a36d0
+
+ # Shortened with alias commands
+ vultr-cli k e l d4908765-b82a-4e7d-83d9-c0bc4c6a36d0
+ `
+
+ upgradeLong = `Initiate an upgrade of the kubernetes version on a given cluster`
+ upgradeExample = `
+ # Full example
+ vultr-cli kubernetes upgrades start d4908765-b82a-4e7d-83d9-c0bc4c6a36d0 --version="v1.23.5+3"
+
+ # Shortened with alias commands
+ vultr-cli k e s d4908765-b82a-4e7d-83d9-c0bc4c6a36d0 -v="v1.23.5+3"
+ `
+
+ nodepoolLong = `Get all available commands for Kubernetes node pools`
+ nodepoolExample = `
+ # Full example
+ vultr-cli kubernetes node-pool
+
+ # Shortened with alias commands
+ vultr-cli k n
+ `
+
+ createNPLong = `Create node pool for your kubernetes cluster on your Vultr account`
+ createNPExample = `
+ # Full Example
+ vultr-cli kubernetes node-pool create ffd31f18-5f77-454c-9064-212f942c3c34 --label="nodepool" --quantity=3 --plan="vc2-1c-2gb"
+
+ # Shortened with alias commands
+ vultr-cli k n c ffd31f18-5f77-454c-9064-212f942c3c34 -l="nodepool" -q=3 -p="vc2-1c-2gb"
+ `
+
+ getNPLong = `Get a node pool in a single kubernetes cluster from your account`
+ getNPExample = `
+ # Full example
+ vultr-cli kubernetes node-pool get ffd31f18-5f77-454c-9064-212f942c3c34 abd31f18-3f77-454c-9064-212f942c3c34
+ # Shortened with alias commands
+ vultr-cli k n g ffd31f18-5f77-454c-9064-212f942c3c34 abd31f18-3f77-454c-9064-212f942c3c34
+ `
+
+ listNPLong = `Get all nodepools from a kubernetes cluster on your Vultr account`
+ listNPExample = `
+ # Full example
+ vultr-cli kubernetes node-pool list ffd31f18-5f77-454c-9064-212f942c3c34
+
+ # Full example with paging
+ vultr-cli kubernetes node-pool list ffd31f18-5f77-454c-9064-212f942c3c34 --per-page=1 --cursor="bmV4dF9fQU1T"
+
+ # Shortened with alias commands
+ vultr-cli k n l ffd31f18-5f77-454c-9064-212f942c3c34
+ `
+
+ updateNPLong = `Update a specific node pool in a kubernetes cluster on your Vultr Account`
+ updateNPExample = `
+ # Full example
+ vultr-cli kubernetes node-pool update ffd31f18-5f77-454c-9064-212f942c3c34 abd31f18-3f77-454c-9064-212f942c3c34 --quantity=4
+
+ # Shortened with alias commands
+ vultr-cli k n u ffd31f18-5f77-454c-9065-212f942c3c35 abd31f18-3f77-454c-9064-212f942c3c34 --q=4
+ `
+
+ deleteNPLong = `Delete a specific node pool in a kubernetes cluster off your Vultr Account`
+ deleteNPExample = `
+ # Full example
+ vultr-cli kubernetes node-pool delete ffd31f18-5f77-454c-9065-212f942c3c35 abd31f18-3f77-454c-9064-212f942c3c34
+
+ # Shortened with alias commands
+ vultr-cli k n d ffd31f18-5f77-454c-9065-212f942c3c35 abd31f18-3f77-454c-9064-212f942c3c34'
+ `
+
+ nodeLong = `Get all available commands for Kubernetes node pool nodes`
+ nodeExample = `
+ # Full example
+ vultr-cli kubernetes node-pool node
+
+ # Shortened with alias commands
+ vultr-cli k n node
+ `
+
+ nodeDeleteLong = `Delete a specific node pool node in a kubernetes cluster`
+ nodeDeleteExample = `
+ # Full example
+ vultr-cli kubernetes node-pool node delete ffd31f18-5f77-454c-9065-212f942c3c35
+
+ # Shortened with alias commands
+ vultr-cli k n node d ffd31f18-5f77-454c-9065-212f942c3c35
+ `
+
+ nodeRecycleLong = `Recycles a specific node pool node in a kubernetes cluster`
+ nodeRecycleExample = `
+ # Full example
+ vultr-cli kubernetes node-pool node recycle ffd31f18-5f77-454c-9065-212f942c3c35
+
+ # Shortened with alias commands
+ vultr-cli k n node r ffd31f18-5f77-454c-9065-212f942c3c35
+ `
+)
+
+const (
+ kubeconfigFilePermission = 0600
+ kubeconfigDirPermission = 0755
+)
+
+// NewCmdKubernetes provides the CLI command for VKE functions
+func NewCmdKubernetes(base *cli.Base) *cobra.Command { //nolint:funlen,gocyclo
+ o := &options{Base: base}
+
+ cmd := &cobra.Command{
+ Use: "kubernetes",
+ Aliases: []string{"k"},
+ Short: "Access kubernetes cluster commands",
+ Long: long,
+ Example: example,
+ PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+ utils.SetOptions(o.Base, cmd, args)
+ if !o.Base.HasAuth {
+ return errors.New(utils.APIKeyError)
+ }
+ return nil
+ },
+ }
+
+ // List
+ list := &cobra.Command{
+ Use: "list",
+ Short: "List kubernetes clusters",
+ Aliases: []string{"l"},
+ Long: listLong,
+ Example: listExample,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ o.Base.Options = utils.GetPaging(cmd)
+
+ summarize, errSu := cmd.Flags().GetBool("summarize")
+ if errSu != nil {
+ return fmt.Errorf("error parsing flag 'summarize' for kubernetes list : %v", errSu)
+ }
+
+ k8s, meta, err := o.list()
+ if err != nil {
+ return fmt.Errorf("error retrieving kubernetes clusters list : %v", err)
+ }
+
+ var data printer.ResourceOutput
+ if summarize {
+ data = &ClustersSummaryPrinter{Clusters: k8s, Meta: meta}
+ } else {
+ data = &ClustersPrinter{Clusters: k8s, Meta: meta}
+ }
+
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ list.Flags().StringP("cursor", "c", "", "(optional) cursor for paging.")
+ list.Flags().IntP(
+ "per-page",
+ "p",
+ utils.PerPageDefault,
+ fmt.Sprintf("(optional) Number of items requested per page. Default is %d and Max is 500.", utils.PerPageDefault),
+ )
+ list.Flags().BoolP("summarize", "", false, "(optional) Summarize the list output. One line per cluster.")
+
+ // Get
+ get := &cobra.Command{
+ Use: "get ",
+ Short: "Retrieves a kubernetes cluster",
+ Long: getLong,
+ Example: getExample,
+ Aliases: []string{"g"},
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) < 1 {
+ return errors.New("please provide a cluster ID")
+ }
+ return nil
+ },
+ RunE: func(cmd *cobra.Command, args []string) error {
+ k8, err := o.get()
+ if err != nil {
+ return fmt.Errorf("error retrieving kubernetes cluster : %v", err)
+ }
+
+ data := &ClusterPrinter{Cluster: k8}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ // Create
+ create := &cobra.Command{
+ Use: "create",
+ Short: "Create kubernetes cluster",
+ Long: createLong,
+ Example: createExample,
+ Aliases: []string{"c"},
+ RunE: func(cmd *cobra.Command, args []string) error {
+ label, errLa := cmd.Flags().GetString("label")
+ if errLa != nil {
+ return fmt.Errorf("error parsing flag 'label' for kubernetes cluster create : %v", errLa)
+ }
+
+ region, errRe := cmd.Flags().GetString("region")
+ if errRe != nil {
+ return fmt.Errorf("error parsing flag 'region' for kubernetes cluster create : %v", errRe)
+ }
+
+ nodepools, errNP := cmd.Flags().GetStringArray("node-pools")
+ if errNP != nil {
+ return fmt.Errorf("error parsing flag 'node-pools' for kubernetes cluster create : %v", errNP)
+ }
+
+ version, errVe := cmd.Flags().GetString("version")
+ if errVe != nil {
+ return fmt.Errorf("error parsing flag 'version' for kubernetes cluster create : %v", errVe)
+ }
+
+ ha, errHi := cmd.Flags().GetBool("high-avail")
+ if errHi != nil {
+ return fmt.Errorf("error parsing flag 'high-avail' for kubernetes cluster create : %v", errHi)
+ }
+
+ nps, errFm := formatNodePools(nodepools)
+ if errFm != nil {
+ return fmt.Errorf("error in node pool formating : %v", errFm)
+ }
+
+ o.CreateReq = &govultr.ClusterReq{
+ Label: label,
+ Region: region,
+ NodePools: nps,
+ Version: version,
+ HAControlPlanes: ha,
+ }
+
+ k8, err := o.create()
+ if err != nil {
+ return fmt.Errorf("error creating kubernetes cluster : %v", err)
+ }
+
+ data := &ClusterPrinter{Cluster: k8}
+ o.Base.Printer.Display(data, nil)
+
+ return nil
+ },
+ }
+
+ create.Flags().StringP("label", "l", "", "label for your kubernetes cluster")
+ if err := create.MarkFlagRequired("label"); err != nil {
+ fmt.Printf("error marking kubernetes create 'label' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ create.Flags().StringP("region", "r", "", "region you want your kubernetes cluster to be located in")
+ if err := create.MarkFlagRequired("region"); err != nil {
+ fmt.Printf("error marking kubernetes create 'region' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ create.Flags().StringP("version", "v", "", "the kubernetes version you want for your cluster")
+ if err := create.MarkFlagRequired("version"); err != nil {
+ fmt.Printf("error marking kubernetes create 'version' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ create.Flags().Bool(
+ "high-avail",
+ false,
+ `(optional, default false) whether or not the cluster should be deployed with multiple,
+highly available, control planes`,
+ )
+
+ create.Flags().StringArrayP(
+ "node-pools",
+ "n",
+ []string{},
+ `a comma-separated, key-value pair list of node pools. At least one node pool is required. At least one node is
+required in node pool. Use / between each new node pool. E.g:
+'plan:vhf-8c-32gb,label:mynodepool,tag:my-tag,quantity:3/plan:vhf-8c-32gb,label:mynodepool2,quantity:3`,
+ )
+ if err := create.MarkFlagRequired("node-pools"); err != nil {
+ fmt.Printf("error marking kubernetes create 'ns-primary' flag required: %v", err)
+ os.Exit(1)
+ }
+
+ // Update
+ update := &cobra.Command{
+ Use: "update