├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── review.yml │ ├── notify-pr.yml │ ├── notify-issue.yml │ ├── gochecks.yml │ └── releaser.yml ├── Dockerfile.goreleaser ├── main.go ├── cmd ├── printer │ ├── info.go │ ├── error.go │ ├── message.go │ ├── marketplace.go │ └── printer.go ├── utils │ ├── errors.go │ ├── timestamp.go │ ├── paging.go │ └── utils.go ├── version │ ├── printer.go │ └── version.go ├── userdata │ └── printer.go ├── marketplace │ ├── printer.go │ └── marketplace.go ├── operatingsystems │ ├── printer.go │ └── operatingsystems.go ├── applications │ ├── printer.go │ └── applications.go ├── sshkeys │ ├── printer.go │ └── sshKeys.go ├── logs │ ├── printer.go │ └── logs.go ├── users │ └── printer.go ├── backups │ ├── printer.go │ └── backups.go ├── script │ ├── printer.go │ └── script.go ├── ip │ └── printer.go ├── vpc │ ├── printer.go │ └── vpc.go ├── reservedip │ └── printer.go ├── snapshot │ ├── printer.go │ └── snapshot.go ├── account │ ├── account.go │ └── printer.go ├── blockstorage │ └── printer.go ├── regions │ ├── printer.go │ └── regions.go ├── iso │ ├── printer.go │ └── iso.go ├── inference │ ├── printer.go │ └── inference.go ├── vpc2 │ └── printer.go ├── plans │ ├── printer.go │ └── plans.go ├── firewall │ └── printer.go ├── billing │ ├── printer.go │ └── billing.go ├── root.go ├── dns │ └── printer.go ├── baremetal │ └── printer.go └── objectstorage │ └── printer.go ├── scripts └── entrypoint.sh ├── .gitignore ├── Dockerfile ├── NOTICE ├── Makefile ├── go.mod ├── CONTRIBUTING.md ├── pkg └── cli │ └── cli.go ├── .goreleaser.yml ├── .golangci.yaml ├── go.sum └── README.md /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @optik-aper 2 | -------------------------------------------------------------------------------- /Dockerfile.goreleaser: -------------------------------------------------------------------------------- 1 | FROM alpine:3.12 2 | 3 | RUN apk add --no-cache ca-certificates 4 | COPY vultr-cli . 5 | ENTRYPOINT ["./vultr-cli"] -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Package main provides the main command 2 | package main 3 | 4 | import "github.com/vultr/vultr-cli/v3/cmd" 5 | 6 | func main() { 7 | cmd.Execute() 8 | } 9 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | -------------------------------------------------------------------------------- /cmd/printer/info.go: -------------------------------------------------------------------------------- 1 | package printer 2 | 3 | // Info intializes and returns a Message resource output struct 4 | func Info(msg string) *Message { 5 | return &Message{Message: msg} 6 | } 7 | -------------------------------------------------------------------------------- /scripts/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ -n "$DOCKER_USERNAME" ] && [ -n "$DOCKER_PASSWORD" ]; then 4 | echo "Login to the docker..." 5 | echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin $DOCKER_REGISTRY 6 | fi -------------------------------------------------------------------------------- /.github/workflows/review.yml: -------------------------------------------------------------------------------- 1 | name: AI PR Review 2 | on: 3 | pull_request_target: 4 | types: [opened, reopened, ready_for_review] 5 | issue_comment: 6 | jobs: 7 | pr_agent_job: 8 | if: ${{ github.event.sender.type != 'Bot' }} 9 | uses: vultr/shared-actions/.github/workflows/review.yml@main 10 | secrets: inherit 11 | -------------------------------------------------------------------------------- /cmd/printer/error.go: -------------------------------------------------------------------------------- 1 | package printer 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func Error(err error) { 9 | // TODO make errors uniform 10 | // t := errorToStruct(err) 11 | 12 | col := columns{"ERROR MESSAGE", "STATUS CODE"} 13 | display(col) 14 | // display(columns{t.Error, t.Status}) 15 | fmt.Printf("%v", err) 16 | flush() 17 | 18 | os.Exit(1) 19 | } 20 | -------------------------------------------------------------------------------- /cmd/utils/errors.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | const ( 4 | // APIKeyError is the error used when missing the API key on commands which 5 | // require it 6 | //nolint:gosec 7 | APIKeyError string = ` 8 | Please export your VULTR API key as an environment variable or add 'api-key' to your config file, eg: 9 | export VULTR_API_KEY='' 10 | ` 11 | ) 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Go ### 2 | # Binaries for programs and plugins 3 | vultr-cli 4 | *.exe 5 | *.exe~ 6 | *.dll 7 | *.so 8 | *.dylib 9 | 10 | # Test binary, built with `go test -c` 11 | *.test 12 | 13 | # Output of the go coverage tool, specifically when used with LiteIDE 14 | *.out 15 | 16 | ### Go Patch ### 17 | /Godeps/ 18 | 19 | 20 | .DS_STORE 21 | .vscode/ 22 | .idea 23 | builds/ 24 | dist/ 25 | vendor/ 26 | -------------------------------------------------------------------------------- /cmd/utils/timestamp.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "time" 7 | ) 8 | 9 | func ParseAPITimestamp(ts string) string { 10 | var tsTime time.Time 11 | tsInt, err := strconv.Atoi(ts) 12 | if err != nil { 13 | tsTime = time.Time{} 14 | } else { 15 | tsTime = time.Unix(int64(tsInt), 0) 16 | } 17 | 18 | tsYear, tsMonth, tsDay := tsTime.Date() 19 | return fmt.Sprintf("%d-%02d-%02d", tsYear, int(tsMonth), tsDay) 20 | } 21 | -------------------------------------------------------------------------------- /cmd/utils/paging.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "github.com/vultr/govultr/v3" 6 | ) 7 | 8 | func GetPaging(cmd *cobra.Command) *govultr.ListOptions { 9 | options := &govultr.ListOptions{} 10 | 11 | cursor, _ := cmd.Flags().GetString("cursor") 12 | perPage, _ := cmd.Flags().GetInt("per-page") 13 | 14 | if cursor != "" { 15 | options.Cursor = cursor 16 | } 17 | 18 | if perPage != 0 { 19 | options.PerPage = perPage 20 | } 21 | 22 | return options 23 | } 24 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.21-alpine as builder 2 | 3 | RUN apk add --update \ 4 | make 5 | 6 | ENV CGO_ENABLED 0 7 | 8 | RUN mkdir -p /out 9 | RUN mkdir -p /go/src/github.com/vultr/vultr-cli 10 | ADD . /go/src/github.com/vultr/vultr-cli 11 | 12 | RUN cd /go/src/github.com/vultr/vultr-cli && \ 13 | make builds/vultr-cli_linux_amd64 14 | 15 | 16 | FROM alpine:latest 17 | RUN apk add --no-cache ca-certificates 18 | 19 | COPY --from=builder /go/src/github.com/vultr/vultr-cli/builds/* / 20 | ENTRYPOINT ["/vultr-cli_linux_amd64"] 21 | -------------------------------------------------------------------------------- /.github/workflows/notify-pr.yml: -------------------------------------------------------------------------------- 1 | name: notify-pr 2 | 3 | on: pull_request_target 4 | 5 | jobs: 6 | pr: 7 | runs-on: ubuntu-latest 8 | name: Pull Request Notification 9 | steps: 10 | - uses: mattermost/action-mattermost-notify@2.0.0 11 | with: 12 | MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }} 13 | MATTERMOST_USERNAME: ${{ secrets.MATTERMOST_USERNAME}} 14 | MATTERMOST_ICON_URL: ${{ secrets.MATTERMOST_ICON }} 15 | TEXT: "${{ github.repository }} : PR https://github.com/${{ github.repository }}/pull/${{ github.event.number }}" 16 | -------------------------------------------------------------------------------- /.github/workflows/notify-issue.yml: -------------------------------------------------------------------------------- 1 | name: notify-issue 2 | 3 | on: 4 | issues: 5 | types: [opened] 6 | 7 | jobs: 8 | issue: 9 | runs-on: ubuntu-latest 10 | name: New Issue Notification 11 | steps: 12 | - uses: mattermost/action-mattermost-notify@2.0.0 13 | with: 14 | MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }} 15 | MATTERMOST_USERNAME: ${{ secrets.MATTERMOST_USERNAME}} 16 | MATTERMOST_ICON_URL: ${{ secrets.MATTERMOST_ICON }} 17 | TEXT: "${{ github.repository }}: New Issue https://github.com/${{ github.repository }}/issues/${{ github.event.issue.number }}" 18 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Vultr-CLI 2 | Copyright © 2024 Vultr 3 | 4 | This product includes software developed at Vultr 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | -------------------------------------------------------------------------------- /cmd/printer/message.go: -------------------------------------------------------------------------------- 1 | package printer 2 | 3 | // Message provides generic output for the CLI 4 | type Message struct { 5 | Message string `json:"message"` 6 | } 7 | 8 | // JSON ... 9 | func (m *Message) JSON() []byte { 10 | return MarshalObject(m, "json") 11 | } 12 | 13 | // YAML ... 14 | func (m *Message) YAML() []byte { 15 | return MarshalObject(m, "yaml") 16 | } 17 | 18 | // Columns ... 19 | func (m *Message) Columns() [][]string { 20 | return [][]string{0: {"MESSAGE"}} 21 | } 22 | 23 | // Data ... 24 | func (m *Message) Data() [][]string { 25 | return [][]string{0: {m.Message}} 26 | } 27 | 28 | // Paging ... 29 | func (m *Message) Paging() [][]string { 30 | return nil 31 | } 32 | -------------------------------------------------------------------------------- /cmd/printer/marketplace.go: -------------------------------------------------------------------------------- 1 | package printer 2 | 3 | import ( 4 | "github.com/vultr/govultr/v3" 5 | ) 6 | 7 | // MarketplaceAppVariableList will generate a printer display of user-supplied variables for a Vultr Marketplace app 8 | func MarketplaceAppVariableList(appVariables []govultr.MarketplaceAppVariable) { 9 | defer flush() 10 | 11 | if len(appVariables) == 0 { 12 | displayString("This app contains no user-supplied variables") 13 | return 14 | } 15 | 16 | for p := range appVariables { 17 | display(columns{"NAME", appVariables[p].Name}) 18 | display(columns{"DESCRIPTION", appVariables[p].Description}) 19 | display(columns{"TYPE", *appVariables[p].Required}) 20 | display(columns{"---------------------------"}) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cmd/version/printer.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import ( 4 | "github.com/vultr/vultr-cli/v3/cmd/printer" 5 | ) 6 | 7 | // VersionPrinter represents the version data 8 | type VersionPrinter struct { 9 | Version string `json:"version"` 10 | } 11 | 12 | // JSON ... 13 | func (v *VersionPrinter) JSON() []byte { 14 | return printer.MarshalObject(v, "json") 15 | } 16 | 17 | // YAML ... 18 | func (v *VersionPrinter) YAML() []byte { 19 | return printer.MarshalObject(v, "yaml") 20 | } 21 | 22 | // Columns ... 23 | func (v *VersionPrinter) Columns() [][]string { 24 | return nil 25 | } 26 | 27 | // Data ... 28 | func (v *VersionPrinter) Data() [][]string { 29 | return [][]string{0: {v.Version}} 30 | } 31 | 32 | // Paging ... 33 | func (v *VersionPrinter) Paging() [][]string { 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /cmd/utils/utils.go: -------------------------------------------------------------------------------- 1 | // Package utils provides some common utility functions 2 | package utils 3 | 4 | import ( 5 | "fmt" 6 | 7 | "github.com/spf13/cobra" 8 | "github.com/spf13/viper" 9 | "github.com/vultr/vultr-cli/v3/pkg/cli" 10 | ) 11 | 12 | const ( 13 | PerPageDefault int = 100 14 | FloatPrecision int = 2 15 | FloatBitDepth int = 32 16 | ) 17 | 18 | // SetOptions initializes values used in all CLI commands 19 | func SetOptions(b *cli.Base, cmd *cobra.Command, args []string) { 20 | b.Args = args 21 | b.Printer.Output = viper.GetString("output") 22 | } 23 | 24 | // GetFirewallSource parses the source and if empty, returns 'anywhere' 25 | func GetFirewallSource(source string) string { 26 | if source == "" { 27 | return "anywhere" 28 | } 29 | return source 30 | } 31 | 32 | // FormatFirewallNetwork returns the subnet and size of a network in CIDR 33 | // notation 34 | func FormatFirewallNetwork(subnet string, size int) string { 35 | return fmt.Sprintf("%s/%d", subnet, size) 36 | } 37 | -------------------------------------------------------------------------------- /.github/workflows/gochecks.yml: -------------------------------------------------------------------------------- 1 | name: Checks 2 | on: 3 | pull_request: 4 | branches: 5 | - master 6 | jobs: 7 | Golangci-Lint: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | - name: Setup Go 12 | uses: actions/setup-go@v5 13 | with: 14 | go-version: "1.24" 15 | - name: Run golangci-lint 16 | uses: golangci/golangci-lint-action@v8 17 | with: 18 | version: "v2.1.0" 19 | args: "cmd/..." 20 | Go-Fmt: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v4 24 | - name: Setup Go 25 | uses: actions/setup-go@v5 26 | with: 27 | go-version: "1.24" 28 | - name: Run fmt 29 | run: | 30 | gofmt_files=$(gofmt -l cmd) 31 | if [[ -n ${gofmt_files} ]]; then 32 | echo 'gofmt needs running on the following files:' 33 | echo "${gofmt_files}" 34 | exit 1 35 | fi 36 | exit 0 37 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: remove format 2 | 3 | export CGO=0 4 | export GOFLAGS=-trimpath 5 | 6 | DIR?=builds 7 | 8 | $(DIR): 9 | mkdir -p $(DIR) 10 | 11 | $(DIR)/vultr-cli_darwin_amd64: $(DIR) 12 | env GOOS=darwin GOARCH=amd64 go build -o $@ 13 | 14 | $(DIR)/vultr-cli_darwin_arm64: $(DIR) 15 | env GOOS=darwin GOARCH=arm64 go build -o $@ 16 | 17 | $(DIR)/vultr-cli_linux_386: $(DIR) 18 | env GOOS=linux GOARCH=386 go build -o $@ 19 | 20 | $(DIR)/vultr-cli_linux_amd64: $(DIR) 21 | env GOOS=linux GOARCH=amd64 go build -o $@ 22 | 23 | $(DIR)/vultr-cli_linux_arm64: $(DIR) 24 | env GOOS=linux GOARCH=arm64 go build -o $@ 25 | 26 | $(DIR)/vultr-cli_windows_386.exe: $(DIR) 27 | env GOOS=windows GOARCH=386 go build -o $@ 28 | 29 | $(DIR)/vultr-cli_windows_amd64.exe: $(DIR) 30 | env GOOS=windows GOARCH=amd64 go build -o $@ 31 | 32 | $(DIR)/vultr-cli_linux_arm: $(DIR) 33 | env GOOS=linux GOARCH=arm go build -o $@ 34 | 35 | remove: 36 | @rm -rf builds 37 | 38 | format: 39 | @go fmt ./... 40 | 41 | docker: 42 | docker build . -t vultr/vultr-cli 43 | docker push vultr/vultr-cli 44 | -------------------------------------------------------------------------------- /cmd/version/version.go: -------------------------------------------------------------------------------- 1 | // Package version provides functionality to display the CLI version 2 | package version 3 | 4 | import ( 5 | "fmt" 6 | 7 | "github.com/spf13/cobra" 8 | "github.com/vultr/vultr-cli/v3/pkg/cli" 9 | ) 10 | 11 | const ( 12 | Version string = "v3.8.0" 13 | ) 14 | 15 | var ( 16 | long = `Displays current version of the Vultr-CLI` 17 | 18 | example = ` 19 | # example 20 | vultr-cli version 21 | 22 | # Shortened with alias commands 23 | vultr-cli v 24 | ` 25 | ) 26 | 27 | // NewCmdVersion returns cobra command for version 28 | func NewCmdVersion(base *cli.Base) *cobra.Command { 29 | o := &options{Base: base} 30 | 31 | cmd := &cobra.Command{ 32 | Use: "version", 33 | Short: "Display the vultr-cli version", 34 | Aliases: []string{"v"}, 35 | Long: long, 36 | Example: example, 37 | Run: func(cmd *cobra.Command, args []string) { 38 | o.Base.Printer.Display(&VersionPrinter{Version: o.get()}, nil) 39 | }, 40 | } 41 | 42 | return cmd 43 | } 44 | 45 | type options struct { 46 | Base *cli.Base 47 | Version string 48 | } 49 | 50 | func (o *options) get() string { 51 | return fmt.Sprintf("Vultr-CLI %s", Version) 52 | } 53 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/vultr/vultr-cli/v3 2 | 3 | go 1.24.0 4 | 5 | require ( 6 | github.com/spf13/cobra v1.10.1 7 | github.com/spf13/viper v1.21.0 8 | github.com/vultr/govultr/v3 v3.25.0 9 | golang.org/x/oauth2 v0.33.0 10 | gopkg.in/yaml.v3 v3.0.1 11 | ) 12 | 13 | require ( 14 | github.com/fsnotify/fsnotify v1.9.0 // indirect 15 | github.com/go-viper/mapstructure/v2 v2.4.0 // indirect 16 | github.com/google/go-querystring v1.1.0 // indirect 17 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 18 | github.com/hashicorp/go-retryablehttp v0.7.8 // indirect 19 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 20 | github.com/pelletier/go-toml/v2 v2.2.4 // indirect 21 | github.com/sagikazarmark/locafero v0.11.0 // indirect 22 | github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect 23 | github.com/spf13/afero v1.15.0 // indirect 24 | github.com/spf13/cast v1.10.0 // indirect 25 | github.com/spf13/pflag v1.0.10 // indirect 26 | github.com/subosito/gotenv v1.6.0 // indirect 27 | go.yaml.in/yaml/v3 v3.0.4 // indirect 28 | golang.org/x/sys v0.29.0 // indirect 29 | golang.org/x/text v0.28.0 // indirect 30 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect 31 | ) 32 | -------------------------------------------------------------------------------- /cmd/userdata/printer.go: -------------------------------------------------------------------------------- 1 | // Package userdata provides a printer for server user data 2 | package userdata 3 | 4 | import ( 5 | "encoding/base64" 6 | "fmt" 7 | 8 | "github.com/vultr/govultr/v3" 9 | "github.com/vultr/vultr-cli/v3/cmd/printer" 10 | ) 11 | 12 | // UserDataPrinter ... 13 | type UserDataPrinter struct { 14 | UserData govultr.UserData `json:"user_data"` 15 | } 16 | 17 | // JSON ... 18 | func (u *UserDataPrinter) JSON() []byte { 19 | return printer.MarshalObject(u, "json") 20 | } 21 | 22 | // YAML ... 23 | func (u *UserDataPrinter) YAML() []byte { 24 | return printer.MarshalObject(u, "yaml") 25 | } 26 | 27 | // Columns ... 28 | func (u *UserDataPrinter) Columns() [][]string { 29 | return [][]string{0: { 30 | "USERDATA", 31 | }} 32 | } 33 | 34 | // Data ... 35 | func (u *UserDataPrinter) Data() [][]string { 36 | ud, err := base64.StdEncoding.DecodeString(u.UserData.Data) 37 | if err != nil { 38 | printer.Error(fmt.Errorf("error decoding base64 user data : %v", err)) 39 | } 40 | 41 | if len(ud) == 0 { 42 | return [][]string{0: {"None"}} 43 | } 44 | 45 | return [][]string{0: { 46 | string(ud), 47 | }} 48 | } 49 | 50 | // Paging ... 51 | func (u *UserDataPrinter) Paging() [][]string { 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /cmd/marketplace/printer.go: -------------------------------------------------------------------------------- 1 | package marketplace 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | "github.com/vultr/vultr-cli/v3/cmd/printer" 8 | ) 9 | 10 | // VariablesPrinter ... 11 | type VariablesPrinter struct { 12 | Variables []govultr.MarketplaceAppVariable `json:"variables"` 13 | } 14 | 15 | // JSON ... 16 | func (v *VariablesPrinter) JSON() []byte { 17 | return printer.MarshalObject(v, "json") 18 | } 19 | 20 | // YAML ... 21 | func (v *VariablesPrinter) YAML() []byte { 22 | return printer.MarshalObject(v, "yaml") 23 | } 24 | 25 | // Columns ... 26 | func (v *VariablesPrinter) Columns() [][]string { 27 | return [][]string{0: { 28 | "NAME", 29 | "DESCRIPTION", 30 | "REQUIRED", 31 | }} 32 | } 33 | 34 | // Data ... 35 | func (v *VariablesPrinter) Data() [][]string { 36 | if len(v.Variables) == 0 { 37 | return [][]string{0: {"---", "---", "---"}} 38 | } 39 | 40 | var data [][]string 41 | for i := range v.Variables { 42 | data = append(data, []string{ 43 | v.Variables[i].Name, 44 | v.Variables[i].Description, 45 | strconv.FormatBool(*v.Variables[i].Required), 46 | }) 47 | } 48 | 49 | return data 50 | } 51 | 52 | // Paging ... 53 | func (v *VariablesPrinter) Paging() [][]string { 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to `vultr-cli` 2 | 3 | We would love to get your feedback, thoughts, and overall improvements to `vultr-cli`! 4 | 5 | ## Overview 6 | 7 | - All Code should run through `go fmt` 8 | 9 | ## Getting started 10 | 11 | Vultr-cli supports `go modules` so you can pull down the repo outside of your `$GOPATH`. 12 | 13 | You can also run: 14 | `go get -u github.com/vultr/vultr-cli` 15 | 16 | ## Versioning 17 | 18 | Vultr-cli follows [SemVer](http://semver.org/) for versioning. New functionality will result in a increment to the minor version. While, 19 | bug fixes will result in a increment to the patch version. 20 | 21 | ## Releases 22 | Releases of new versions are done as their independent pull requests - They will also be done by the maintainers. 23 | 24 | To release a new version of `vultr-cli` we must do the following. 25 | 26 | - Make the appropriate updates to `CHANGELOG.md`. This should include the 27 | - Version, 28 | - List of fix/features with accompanying pull request ID 29 | - Description of each fix/feature 30 | 31 | ``` 32 | ## v0.0.1 (2019-06-12) 33 | 34 | ### Fixes 35 | * Fixed random bug #12 36 | ``` 37 | - Submit a pull request with the following changes 38 | - Once the pull request is merged in - create a new tag and publish. 39 | -------------------------------------------------------------------------------- /cmd/operatingsystems/printer.go: -------------------------------------------------------------------------------- 1 | package operatingsystems 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | "github.com/vultr/vultr-cli/v3/cmd/printer" 8 | ) 9 | 10 | // OSPrinter represents the plans data from the API 11 | type OSPrinter struct { 12 | OperatingSystems []govultr.OS `json:"os"` 13 | Meta *govultr.Meta `json:"meta"` 14 | } 15 | 16 | // JSON provides the JSON formatted byte data 17 | func (o *OSPrinter) JSON() []byte { 18 | return printer.MarshalObject(o, "json") 19 | } 20 | 21 | // YAML provides the YAML formatted byte data 22 | func (o *OSPrinter) YAML() []byte { 23 | return printer.MarshalObject(o, "yaml") 24 | } 25 | 26 | // Columns provides the plan columns for the printer 27 | func (o *OSPrinter) Columns() [][]string { 28 | return [][]string{0: { 29 | "ID", 30 | "NAME", 31 | "ARCH", 32 | "FAMILY", 33 | }} 34 | } 35 | 36 | // Data provides the plan data for the printer 37 | func (o *OSPrinter) Data() [][]string { 38 | var data [][]string 39 | 40 | if len(o.OperatingSystems) == 0 { 41 | data = append(data, []string{"---", "---", "---", "---"}) 42 | return data 43 | } 44 | 45 | for i := range o.OperatingSystems { 46 | data = append(data, []string{ 47 | strconv.Itoa(o.OperatingSystems[i].ID), 48 | o.OperatingSystems[i].Name, 49 | o.OperatingSystems[i].Arch, 50 | o.OperatingSystems[i].Family, 51 | }) 52 | } 53 | 54 | return data 55 | } 56 | 57 | // Paging validates and forms the paging data for output 58 | func (o *OSPrinter) Paging() [][]string { 59 | return printer.NewPagingFromMeta(o.Meta).Compose() 60 | } 61 | -------------------------------------------------------------------------------- /pkg/cli/cli.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/spf13/viper" 8 | "github.com/vultr/govultr/v3" 9 | "github.com/vultr/vultr-cli/v3/cmd/printer" 10 | "golang.org/x/oauth2" 11 | ) 12 | 13 | // BaseInterface that is required for any struct that is used as a base 14 | type BaseInterface interface { 15 | configureClient(apiKey string) 16 | configurePrinter() 17 | } 18 | 19 | // Base contains the basic needs for all CLI commands 20 | type Base struct { 21 | Args []string 22 | Client *govultr.Client 23 | Options *govultr.ListOptions 24 | Printer *printer.Output 25 | Context context.Context 26 | HasAuth bool 27 | } 28 | 29 | // NewCLIBase creates new base struct 30 | func NewCLIBase(apiKey, userAgent, output string) *Base { 31 | base := new(Base) 32 | base.configurePrinter() 33 | base.configureClient(apiKey, userAgent) 34 | base.configureContext() 35 | return base 36 | } 37 | 38 | func (b *Base) configureClient(apiKey, userAgent string) { 39 | var token string 40 | b.HasAuth = false 41 | 42 | token = viper.GetString("api-key") 43 | if token == "" { 44 | token = apiKey 45 | } 46 | 47 | if token == "" { 48 | b.Client = govultr.NewClient(nil) 49 | } else { 50 | config := &oauth2.Config{} 51 | ts := config.TokenSource(context.Background(), &oauth2.Token{AccessToken: token}) 52 | b.Client = govultr.NewClient(oauth2.NewClient(context.Background(), ts)) 53 | b.HasAuth = true 54 | } 55 | 56 | b.Client.SetRateLimit(1 * time.Second) 57 | b.Client.SetUserAgent(userAgent) 58 | } 59 | 60 | func (b *Base) configurePrinter() { 61 | b.Printer = &printer.Output{} 62 | } 63 | 64 | func (b *Base) configureContext() { 65 | b.Context = context.Background() 66 | } 67 | -------------------------------------------------------------------------------- /cmd/applications/printer.go: -------------------------------------------------------------------------------- 1 | package applications 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | 8 | "github.com/vultr/vultr-cli/v3/cmd/printer" 9 | ) 10 | 11 | // ApplicationsPrinter represents the plans data from the API 12 | type ApplicationsPrinter struct { 13 | Applications []govultr.Application `json:"applications"` 14 | Meta *govultr.Meta `json:"meta"` 15 | } 16 | 17 | // JSON provides the JSON formatted byte data 18 | func (a *ApplicationsPrinter) JSON() []byte { 19 | return printer.MarshalObject(a, "json") 20 | } 21 | 22 | // YAML provides the YAML formatted byte data 23 | func (a *ApplicationsPrinter) YAML() []byte { 24 | return printer.MarshalObject(a, "yaml") 25 | } 26 | 27 | // Columns provides the plan columns for the printer 28 | func (a *ApplicationsPrinter) Columns() [][]string { 29 | return [][]string{0: { 30 | "ID", 31 | "NAME", 32 | "SHORT NAME", 33 | "DEPLOY NAME", 34 | "TYPE", 35 | "VENDOR", 36 | "IMAGE ID", 37 | }} 38 | } 39 | 40 | // Data provides the plan data for the printer 41 | func (a *ApplicationsPrinter) Data() [][]string { 42 | var data [][]string 43 | 44 | if len(a.Applications) == 0 { 45 | data = append(data, []string{"---", "---", "---", "---", "---", "---", "---"}) 46 | return data 47 | } 48 | 49 | for i := range a.Applications { 50 | data = append(data, []string{ 51 | strconv.Itoa(a.Applications[i].ID), 52 | a.Applications[i].Name, 53 | a.Applications[i].ShortName, 54 | a.Applications[i].DeployName, 55 | a.Applications[i].Type, 56 | a.Applications[i].Vendor, 57 | a.Applications[i].ImageID, 58 | }) 59 | } 60 | 61 | return data 62 | } 63 | 64 | // Paging validates and forms the paging data for output 65 | func (a *ApplicationsPrinter) Paging() [][]string { 66 | return printer.NewPagingFromMeta(a.Meta).Compose() 67 | } 68 | -------------------------------------------------------------------------------- /cmd/sshkeys/printer.go: -------------------------------------------------------------------------------- 1 | package sshkeys 2 | 3 | import ( 4 | "github.com/vultr/govultr/v3" 5 | "github.com/vultr/vultr-cli/v3/cmd/printer" 6 | ) 7 | 8 | // SSHKeysPrinter ... 9 | type SSHKeysPrinter struct { 10 | SSHKeys []govultr.SSHKey `json:"ssh_keys"` 11 | Meta *govultr.Meta 12 | } 13 | 14 | // JSON ... 15 | func (s *SSHKeysPrinter) JSON() []byte { 16 | return printer.MarshalObject(s, "json") 17 | } 18 | 19 | // YAML ... 20 | func (s *SSHKeysPrinter) YAML() []byte { 21 | return printer.MarshalObject(s, "yaml") 22 | } 23 | 24 | // Columns ... 25 | func (s *SSHKeysPrinter) Columns() [][]string { 26 | return [][]string{0: { 27 | "ID", 28 | "DATE CREATED", 29 | "NAME", 30 | "KEY", 31 | }} 32 | } 33 | 34 | // Data ... 35 | func (s *SSHKeysPrinter) Data() [][]string { 36 | data := [][]string{} 37 | for i := range s.SSHKeys { 38 | data = append(data, []string{ 39 | s.SSHKeys[i].ID, 40 | s.SSHKeys[i].DateCreated, 41 | s.SSHKeys[i].Name, 42 | s.SSHKeys[i].SSHKey, 43 | }) 44 | } 45 | return data 46 | } 47 | 48 | // Paging ... 49 | func (s *SSHKeysPrinter) Paging() [][]string { 50 | return printer.NewPagingFromMeta(s.Meta).Compose() 51 | } 52 | 53 | // SSHKeyPrinter ... 54 | type SSHKeyPrinter struct { 55 | SSHKey *govultr.SSHKey `json:"ssh_key"` 56 | } 57 | 58 | // JSON ... 59 | func (s SSHKeyPrinter) JSON() []byte { 60 | return printer.MarshalObject(s, "json") 61 | } 62 | 63 | // YAML ... 64 | func (s SSHKeyPrinter) YAML() []byte { 65 | return printer.MarshalObject(s, "yaml") 66 | } 67 | 68 | // Columns ... 69 | func (s SSHKeyPrinter) Columns() [][]string { 70 | return [][]string{0: { 71 | "ID", 72 | "DATE CREATED", 73 | "NAME", 74 | "KEY", 75 | }} 76 | } 77 | 78 | // Data ... 79 | func (s SSHKeyPrinter) Data() [][]string { 80 | return [][]string{0: { 81 | s.SSHKey.ID, 82 | s.SSHKey.DateCreated, 83 | s.SSHKey.Name, 84 | s.SSHKey.SSHKey, 85 | }} 86 | } 87 | 88 | // Paging ... 89 | func (s SSHKeyPrinter) Paging() [][]string { 90 | return nil 91 | } 92 | -------------------------------------------------------------------------------- /cmd/logs/printer.go: -------------------------------------------------------------------------------- 1 | package logs 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | "github.com/vultr/vultr-cli/v3/cmd/printer" 8 | ) 9 | 10 | // LogsPrinter ... 11 | type LogsPrinter struct { 12 | Logs []govultr.Log `json:"logs"` 13 | Meta *govultr.LogsMeta `json:"meta"` 14 | } 15 | 16 | // JSON ... 17 | func (l *LogsPrinter) JSON() []byte { 18 | return printer.MarshalObject(l, "json") 19 | } 20 | 21 | // YAML ... 22 | func (l *LogsPrinter) YAML() []byte { 23 | return printer.MarshalObject(l, "yaml") 24 | } 25 | 26 | // Columns ... 27 | func (l *LogsPrinter) Columns() [][]string { 28 | return nil 29 | } 30 | 31 | // Data ... 32 | func (l *LogsPrinter) Data() [][]string { 33 | if len(l.Logs) == 0 { 34 | return [][]string{0: {"No logs returned"}} 35 | } 36 | 37 | var data [][]string 38 | for i := range l.Logs { 39 | data = append(data, 40 | []string{"---------------------------"}, 41 | []string{"UUID", l.Logs[i].ResourceID}, 42 | []string{"TYPE", l.Logs[i].ResourceType}, 43 | []string{"LEVEL", l.Logs[i].Level}, 44 | []string{"MESSAGE", l.Logs[i].Message}, 45 | []string{"TIMESTAMP", l.Logs[i].Timestamp}, 46 | []string{" "}, 47 | []string{"USER ID", l.Logs[i].Metadata.UserID}, 48 | []string{"USER NAME", l.Logs[i].Metadata.UserName}, 49 | []string{"IP", l.Logs[i].Metadata.IPAddress}, 50 | []string{"HTTP CODE", strconv.Itoa(l.Logs[i].Metadata.HTTPStatusCode)}, 51 | []string{"HTTP METHOD", l.Logs[i].Metadata.Method}, 52 | []string{"REQUEST PATH", l.Logs[i].Metadata.RequestPath}, 53 | []string{"REQUEST BODY", l.Logs[i].Metadata.RequestBody}, 54 | []string{"PARAMETERS", l.Logs[i].Metadata.QueryParameters}, 55 | ) 56 | } 57 | 58 | return data 59 | } 60 | 61 | // Paging ... 62 | func (l *LogsPrinter) Paging() [][]string { 63 | if l.Meta.TotalCount == 0 { 64 | return nil 65 | } 66 | 67 | var data [][]string 68 | data = append(data, 69 | []string{"======================================"}, 70 | []string{"CONTINUE TIME", l.Meta.ContinueTime}, 71 | []string{"RETURNED COUNT", strconv.Itoa(l.Meta.ReturnedCount)}, 72 | []string{"UNRETURNED COUNT", strconv.Itoa(l.Meta.UnreturnedCount)}, 73 | []string{"TOTAL COUNT", strconv.Itoa(l.Meta.TotalCount)}, 74 | ) 75 | 76 | return data 77 | } 78 | -------------------------------------------------------------------------------- /cmd/users/printer.go: -------------------------------------------------------------------------------- 1 | package users 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | "github.com/vultr/vultr-cli/v3/cmd/printer" 8 | ) 9 | 10 | // UsersPrinter ... 11 | type UsersPrinter struct { 12 | Users []govultr.User `json:"users"` 13 | Meta *govultr.Meta `json:"meta"` 14 | } 15 | 16 | // JSON ... 17 | func (u *UsersPrinter) JSON() []byte { 18 | return printer.MarshalObject(u, "json") 19 | } 20 | 21 | // YAML ... 22 | func (u *UsersPrinter) YAML() []byte { 23 | return printer.MarshalObject(u, "yaml") 24 | } 25 | 26 | // Columns ... 27 | func (u *UsersPrinter) Columns() [][]string { 28 | return [][]string{0: { 29 | "ID", 30 | "NAME", 31 | "EMAIL", 32 | "API", 33 | "ACL", 34 | }} 35 | } 36 | 37 | // Data ... 38 | func (u *UsersPrinter) Data() [][]string { 39 | data := [][]string{} 40 | for i := range u.Users { 41 | data = append(data, []string{ 42 | u.Users[i].ID, 43 | u.Users[i].Name, 44 | u.Users[i].Email, 45 | strconv.FormatBool(*u.Users[i].APIEnabled), 46 | printer.ArrayOfStringsToString(u.Users[i].ACL), 47 | }) 48 | } 49 | return data 50 | } 51 | 52 | // Paging ... 53 | func (u *UsersPrinter) Paging() [][]string { 54 | return printer.NewPagingFromMeta(u.Meta).Compose() 55 | } 56 | 57 | // ====================================== 58 | 59 | // UserPrinter ... 60 | type UserPrinter struct { 61 | User govultr.User `json:"user"` 62 | } 63 | 64 | // JSON ... 65 | func (u *UserPrinter) JSON() []byte { 66 | return printer.MarshalObject(u, "json") 67 | } 68 | 69 | // YAML ... 70 | func (u *UserPrinter) YAML() []byte { 71 | return printer.MarshalObject(u, "yaml") 72 | } 73 | 74 | // Columns ... 75 | func (u *UserPrinter) Columns() [][]string { 76 | return [][]string{0: { 77 | "ID", 78 | "NAME", 79 | "EMAIL", 80 | "API", 81 | "ACL", 82 | }} 83 | } 84 | 85 | // Data ... 86 | func (u *UserPrinter) Data() [][]string { 87 | return [][]string{0: { 88 | u.User.ID, 89 | u.User.Name, 90 | u.User.Email, 91 | strconv.FormatBool(*u.User.APIEnabled), 92 | printer.ArrayOfStringsToString(u.User.ACL), 93 | }} 94 | } 95 | 96 | // Paging ... 97 | func (u *UserPrinter) Paging() [][]string { 98 | return nil 99 | } 100 | -------------------------------------------------------------------------------- /cmd/backups/printer.go: -------------------------------------------------------------------------------- 1 | package backups 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | "github.com/vultr/vultr-cli/v3/cmd/printer" 8 | ) 9 | 10 | // BackupsPrinter ... 11 | type BackupsPrinter struct { 12 | Backups []govultr.Backup `json:"backups"` 13 | Meta *govultr.Meta `json:"meta"` 14 | } 15 | 16 | // JSON ... 17 | func (b *BackupsPrinter) JSON() []byte { 18 | return printer.MarshalObject(b, "json") 19 | } 20 | 21 | // YAML ... 22 | func (b *BackupsPrinter) YAML() []byte { 23 | return printer.MarshalObject(b, "yaml") 24 | } 25 | 26 | // Columns ... 27 | func (b *BackupsPrinter) Columns() [][]string { 28 | return [][]string{0: { 29 | "ID", 30 | "DATE CREATED", 31 | "DESCRIPTION", 32 | "SIZE", 33 | "STATUS", 34 | }} 35 | } 36 | 37 | // Data ... 38 | func (b *BackupsPrinter) Data() [][]string { 39 | data := [][]string{} 40 | for i := range b.Backups { 41 | data = append(data, []string{ 42 | b.Backups[i].ID, 43 | b.Backups[i].DateCreated, 44 | b.Backups[i].Description, 45 | strconv.Itoa(b.Backups[i].Size), 46 | b.Backups[i].Status, 47 | }) 48 | } 49 | return data 50 | } 51 | 52 | // Paging ... 53 | func (b *BackupsPrinter) Paging() [][]string { 54 | return printer.NewPagingFromMeta(b.Meta).Compose() 55 | } 56 | 57 | // ====================================== 58 | 59 | // BackupPrinter ... 60 | type BackupPrinter struct { 61 | Backup *govultr.Backup `json:"backup"` 62 | } 63 | 64 | // JSON ... 65 | func (b *BackupPrinter) JSON() []byte { 66 | return printer.MarshalObject(b, "json") 67 | } 68 | 69 | // YAML ... 70 | func (b *BackupPrinter) YAML() []byte { 71 | return printer.MarshalObject(b, "yaml") 72 | } 73 | 74 | // Columns ... 75 | func (b *BackupPrinter) Columns() [][]string { 76 | return [][]string{0: { 77 | "ID", 78 | "DATE CREATED", 79 | "DESCRIPTION", 80 | "SIZE", 81 | "STATUS", 82 | }} 83 | } 84 | 85 | // Data ... 86 | func (b *BackupPrinter) Data() [][]string { 87 | return [][]string{0: { 88 | b.Backup.ID, 89 | b.Backup.DateCreated, 90 | b.Backup.Description, 91 | strconv.Itoa(b.Backup.Size), 92 | b.Backup.Status, 93 | }} 94 | } 95 | 96 | // Paging ... 97 | func (b *BackupPrinter) Paging() [][]string { 98 | return nil 99 | } 100 | -------------------------------------------------------------------------------- /cmd/script/printer.go: -------------------------------------------------------------------------------- 1 | package script 2 | 3 | import ( 4 | "github.com/vultr/govultr/v3" 5 | "github.com/vultr/vultr-cli/v3/cmd/printer" 6 | ) 7 | 8 | // ScriptsPrinter ... 9 | type ScriptsPrinter struct { 10 | Scripts []govultr.StartupScript `json:"startup_scripts"` 11 | Meta *govultr.Meta `json:"meta"` 12 | } 13 | 14 | // JSON ... 15 | func (s *ScriptsPrinter) JSON() []byte { 16 | return printer.MarshalObject(s, "json") 17 | } 18 | 19 | // YAML ... 20 | func (s *ScriptsPrinter) YAML() []byte { 21 | return printer.MarshalObject(s, "yaml") 22 | } 23 | 24 | // Columns ... 25 | func (s *ScriptsPrinter) Columns() [][]string { 26 | return [][]string{0: { 27 | "ID", 28 | "DATE CREATED", 29 | "DATE MODIFIED", 30 | "TYPE", 31 | "NAME", 32 | }} 33 | } 34 | 35 | // Data ... 36 | func (s *ScriptsPrinter) Data() [][]string { 37 | if len(s.Scripts) == 0 { 38 | return [][]string{0: {"---", "---", "---", "---", "---"}} 39 | } 40 | 41 | var data [][]string 42 | for i := range s.Scripts { 43 | data = append(data, []string{ 44 | s.Scripts[i].ID, 45 | s.Scripts[i].DateCreated, 46 | s.Scripts[i].DateModified, 47 | s.Scripts[i].Type, 48 | s.Scripts[i].Name, 49 | }) 50 | } 51 | 52 | return data 53 | } 54 | 55 | // Paging ... 56 | func (s *ScriptsPrinter) Paging() [][]string { 57 | return printer.NewPagingFromMeta(s.Meta).Compose() 58 | } 59 | 60 | // ====================================== 61 | 62 | // ScriptPrinter ... 63 | type ScriptPrinter struct { 64 | Script *govultr.StartupScript `json:"startup_script"` 65 | } 66 | 67 | // JSON ... 68 | func (s *ScriptPrinter) JSON() []byte { 69 | return printer.MarshalObject(s, "json") 70 | } 71 | 72 | // YAML ... 73 | func (s *ScriptPrinter) YAML() []byte { 74 | return printer.MarshalObject(s, "yaml") 75 | } 76 | 77 | // Columns ... 78 | func (s *ScriptPrinter) Columns() [][]string { 79 | return nil 80 | } 81 | 82 | // Data ... 83 | func (s *ScriptPrinter) Data() [][]string { 84 | return [][]string{ 85 | 0: {"ID", s.Script.ID}, 86 | 1: {"DATE CREATED", s.Script.DateCreated}, 87 | 2: {"DATE MODIFIED", s.Script.DateModified}, 88 | 3: {"TYPE", s.Script.Type}, 89 | 4: {"NAME", s.Script.Name}, 90 | 5: {"SCRIPT", s.Script.Script}, 91 | } 92 | } 93 | 94 | // Paging ... 95 | func (s *ScriptPrinter) Paging() [][]string { 96 | return nil 97 | } 98 | -------------------------------------------------------------------------------- /cmd/ip/printer.go: -------------------------------------------------------------------------------- 1 | // Package ip provides printers for server network addresses 2 | package ip 3 | 4 | import ( 5 | "strconv" 6 | 7 | "github.com/vultr/govultr/v3" 8 | "github.com/vultr/vultr-cli/v3/cmd/printer" 9 | ) 10 | 11 | // IPv4sPrinter ... 12 | type IPv4sPrinter struct { 13 | IPv4s []govultr.IPv4 `json:"ipv4s"` 14 | Meta *govultr.Meta `json:"meta"` 15 | } 16 | 17 | // JSON ... 18 | func (i *IPv4sPrinter) JSON() []byte { 19 | return printer.MarshalObject(i, "json") 20 | } 21 | 22 | // YAML ... 23 | func (i *IPv4sPrinter) YAML() []byte { 24 | return printer.MarshalObject(i, "yaml") 25 | } 26 | 27 | // Columns ... 28 | func (i *IPv4sPrinter) Columns() [][]string { 29 | return [][]string{0: { 30 | "IP", 31 | "NETMASK", 32 | "GATEWAY", 33 | "TYPE", 34 | }} 35 | } 36 | 37 | // Data ... 38 | func (i *IPv4sPrinter) Data() [][]string { 39 | var data [][]string 40 | for j := range i.IPv4s { 41 | data = append(data, []string{ 42 | i.IPv4s[j].IP, 43 | i.IPv4s[j].Netmask, 44 | i.IPv4s[j].Gateway, 45 | i.IPv4s[j].Type, 46 | }) 47 | } 48 | 49 | return data 50 | } 51 | 52 | // Paging ... 53 | func (i *IPv4sPrinter) Paging() [][]string { 54 | return printer.NewPagingFromMeta(i.Meta).Compose() 55 | } 56 | 57 | // ====================================== 58 | 59 | // IPv6sPrinter ... 60 | type IPv6sPrinter struct { 61 | IPv6s []govultr.IPv6 `json:"ipv6s"` 62 | Meta *govultr.Meta `json:"meta"` 63 | } 64 | 65 | // JSON ... 66 | func (i *IPv6sPrinter) JSON() []byte { 67 | return printer.MarshalObject(i, "json") 68 | } 69 | 70 | // YAML ... 71 | func (i *IPv6sPrinter) YAML() []byte { 72 | return printer.MarshalObject(i, "yaml") 73 | } 74 | 75 | // Columns ... 76 | func (i *IPv6sPrinter) Columns() [][]string { 77 | return [][]string{0: { 78 | "IP", 79 | "NETWORK", 80 | "NETWORK SIZE", 81 | "TYPE", 82 | }} 83 | } 84 | 85 | // Data ... 86 | func (i *IPv6sPrinter) Data() [][]string { 87 | var data [][]string 88 | for j := range i.IPv6s { 89 | data = append(data, []string{ 90 | i.IPv6s[j].IP, 91 | i.IPv6s[j].Network, 92 | strconv.Itoa(i.IPv6s[j].NetworkSize), 93 | i.IPv6s[j].Type, 94 | }) 95 | } 96 | 97 | return data 98 | } 99 | 100 | // Paging ... 101 | func (i *IPv6sPrinter) Paging() [][]string { 102 | return printer.NewPagingFromMeta(i.Meta).Compose() 103 | } 104 | -------------------------------------------------------------------------------- /cmd/vpc/printer.go: -------------------------------------------------------------------------------- 1 | package vpc 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | 8 | "github.com/vultr/vultr-cli/v3/cmd/printer" 9 | ) 10 | 11 | // VPCsPrinter ... 12 | type VPCsPrinter struct { 13 | VPCs []govultr.VPC `json:"vpcs"` 14 | Meta *govultr.Meta `json:"meta"` 15 | } 16 | 17 | // JSON ... 18 | func (s *VPCsPrinter) JSON() []byte { 19 | return printer.MarshalObject(s, "json") 20 | } 21 | 22 | // YAML ... 23 | func (s *VPCsPrinter) YAML() []byte { 24 | return printer.MarshalObject(s, "yaml") 25 | } 26 | 27 | // Columns ... 28 | func (s *VPCsPrinter) Columns() [][]string { 29 | return [][]string{0: { 30 | "ID", 31 | "REGION", 32 | "DESCRIPTION", 33 | "V4 SUBNET", 34 | "V4 SUBNET MASK", 35 | "DATE CREATED", 36 | }} 37 | } 38 | 39 | // Data ... 40 | func (s *VPCsPrinter) Data() [][]string { 41 | if len(s.VPCs) == 0 { 42 | return [][]string{0: {"---", "---", "---", "---", "---", "---"}} 43 | } 44 | 45 | var data [][]string 46 | for i := range s.VPCs { 47 | data = append(data, []string{ 48 | s.VPCs[i].ID, 49 | s.VPCs[i].Region, 50 | s.VPCs[i].Description, 51 | s.VPCs[i].V4Subnet, 52 | strconv.Itoa(s.VPCs[i].V4SubnetMask), 53 | s.VPCs[i].DateCreated, 54 | }) 55 | } 56 | 57 | return data 58 | } 59 | 60 | // Paging ... 61 | func (s *VPCsPrinter) Paging() [][]string { 62 | return printer.NewPagingFromMeta(s.Meta).Compose() 63 | } 64 | 65 | // ====================================== 66 | 67 | // VPCPrinter ... 68 | type VPCPrinter struct { 69 | VPC *govultr.VPC `json:"vpc"` 70 | } 71 | 72 | // JSON ... 73 | func (s *VPCPrinter) JSON() []byte { 74 | return printer.MarshalObject(s, "json") 75 | } 76 | 77 | // YAML ... 78 | func (s *VPCPrinter) YAML() []byte { 79 | return printer.MarshalObject(s, "yaml") 80 | } 81 | 82 | // Columns ... 83 | func (s *VPCPrinter) Columns() [][]string { 84 | return [][]string{0: { 85 | "ID", 86 | "REGION", 87 | "DESCRIPTION", 88 | "V4 SUBNET", 89 | "V4 SUBNET MASK", 90 | "DATE CREATED", 91 | }} 92 | } 93 | 94 | // Data ... 95 | func (s *VPCPrinter) Data() [][]string { 96 | return [][]string{0: { 97 | s.VPC.ID, 98 | s.VPC.Region, 99 | s.VPC.Description, 100 | s.VPC.V4Subnet, 101 | strconv.Itoa(s.VPC.V4SubnetMask), 102 | s.VPC.DateCreated, 103 | }} 104 | } 105 | 106 | // Paging ... 107 | func (s *VPCPrinter) Paging() [][]string { 108 | return nil 109 | } 110 | -------------------------------------------------------------------------------- /cmd/operatingsystems/operatingsystems.go: -------------------------------------------------------------------------------- 1 | // Package operatingsystems provides the operating systems functionality for 2 | // the CLI 3 | package operatingsystems 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | 9 | "github.com/spf13/cobra" 10 | "github.com/vultr/govultr/v3" 11 | "github.com/vultr/vultr-cli/v3/cmd/utils" 12 | "github.com/vultr/vultr-cli/v3/pkg/cli" 13 | ) 14 | 15 | var ( 16 | long = `OS will retrieve available operating systems that can be deployed` 17 | example = ` 18 | # Example 19 | vultr-cli os 20 | ` 21 | 22 | listLong = `List all operating systems available to be deployed on Vultr` 23 | listExample = ` 24 | # Full example 25 | vultr-cli os list 26 | 27 | # Full example with paging 28 | vultr-cli os list --per-page=1 --cursor="bmV4dF9fMTI0" 29 | 30 | # Shortened with alias commands 31 | vultr-cli o l 32 | ` 33 | ) 34 | 35 | // NewCmdOS provides the command for operating systems to the CLI 36 | func NewCmdOS(base *cli.Base) *cobra.Command { 37 | o := &options{Base: base} 38 | 39 | cmd := &cobra.Command{ 40 | Use: "os", 41 | Short: "Display available operating systems", 42 | Aliases: []string{"o"}, 43 | Long: long, 44 | Example: example, 45 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 46 | utils.SetOptions(o.Base, cmd, args) 47 | return nil 48 | }, 49 | } 50 | 51 | // List 52 | list := &cobra.Command{ 53 | Use: "list", 54 | Short: "List all operating systems", 55 | Aliases: []string{"l"}, 56 | Long: listLong, 57 | Example: listExample, 58 | RunE: func(cmd *cobra.Command, args []string) error { 59 | os, meta, err := o.list() 60 | if err != nil { 61 | return fmt.Errorf("error getting operating systems : %v", err) 62 | } 63 | 64 | data := &OSPrinter{OperatingSystems: os, Meta: meta} 65 | o.Base.Printer.Display(data, err) 66 | 67 | return nil 68 | }, 69 | } 70 | 71 | list.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.") 72 | list.Flags().IntP( 73 | "per-page", 74 | "p", 75 | utils.PerPageDefault, 76 | fmt.Sprintf( 77 | "(optional) Number of items requested per page. Default is %d and Max is 500.", 78 | utils.PerPageDefault, 79 | ), 80 | ) 81 | 82 | cmd.AddCommand(list) 83 | return cmd 84 | } 85 | 86 | type options struct { 87 | Base *cli.Base 88 | } 89 | 90 | func (o *options) list() ([]govultr.OS, *govultr.Meta, error) { 91 | list, meta, _, err := o.Base.Client.OS.List(context.Background(), o.Base.Options) 92 | return list, meta, err 93 | } 94 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | builds: 3 | - 4 | env: 5 | - CGO_ENABLED=0 6 | 7 | binary: vultr-cli 8 | 9 | flags: 10 | - -trimpath #removes all file system paths from the compiled executable 11 | 12 | goos: 13 | - linux 14 | - windows 15 | - darwin 16 | 17 | goarch: 18 | - amd64 19 | - arm64 20 | - arm 21 | 22 | goarm: 23 | - 6 24 | - 7 25 | 26 | archives: 27 | - 28 | name_template: >- 29 | {{- .ProjectName }}_v 30 | {{- .Version }}_ 31 | {{- if eq .Os "darwin" }}macOs 32 | {{- else }}{{ .Os }}{{ end }}_ 33 | {{- if eq .Arch "arm" }}arm32-v{{ .Arm }} 34 | {{- else }}{{ .Arch }}{{ end }} 35 | 36 | format: tar.gz 37 | 38 | files: 39 | - none* 40 | 41 | format_overrides: 42 | - goos: windows 43 | format: zip 44 | 45 | builds_info: 46 | group: root 47 | owner: root 48 | mode: 0644 49 | 50 | checksum: 51 | name_template: "{{ .ProjectName }}_v{{ .Version }}_checksums.txt" 52 | algorithm: sha256 53 | 54 | snapshot: 55 | name_template: "{{ .ProjectName }}_v{{ .Version }}" 56 | 57 | changelog: 58 | sort: asc 59 | filters: 60 | exclude: 61 | - '^docs:' 62 | - '^test:' 63 | 64 | brews: 65 | - 66 | name: vultr-cli 67 | 68 | repository: 69 | owner: vultr 70 | name: homebrew-vultr-cli 71 | 72 | url_template: "https://github.com/vultr/vultr-cli/releases/download/{{ .Tag }}/{{ .ArtifactName }}" 73 | 74 | commit_author: 75 | name: goreleaserbot 76 | email: opensource@vultr.com 77 | 78 | homepage: "https://github.com/vultr/vultr-cli" 79 | 80 | description: "Official command-line tool for Vultr services" 81 | 82 | test: | 83 | output = shell_output("#{bin}/vultr-cli version 2>&1", 1) 84 | assert_match "Please export your VULTR API key as an environment variable or add `api-key` to your config file, eg:\nexport VULTR_API_KEY=''\n", output 85 | 86 | install: | 87 | bin.install "vultr-cli" 88 | prefix.install_metafiles 89 | 90 | dockers: 91 | - dockerfile: Dockerfile.goreleaser 92 | image_templates: 93 | - "vultr/vultr-cli:release" 94 | - "vultr/vultr-cli:latest" 95 | - "vultr/vultr-cli:{{ .Tag }}" 96 | extra_files: 97 | - scripts/entrypoint.sh 98 | 99 | release: 100 | github: 101 | owner: vultr 102 | name: vultr-cli 103 | -------------------------------------------------------------------------------- /cmd/applications/applications.go: -------------------------------------------------------------------------------- 1 | // Package applications provides the application functionality for the CLI 2 | package applications 3 | 4 | import ( 5 | "context" 6 | "fmt" 7 | 8 | "github.com/spf13/cobra" 9 | "github.com/vultr/govultr/v3" 10 | "github.com/vultr/vultr-cli/v3/cmd/printer" 11 | "github.com/vultr/vultr-cli/v3/cmd/utils" 12 | "github.com/vultr/vultr-cli/v3/pkg/cli" 13 | ) 14 | 15 | var ( 16 | appLong = `Display all commands for applications` 17 | appExample = ` 18 | # Full example 19 | vultr-cli applications 20 | ` 21 | 22 | listLong = `Display all available applications.` 23 | listExample = ` 24 | # Full example 25 | vultr-cli applications list 26 | 27 | # Full example with paging 28 | vultr-cli applications list --per-page=1 --cursor="bmV4dF9fMg==" 29 | 30 | # Shortened with alias commands 31 | vultr-cli a l 32 | ` 33 | ) 34 | 35 | // NewCmdApplications creates cobra command for applications 36 | func NewCmdApplications(base *cli.Base) *cobra.Command { 37 | o := &options{Base: base} 38 | 39 | cmd := &cobra.Command{ 40 | Use: "apps", 41 | Short: "Display applications", 42 | Aliases: []string{"a", "application", "applications", "app"}, 43 | Long: appLong, 44 | Example: appExample, 45 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 46 | utils.SetOptions(o.Base, cmd, args) 47 | return nil 48 | }, 49 | } 50 | 51 | // List 52 | list := &cobra.Command{ 53 | Use: "list", 54 | Short: "List available applications", 55 | Aliases: []string{"l"}, 56 | Long: listLong, 57 | Example: listExample, 58 | RunE: func(cmd *cobra.Command, args []string) error { 59 | apps, meta, err := o.list() 60 | if err != nil { 61 | return fmt.Errorf("error retrieving application list : %v", err) 62 | } 63 | 64 | data := &ApplicationsPrinter{Applications: apps, Meta: meta} 65 | o.Base.Printer.Display(data, err) 66 | 67 | return nil 68 | }, 69 | } 70 | 71 | list.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.") 72 | list.Flags().IntP( 73 | "per-page", 74 | "p", 75 | utils.PerPageDefault, 76 | fmt.Sprintf( 77 | "(optional) Number of items requested per page. Default is %d and Max is 500.", 78 | utils.PerPageDefault, 79 | ), 80 | ) 81 | 82 | cmd.AddCommand(list) 83 | return cmd 84 | } 85 | 86 | type options struct { 87 | Base *cli.Base 88 | Printer *printer.Output 89 | } 90 | 91 | func (o *options) list() ([]govultr.Application, *govultr.Meta, error) { 92 | list, meta, _, err := o.Base.Client.Application.List(context.Background(), o.Base.Options) 93 | return list, meta, err 94 | } 95 | -------------------------------------------------------------------------------- /cmd/reservedip/printer.go: -------------------------------------------------------------------------------- 1 | package reservedip 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | "github.com/vultr/vultr-cli/v3/cmd/printer" 8 | ) 9 | 10 | // ReservedIPsPrinter ... 11 | type ReservedIPsPrinter struct { 12 | IPs []govultr.ReservedIP `json:"reserved_ips"` 13 | Meta *govultr.Meta `json:"meta"` 14 | } 15 | 16 | // JSON ... 17 | func (r *ReservedIPsPrinter) JSON() []byte { 18 | return printer.MarshalObject(r, "json") 19 | } 20 | 21 | // YAML ... 22 | func (r *ReservedIPsPrinter) YAML() []byte { 23 | return printer.MarshalObject(r, "yaml") 24 | } 25 | 26 | // Columns ... 27 | func (r *ReservedIPsPrinter) Columns() [][]string { 28 | return [][]string{0: { 29 | "ID", 30 | "REGION", 31 | "IP TYPE", 32 | "SUBNET", 33 | "SUBNET SIZE", 34 | "LABEL", 35 | "ATTACHED TO", 36 | }} 37 | } 38 | 39 | // Data ... 40 | func (r *ReservedIPsPrinter) Data() [][]string { 41 | if len(r.IPs) == 0 { 42 | return [][]string{0: {"---", "---", "---", "---", "---", "---", "---"}} 43 | } 44 | 45 | var data [][]string 46 | for i := range r.IPs { 47 | data = append(data, []string{ 48 | r.IPs[i].ID, 49 | r.IPs[i].Region, 50 | r.IPs[i].IPType, 51 | r.IPs[i].Subnet, 52 | strconv.Itoa(r.IPs[i].SubnetSize), 53 | r.IPs[i].Label, 54 | r.IPs[i].InstanceID, 55 | }) 56 | } 57 | 58 | return data 59 | } 60 | 61 | // Paging ... 62 | func (r *ReservedIPsPrinter) Paging() [][]string { 63 | return printer.NewPagingFromMeta(r.Meta).Compose() 64 | } 65 | 66 | // ====================================== 67 | 68 | // ReservedIPPrinter ... 69 | type ReservedIPPrinter struct { 70 | IP *govultr.ReservedIP `json:"reserved_ip"` 71 | } 72 | 73 | // JSON ... 74 | func (r *ReservedIPPrinter) JSON() []byte { 75 | return printer.MarshalObject(r, "json") 76 | } 77 | 78 | // YAML ... 79 | func (r *ReservedIPPrinter) YAML() []byte { 80 | return printer.MarshalObject(r, "yaml") 81 | } 82 | 83 | // Columns ... 84 | func (r *ReservedIPPrinter) Columns() [][]string { 85 | return [][]string{0: { 86 | "ID", 87 | "REGION", 88 | "IP TYPE", 89 | "SUBNET", 90 | "SUBNET SIZE", 91 | "LABEL", 92 | "ATTACHED TO", 93 | }} 94 | } 95 | 96 | // Data ... 97 | func (r *ReservedIPPrinter) Data() [][]string { 98 | return [][]string{0: { 99 | r.IP.ID, 100 | r.IP.Region, 101 | r.IP.IPType, 102 | r.IP.Subnet, 103 | strconv.Itoa(r.IP.SubnetSize), 104 | r.IP.Label, 105 | r.IP.InstanceID, 106 | }} 107 | } 108 | 109 | // Paging ... 110 | func (r *ReservedIPPrinter) Paging() [][]string { 111 | return nil 112 | } 113 | 114 | // ====================================== 115 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | linters: 3 | default: none 4 | enable: 5 | - dogsled 6 | - dupl 7 | - errcheck 8 | - funlen 9 | - gocyclo 10 | - goprintffuncname 11 | - gosec 12 | - govet 13 | - ineffassign 14 | - lll 15 | - misspell 16 | - mnd 17 | - nakedret 18 | - noctx 19 | - nolintlint 20 | - revive 21 | - staticcheck 22 | - unconvert 23 | - unparam 24 | - unused 25 | - whitespace 26 | settings: 27 | dupl: 28 | threshold: 300 29 | funlen: 30 | lines: -1 31 | statements: 50 32 | goconst: 33 | min-len: 2 34 | min-occurrences: 3 35 | gocritic: 36 | disabled-checks: 37 | - dupImport 38 | - ifElseChain 39 | - octalLiteral 40 | - whyNoLint 41 | enabled-tags: 42 | - diagnostic 43 | - experimental 44 | - opinionated 45 | - performance 46 | - style 47 | gocyclo: 48 | min-complexity: 15 49 | govet: 50 | settings: 51 | printf: 52 | funcs: 53 | - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof 54 | - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf 55 | - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf 56 | - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf 57 | lll: 58 | line-length: 120 59 | misspell: 60 | locale: US 61 | mnd: 62 | checks: 63 | - argument 64 | - case 65 | - condition 66 | - return 67 | ignored-numbers: 68 | - "0" 69 | - "1" 70 | - "2" 71 | - "3" 72 | ignored-functions: 73 | - strings.SplitN 74 | nolintlint: 75 | require-explanation: false 76 | require-specific: false 77 | allow-unused: false 78 | revive: 79 | rules: 80 | - name: unexported-return 81 | disabled: true 82 | exclusions: 83 | generated: lax 84 | presets: 85 | - comments 86 | - common-false-positives 87 | - legacy 88 | - std-error-handling 89 | rules: 90 | - path: (.+)\.go$ 91 | text: abcdef 92 | - path: (.+)\.go$ 93 | text: ST1023 94 | paths: 95 | - third_party$ 96 | - builtin$ 97 | - examples$ 98 | formatters: 99 | enable: 100 | - gofmt 101 | - goimports 102 | settings: 103 | goimports: 104 | local-prefixes: 105 | - github.com/golangci/golangci-lint 106 | exclusions: 107 | generated: lax 108 | paths: 109 | - third_party$ 110 | - builtin$ 111 | - examples$ 112 | -------------------------------------------------------------------------------- /cmd/marketplace/marketplace.go: -------------------------------------------------------------------------------- 1 | // Package marketplace provides the command for the CLI to access marketplace 2 | // functionality 3 | package marketplace 4 | 5 | import ( 6 | "errors" 7 | "fmt" 8 | 9 | "github.com/spf13/cobra" 10 | "github.com/vultr/govultr/v3" 11 | "github.com/vultr/vultr-cli/v3/cmd/utils" 12 | "github.com/vultr/vultr-cli/v3/pkg/cli" 13 | ) 14 | 15 | var ( 16 | long = `Get commands available to marketplace` 17 | example = ` 18 | # Full example 19 | vultr-cli marketplace 20 | ` 21 | appLong = `Get commands available to marketplace apps` 22 | appExample = ` 23 | # Full example 24 | vultr-cli marketplace app 25 | ` 26 | listAppVariablesLong = `List all user-supplied variables for a given marketplace app` 27 | listAppVariablesExample = ` 28 | # Full example 29 | vultr-cli marketplace app list-variables drupal 30 | ` 31 | ) 32 | 33 | // NewCmdMarketplace provides the CLI command for marketplace functions 34 | func NewCmdMarketplace(base *cli.Base) *cobra.Command { 35 | o := &options{Base: base} 36 | 37 | cmd := &cobra.Command{ 38 | Use: "marketplace", 39 | Short: "Display marketplace information", 40 | Long: long, 41 | Example: example, 42 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 43 | utils.SetOptions(o.Base, cmd, args) 44 | return nil 45 | }, 46 | } 47 | 48 | // App 49 | app := &cobra.Command{ 50 | Use: "app", 51 | Short: "Commands to interact with vultr marketplace apps", 52 | Long: appLong, 53 | Example: appExample, 54 | } 55 | 56 | // List Variables 57 | listVariables := &cobra.Command{ 58 | Use: "list-variables", 59 | Short: "List all user-supplied variables for a marketplace app", 60 | Aliases: []string{"l"}, 61 | Long: listAppVariablesLong, 62 | Example: listAppVariablesExample, 63 | Args: func(cmd *cobra.Command, args []string) error { 64 | if len(args) < 1 { 65 | return errors.New("please provide an image ID") 66 | } 67 | return nil 68 | }, 69 | RunE: func(cmd *cobra.Command, args []string) error { 70 | vars, err := o.listVariables() 71 | if err != nil { 72 | return fmt.Errorf("error getting list of marketplace app variables : %v", err) 73 | } 74 | 75 | o.Base.Printer.Display(&VariablesPrinter{Variables: vars}, nil) 76 | 77 | return nil 78 | }, 79 | } 80 | 81 | app.AddCommand( 82 | listVariables, 83 | ) 84 | 85 | cmd.AddCommand( 86 | app, 87 | ) 88 | 89 | return cmd 90 | } 91 | 92 | type options struct { 93 | Base *cli.Base 94 | } 95 | 96 | func (o *options) listVariables() ([]govultr.MarketplaceAppVariable, error) { 97 | vars, _, err := o.Base.Client.Marketplace.ListAppVariables(o.Base.Context, o.Base.Args[0]) 98 | return vars, err 99 | } 100 | -------------------------------------------------------------------------------- /cmd/snapshot/printer.go: -------------------------------------------------------------------------------- 1 | package snapshot 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | "github.com/vultr/vultr-cli/v3/cmd/printer" 8 | ) 9 | 10 | // SnapshotsPrinter ... 11 | type SnapshotsPrinter struct { 12 | Snapshots []govultr.Snapshot `json:"snapshots"` 13 | Meta *govultr.Meta `json:"meta"` 14 | } 15 | 16 | // JSON ... 17 | func (s *SnapshotsPrinter) JSON() []byte { 18 | return printer.MarshalObject(s, "json") 19 | } 20 | 21 | // YAML ... 22 | func (s *SnapshotsPrinter) YAML() []byte { 23 | return printer.MarshalObject(s, "yaml") 24 | } 25 | 26 | // Columns ... 27 | func (s *SnapshotsPrinter) Columns() [][]string { 28 | return [][]string{0: { 29 | "ID", 30 | "DATE CREATED", 31 | "SIZE", 32 | "COMPRESSED SIZE", 33 | "STATUS", 34 | "OSID", 35 | "APPID", 36 | "DESCRIPTION", 37 | }} 38 | } 39 | 40 | // Data ... 41 | func (s *SnapshotsPrinter) Data() [][]string { 42 | if len(s.Snapshots) == 0 { 43 | return [][]string{0: {"---", "---", "---", "---", "---", "---", "---", "---"}} 44 | } 45 | 46 | var data [][]string 47 | for i := range s.Snapshots { 48 | data = append(data, []string{ 49 | s.Snapshots[i].ID, 50 | s.Snapshots[i].DateCreated, 51 | strconv.Itoa(s.Snapshots[i].Size), 52 | strconv.Itoa(s.Snapshots[i].CompressedSize), 53 | s.Snapshots[i].Status, 54 | strconv.Itoa(s.Snapshots[i].OsID), 55 | strconv.Itoa(s.Snapshots[i].AppID), 56 | s.Snapshots[i].Description, 57 | }) 58 | } 59 | 60 | return data 61 | } 62 | 63 | // Paging ... 64 | func (s *SnapshotsPrinter) Paging() [][]string { 65 | return printer.NewPagingFromMeta(s.Meta).Compose() 66 | } 67 | 68 | // ====================================== 69 | 70 | // SnapshotPrinter ... 71 | type SnapshotPrinter struct { 72 | Snapshot *govultr.Snapshot `json:"snapshot"` 73 | } 74 | 75 | // JSON ... 76 | func (s *SnapshotPrinter) JSON() []byte { 77 | return printer.MarshalObject(s, "json") 78 | } 79 | 80 | // YAML ... 81 | func (s *SnapshotPrinter) YAML() []byte { 82 | return printer.MarshalObject(s, "yaml") 83 | } 84 | 85 | // Columns ... 86 | func (s *SnapshotPrinter) Columns() [][]string { 87 | return [][]string{0: { 88 | "ID", 89 | "DATE CREATED", 90 | "SIZE", 91 | "COMPRESSED SIZE", 92 | "STATUS", 93 | "OSID", 94 | "APPID", 95 | "DESCRIPTION", 96 | }} 97 | } 98 | 99 | // Data ... 100 | func (s *SnapshotPrinter) Data() [][]string { 101 | return [][]string{0: { 102 | s.Snapshot.ID, 103 | s.Snapshot.DateCreated, 104 | strconv.Itoa(s.Snapshot.Size), 105 | strconv.Itoa(s.Snapshot.CompressedSize), 106 | s.Snapshot.Status, 107 | strconv.Itoa(s.Snapshot.OsID), 108 | strconv.Itoa(s.Snapshot.AppID), 109 | s.Snapshot.Description, 110 | }} 111 | } 112 | 113 | // Paging ... 114 | func (s *SnapshotPrinter) Paging() [][]string { 115 | return nil 116 | } 117 | -------------------------------------------------------------------------------- /cmd/account/account.go: -------------------------------------------------------------------------------- 1 | // Package account provides the account functionality for the CLI 2 | package account 3 | 4 | import ( 5 | "errors" 6 | "fmt" 7 | 8 | "github.com/spf13/cobra" 9 | "github.com/vultr/govultr/v3" 10 | "github.com/vultr/vultr-cli/v3/cmd/utils" 11 | "github.com/vultr/vultr-cli/v3/pkg/cli" 12 | ) 13 | 14 | var ( 15 | accountLong = `Account related commands` 16 | accountExample = ` 17 | # Full example 18 | vultr-cli account 19 | ` 20 | accountInfoLong = `Retrieve information about your account.` 21 | accountInfoExample = ` 22 | # Full example 23 | vultr-cli account info 24 | ` 25 | accountBandwidthLong = `Retrieve information about accout bandwidth` 26 | accountBandwidthExample = ` 27 | # Full example 28 | vultr-cli account bandwidth 29 | ` 30 | ) 31 | 32 | // NewCmdAccount creates a cobra command for Account 33 | func NewCmdAccount(base *cli.Base) *cobra.Command { 34 | o := &options{Base: base} 35 | 36 | cmd := &cobra.Command{ 37 | Use: "account", 38 | Short: "Commands related to account information", 39 | Long: accountLong, 40 | Example: accountExample, 41 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 42 | utils.SetOptions(o.Base, cmd, args) 43 | if !o.Base.HasAuth { 44 | return errors.New(utils.APIKeyError) 45 | } 46 | return nil 47 | }, 48 | } 49 | 50 | info := &cobra.Command{ 51 | Use: "info", 52 | Short: "Display account information", 53 | Long: accountInfoLong, 54 | Example: accountInfoExample, 55 | RunE: func(cmd *cobra.Command, args []string) error { 56 | account, err := o.get() 57 | if err != nil { 58 | return fmt.Errorf("error retrieving account information : %v", err) 59 | } 60 | 61 | o.Base.Printer.Display(&AccountPrinter{Account: account}, nil) 62 | 63 | return nil 64 | }, 65 | } 66 | 67 | bandwidth := &cobra.Command{ 68 | Use: "bandwidth", 69 | Short: "Display account bandwidth", 70 | Long: accountBandwidthLong, 71 | Example: accountBandwidthExample, 72 | RunE: func(cmd *cobra.Command, args []string) error { 73 | bandwidth, err := o.getBandwidth() 74 | if err != nil { 75 | return fmt.Errorf("error retrieving account bandwidth : %v", err) 76 | } 77 | 78 | o.Base.Printer.Display(&AccountBandwidthPrinter{Bandwidth: bandwidth}, nil) 79 | 80 | return nil 81 | }, 82 | } 83 | 84 | cmd.AddCommand( 85 | info, 86 | bandwidth, 87 | ) 88 | 89 | return cmd 90 | } 91 | 92 | type options struct { 93 | Base *cli.Base 94 | } 95 | 96 | func (o *options) get() (*govultr.Account, error) { 97 | account, _, err := o.Base.Client.Account.Get(o.Base.Context) 98 | return account, err 99 | } 100 | 101 | func (o *options) getBandwidth() (*govultr.AccountBandwidth, error) { 102 | bw, _, err := o.Base.Client.Account.GetBandwidth(o.Base.Context) 103 | return bw, err 104 | } 105 | -------------------------------------------------------------------------------- /.github/workflows/releaser.yml: -------------------------------------------------------------------------------- 1 | name: "Automatic Releaser" 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | check-commit: 13 | runs-on: ubuntu-latest 14 | outputs: 15 | msg_check: ${{ steps.check-msg.outputs.match }} 16 | steps: 17 | - name: Check Message 18 | id: check-msg 19 | run: | 20 | pattern="^Release v[0-9]+.[0-9]+.[0-9]+ #(minor|major|patch)$" 21 | if [[ "${{ github.event.head_commit.message }}" =~ ${pattern} ]]; then 22 | echo match=true >> $GITHUB_OUTPUT 23 | fi 24 | create-tag: 25 | runs-on: ubuntu-latest 26 | if: needs.check-commit.outputs.msg_check == 'true' 27 | needs: check-commit 28 | outputs: 29 | new_tag: ${{ steps.tagger.outputs.new_tag }} 30 | steps: 31 | - uses: actions/checkout@v2 32 | with: 33 | fetch-depth: 0 34 | 35 | - name: Bump version and push tag 36 | id: tagger 37 | uses: anothrNick/github-tag-action@v1 38 | env: 39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 40 | WITH_V: true 41 | DEFAULT_BUMP: "none" 42 | 43 | goreleaser: 44 | runs-on: ubuntu-latest 45 | needs: create-tag 46 | steps: 47 | - 48 | name: Checkout 49 | uses: actions/checkout@v4 50 | with: 51 | fetch-depth: 0 52 | - 53 | name: Set up Go 54 | uses: actions/setup-go@v5 55 | with: 56 | go-version: "1.24" 57 | - 58 | name: Docker Login 59 | env: 60 | DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} 61 | DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} 62 | run: | 63 | echo "${DOCKER_PASSWORD}" | docker login --username "${DOCKER_USERNAME}" --password-stdin 64 | - 65 | name: Run GoReleaser 66 | uses: goreleaser/goreleaser-action@v6 67 | with: 68 | distribution: goreleaser 69 | version: latest 70 | args: release --clean 71 | env: 72 | GITHUB_TOKEN: ${{ secrets.VULTRBOT_TOKEN }} 73 | DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} 74 | DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} 75 | - 76 | name: Clear 77 | if: always() 78 | run: | 79 | rm -f ${HOME}/.docker/config.json 80 | 81 | release: 82 | runs-on: ubuntu-latest 83 | needs: ["goreleaser", "create-tag"] 84 | name: Release Notification 85 | steps: 86 | - uses: mattermost/action-mattermost-notify@2.0.0 87 | with: 88 | MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }} 89 | MATTERMOST_USERNAME: ${{ secrets.MATTERMOST_USERNAME}} 90 | MATTERMOST_ICON_URL: ${{ secrets.MATTERMOST_ICON }} 91 | TEXT: "${{ github.repository }} : Release https://github.com/${{ github.repository }}/releases/tag/${{ needs.create-tag.outputs.new_tag }}" 92 | -------------------------------------------------------------------------------- /cmd/backups/backups.go: -------------------------------------------------------------------------------- 1 | // Package backups provides access to the backups for the CLI 2 | package backups 3 | 4 | import ( 5 | "errors" 6 | "fmt" 7 | 8 | "github.com/spf13/cobra" 9 | "github.com/vultr/govultr/v3" 10 | "github.com/vultr/vultr-cli/v3/cmd/utils" 11 | "github.com/vultr/vultr-cli/v3/pkg/cli" 12 | ) 13 | 14 | var ( 15 | backupsLong = `` 16 | backupsExample = `` 17 | listLong = `` 18 | listExample = `` 19 | getLong = `` 20 | getExample = `` 21 | ) 22 | 23 | // NewCmdBackups provides the backup command for the CLI 24 | func NewCmdBackups(base *cli.Base) *cobra.Command { 25 | o := &options{Base: base} 26 | 27 | cmd := &cobra.Command{ 28 | Use: "backups", 29 | Aliases: []string{"backup", "b"}, 30 | Short: "Display backups", 31 | Long: backupsLong, 32 | Example: backupsExample, 33 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 34 | utils.SetOptions(o.Base, cmd, args) 35 | if !o.Base.HasAuth { 36 | return errors.New(utils.APIKeyError) 37 | } 38 | return nil 39 | }, 40 | } 41 | 42 | // List 43 | list := &cobra.Command{ 44 | Use: "list", 45 | Short: "List all backups", 46 | Aliases: []string{"l"}, 47 | Long: listLong, 48 | Example: listExample, 49 | RunE: func(cmd *cobra.Command, args []string) error { 50 | o.Base.Options = utils.GetPaging(cmd) 51 | backups, meta, err := o.list() 52 | if err != nil { 53 | return fmt.Errorf("error retrieving backups list : %v", err) 54 | } 55 | data := &BackupsPrinter{Backups: backups, Meta: meta} 56 | o.Base.Printer.Display(data, err) 57 | 58 | return nil 59 | }, 60 | } 61 | 62 | list.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.") 63 | list.Flags().IntP( 64 | "per-page", 65 | "p", 66 | utils.PerPageDefault, 67 | fmt.Sprintf( 68 | "(optional) Number of items requested per page. Default is %d and Max is 500.", 69 | utils.PerPageDefault, 70 | ), 71 | ) 72 | 73 | // Get 74 | get := &cobra.Command{ 75 | Use: "get", 76 | Short: "Get a backup", 77 | Long: getLong, 78 | Example: getExample, 79 | Args: func(cmd *cobra.Command, args []string) error { 80 | if len(args) < 1 { 81 | return errors.New("please provide a backup ID") 82 | } 83 | return nil 84 | }, 85 | RunE: func(cmd *cobra.Command, args []string) error { 86 | backup, err := o.get() 87 | if err != nil { 88 | return fmt.Errorf("error retrieving backup : %v", err) 89 | } 90 | 91 | data := &BackupPrinter{Backup: backup} 92 | o.Base.Printer.Display(data, err) 93 | 94 | return nil 95 | }, 96 | } 97 | 98 | cmd.AddCommand(get, list) 99 | return cmd 100 | } 101 | 102 | type options struct { 103 | Base *cli.Base 104 | } 105 | 106 | func (b *options) list() ([]govultr.Backup, *govultr.Meta, error) { 107 | backups, meta, _, err := b.Base.Client.Backup.List(b.Base.Context, b.Base.Options) 108 | return backups, meta, err 109 | } 110 | 111 | func (b *options) get() (*govultr.Backup, error) { 112 | backup, _, err := b.Base.Client.Backup.Get(b.Base.Context, b.Base.Args[0]) 113 | return backup, err 114 | } 115 | -------------------------------------------------------------------------------- /cmd/blockstorage/printer.go: -------------------------------------------------------------------------------- 1 | package blockstorage 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | 7 | "github.com/vultr/govultr/v3" 8 | "github.com/vultr/vultr-cli/v3/cmd/printer" 9 | ) 10 | 11 | // BlockStoragesPrinter ... 12 | type BlockStoragesPrinter struct { 13 | BlockStorages []govultr.BlockStorage `json:"blocks"` 14 | Meta *govultr.Meta `json:"meta"` 15 | } 16 | 17 | // JSON ... 18 | func (b *BlockStoragesPrinter) JSON() []byte { 19 | return printer.MarshalObject(b, "json") 20 | } 21 | 22 | // YAML ... 23 | func (b *BlockStoragesPrinter) YAML() []byte { 24 | return printer.MarshalObject(b, "yaml") 25 | } 26 | 27 | // Columns ... 28 | func (b *BlockStoragesPrinter) Columns() [][]string { 29 | return [][]string{0: { 30 | "ID", 31 | "REGION ID", 32 | "INSTANCE ID", 33 | "SIZE GB", 34 | "STATUS", 35 | "LABEL", 36 | "BLOCK TYPE", 37 | "DATE CREATED", 38 | "MONTHLY COST", 39 | "MOUNT ID", 40 | }} 41 | } 42 | 43 | // Data ... 44 | func (b *BlockStoragesPrinter) Data() [][]string { 45 | if len(b.BlockStorages) == 0 { 46 | return [][]string{0: {"---", "---", "---", "---", "---", "---", "---", "---", "---", "---"}} 47 | } 48 | 49 | var data [][]string 50 | for i := range b.BlockStorages { 51 | data = append(data, []string{ 52 | b.BlockStorages[i].ID, 53 | b.BlockStorages[i].Region, 54 | b.BlockStorages[i].AttachedToInstance, 55 | strconv.Itoa(b.BlockStorages[i].SizeGB), 56 | b.BlockStorages[i].Status, 57 | b.BlockStorages[i].Label, 58 | b.BlockStorages[i].BlockType, 59 | b.BlockStorages[i].DateCreated, 60 | fmt.Sprintf("$%v", b.BlockStorages[i].Cost), 61 | b.BlockStorages[i].MountID, 62 | }) 63 | } 64 | 65 | return data 66 | } 67 | 68 | // Paging ... 69 | func (b *BlockStoragesPrinter) Paging() [][]string { 70 | return printer.NewPagingFromMeta(b.Meta).Compose() 71 | } 72 | 73 | // ====================================== 74 | 75 | // BlockStoragePrinter ... 76 | type BlockStoragePrinter struct { 77 | BlockStorage *govultr.BlockStorage `json:"block"` 78 | } 79 | 80 | // JSON ... 81 | func (b *BlockStoragePrinter) JSON() []byte { 82 | return printer.MarshalObject(b, "json") 83 | } 84 | 85 | // YAML ... 86 | func (b *BlockStoragePrinter) YAML() []byte { 87 | return printer.MarshalObject(b, "yaml") 88 | } 89 | 90 | // Columns ... 91 | func (b *BlockStoragePrinter) Columns() [][]string { 92 | return [][]string{0: { 93 | "ID", 94 | "REGION ID", 95 | "INSTANCE ID", 96 | "SIZE GB", 97 | "STATUS", 98 | "LABEL", 99 | "BLOCK TYPE", 100 | "DATE CREATED", 101 | "MONTHLY COST", 102 | "MOUNT ID", 103 | }} 104 | } 105 | 106 | // Data ... 107 | func (b *BlockStoragePrinter) Data() [][]string { 108 | return [][]string{0: { 109 | b.BlockStorage.ID, 110 | b.BlockStorage.Region, 111 | b.BlockStorage.AttachedToInstance, 112 | strconv.Itoa(b.BlockStorage.SizeGB), 113 | b.BlockStorage.Status, 114 | b.BlockStorage.Label, 115 | b.BlockStorage.BlockType, 116 | b.BlockStorage.DateCreated, 117 | fmt.Sprintf("$%v", b.BlockStorage.Cost), 118 | b.BlockStorage.MountID, 119 | }} 120 | } 121 | 122 | // Paging ... 123 | func (b *BlockStoragePrinter) Paging() [][]string { 124 | return nil 125 | } 126 | -------------------------------------------------------------------------------- /cmd/regions/printer.go: -------------------------------------------------------------------------------- 1 | package regions 2 | 3 | import ( 4 | "github.com/vultr/govultr/v3" 5 | 6 | "github.com/vultr/vultr-cli/v3/cmd/printer" 7 | ) 8 | 9 | // RegionsPrinter represents the regions data from the API and contains the 10 | // methods to format and print the data via the ResourceOutput interface 11 | type RegionsPrinter struct { 12 | Regions []govultr.Region `json:"regions"` 13 | Meta *govultr.Meta `json:"meta"` 14 | } 15 | 16 | // JSON provides the JSON formatted byte data 17 | func (r *RegionsPrinter) JSON() []byte { 18 | return printer.MarshalObject(r, "json") 19 | } 20 | 21 | // YAML provides the YAML formatted byte data 22 | func (r *RegionsPrinter) YAML() []byte { 23 | return printer.MarshalObject(r, "yaml") 24 | } 25 | 26 | // Columns provides the columns for the printer 27 | func (r *RegionsPrinter) Columns() [][]string { 28 | return [][]string{0: { 29 | "ID", 30 | "CITY", 31 | "COUNTRY", 32 | "CONTINENT", 33 | "OPTIONS", 34 | }} 35 | } 36 | 37 | // Data provides the data for the printer 38 | func (r *RegionsPrinter) Data() [][]string { 39 | data := [][]string{} 40 | 41 | if len(r.Regions) == 0 { 42 | data = append(data, []string{"---", "---", "---", "---", "---"}) 43 | return data 44 | } 45 | 46 | for i := range r.Regions { 47 | data = append(data, []string{ 48 | r.Regions[i].ID, 49 | r.Regions[i].City, 50 | r.Regions[i].Country, 51 | r.Regions[i].Continent, 52 | printer.ArrayOfStringsToString(r.Regions[i].Options), 53 | }) 54 | } 55 | 56 | return data 57 | } 58 | 59 | // Paging validates and forms the paging data for output 60 | func (r *RegionsPrinter) Paging() [][]string { 61 | return printer.NewPagingFromMeta(r.Meta).Compose() 62 | } 63 | 64 | // ====================================== 65 | 66 | // RegionsAvailabilityPrinter represents the plan availability data for a 67 | // region from the API and contains the methods to format and print the data 68 | // via the ResourceOutput interface 69 | type RegionsAvailabilityPrinter struct { 70 | Plans *govultr.PlanAvailability `json:"available_plans"` 71 | } 72 | 73 | // JSON provides the JSON formatted byte data 74 | func (r *RegionsAvailabilityPrinter) JSON() []byte { 75 | return printer.MarshalObject(r, "json") 76 | } 77 | 78 | // YAML provides the YAML formatted byte data 79 | func (r *RegionsAvailabilityPrinter) YAML() []byte { 80 | return printer.MarshalObject(r, "yaml") 81 | } 82 | 83 | // Columns provides the available plans columns for the printer 84 | func (r *RegionsAvailabilityPrinter) Columns() [][]string { 85 | return [][]string{0: { 86 | "AVAILABLE PLANS", 87 | }} 88 | } 89 | 90 | // Data provides the region availability plan data for the printer 91 | func (r *RegionsAvailabilityPrinter) Data() [][]string { 92 | data := [][]string{} 93 | 94 | if len(r.Plans.AvailablePlans) == 0 { 95 | data = append(data, []string{"---"}) 96 | return data 97 | } 98 | 99 | for i := range r.Plans.AvailablePlans { 100 | data = append(data, []string{ 101 | r.Plans.AvailablePlans[i], 102 | }) 103 | } 104 | 105 | return data 106 | } 107 | 108 | // Paging validates and forms the paging data for output 109 | func (r *RegionsAvailabilityPrinter) Paging() [][]string { 110 | return nil 111 | } 112 | -------------------------------------------------------------------------------- /cmd/iso/printer.go: -------------------------------------------------------------------------------- 1 | package iso 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | "github.com/vultr/vultr-cli/v3/cmd/printer" 8 | ) 9 | 10 | // ISOsPrinter ... 11 | type ISOsPrinter struct { 12 | ISOs []govultr.ISO `json:"isos"` 13 | Meta *govultr.Meta `json:"meta"` 14 | } 15 | 16 | // JSON ... 17 | func (i *ISOsPrinter) JSON() []byte { 18 | return printer.MarshalObject(i, "json") 19 | } 20 | 21 | // YAML ... 22 | func (i *ISOsPrinter) YAML() []byte { 23 | return printer.MarshalObject(i, "yaml") 24 | } 25 | 26 | // Columns ... 27 | func (i *ISOsPrinter) Columns() [][]string { 28 | return [][]string{0: { 29 | "ID", 30 | "FILE NAME", 31 | "SIZE", 32 | "STATUS", 33 | "MD5SUM", 34 | "SHA512SUM", 35 | "DATE CREATED", 36 | }} 37 | } 38 | 39 | // Data ... 40 | func (i *ISOsPrinter) Data() [][]string { 41 | if len(i.ISOs) == 0 { 42 | return [][]string{0: {"---", "---", "---", "---", "---", "---", "---"}} 43 | } 44 | 45 | var data [][]string 46 | for n := range i.ISOs { 47 | data = append(data, []string{ 48 | i.ISOs[n].ID, 49 | i.ISOs[n].FileName, 50 | strconv.Itoa(i.ISOs[n].Size), 51 | i.ISOs[n].Status, 52 | i.ISOs[n].MD5Sum, 53 | i.ISOs[n].SHA512Sum, 54 | i.ISOs[n].DateCreated, 55 | }) 56 | } 57 | 58 | return data 59 | } 60 | 61 | // Paging ... 62 | func (i *ISOsPrinter) Paging() [][]string { 63 | return printer.NewPagingFromMeta(i.Meta).Compose() 64 | } 65 | 66 | // ====================================== 67 | 68 | // ISOPrinter ... 69 | type ISOPrinter struct { 70 | ISO govultr.ISO `json:"iso"` 71 | } 72 | 73 | // JSON ... 74 | func (i *ISOPrinter) JSON() []byte { 75 | return printer.MarshalObject(i, "json") 76 | } 77 | 78 | // YAML ... 79 | func (i *ISOPrinter) YAML() []byte { 80 | return printer.MarshalObject(i, "yaml") 81 | } 82 | 83 | // Columns ... 84 | func (i *ISOPrinter) Columns() [][]string { 85 | return [][]string{0: { 86 | "ID", 87 | "FILE NAME", 88 | "SIZE", 89 | "STATUS", 90 | "MD5SUM", 91 | "SHA512SUM", 92 | "DATE CREATED", 93 | }} 94 | } 95 | 96 | // Data ... 97 | func (i *ISOPrinter) Data() [][]string { 98 | return [][]string{0: { 99 | i.ISO.ID, 100 | i.ISO.FileName, 101 | strconv.Itoa(i.ISO.Size), 102 | i.ISO.Status, 103 | i.ISO.MD5Sum, 104 | i.ISO.SHA512Sum, 105 | i.ISO.DateCreated, 106 | }} 107 | } 108 | 109 | // Paging ... 110 | func (i *ISOPrinter) Paging() [][]string { 111 | return nil 112 | } 113 | 114 | // ====================================== 115 | 116 | // PublicISOsPrinter ... 117 | type PublicISOsPrinter struct { 118 | ISOs []govultr.PublicISO `json:"public_isos"` 119 | Meta *govultr.Meta `json:"meta"` 120 | } 121 | 122 | // JSON ... 123 | func (i *PublicISOsPrinter) JSON() []byte { 124 | return printer.MarshalObject(i, "json") 125 | } 126 | 127 | // YAML ... 128 | func (i *PublicISOsPrinter) YAML() []byte { 129 | return printer.MarshalObject(i, "yaml") 130 | } 131 | 132 | // Columns ... 133 | func (i *PublicISOsPrinter) Columns() [][]string { 134 | return [][]string{0: {"ID", "NAME", "DESCRIPTION"}} 135 | } 136 | 137 | // Data ... 138 | func (i *PublicISOsPrinter) Data() [][]string { 139 | if len(i.ISOs) == 0 { 140 | return [][]string{0: {"---", "---", "---"}} 141 | } 142 | 143 | var data [][]string 144 | for n := range i.ISOs { 145 | data = append(data, []string{ 146 | i.ISOs[n].ID, 147 | i.ISOs[n].Name, 148 | i.ISOs[n].Description, 149 | }) 150 | } 151 | 152 | return data 153 | } 154 | 155 | // Paging ... 156 | func (i *PublicISOsPrinter) Paging() [][]string { 157 | return printer.NewPagingFromMeta(i.Meta).Compose() 158 | } 159 | -------------------------------------------------------------------------------- /cmd/inference/printer.go: -------------------------------------------------------------------------------- 1 | package inference 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | "github.com/vultr/vultr-cli/v3/cmd/printer" 8 | ) 9 | 10 | // InferenceSubsPrinter ... 11 | type InferenceSubsPrinter struct { 12 | InferenceSubs []govultr.Inference `json:"subscriptions"` 13 | } 14 | 15 | // JSON ... 16 | func (inf *InferenceSubsPrinter) JSON() []byte { 17 | return printer.MarshalObject(inf, "json") 18 | } 19 | 20 | // YAML ... 21 | func (inf *InferenceSubsPrinter) YAML() []byte { 22 | return printer.MarshalObject(inf, "yaml") 23 | } 24 | 25 | // Columns ... 26 | func (inf *InferenceSubsPrinter) Columns() [][]string { 27 | return [][]string{0: { 28 | "ID", 29 | "DATE CREATED", 30 | "LABEL", 31 | "API KEY", 32 | }} 33 | } 34 | 35 | // Data ... 36 | func (inf *InferenceSubsPrinter) Data() [][]string { 37 | if len(inf.InferenceSubs) == 0 { 38 | return [][]string{0: {"---", "---", "---", "---"}} 39 | } 40 | 41 | var data [][]string 42 | for i := range inf.InferenceSubs { 43 | data = append(data, []string{ 44 | inf.InferenceSubs[i].ID, 45 | inf.InferenceSubs[i].DateCreated, 46 | inf.InferenceSubs[i].Label, 47 | inf.InferenceSubs[i].APIKey, 48 | }) 49 | } 50 | 51 | return data 52 | } 53 | 54 | // Paging ... 55 | func (inf *InferenceSubsPrinter) Paging() [][]string { 56 | return nil 57 | } 58 | 59 | // ====================================== 60 | 61 | // InferenceSubPrinter ... 62 | type InferenceSubPrinter struct { 63 | InferenceSub *govultr.Inference `json:"subscription"` 64 | } 65 | 66 | // JSON ... 67 | func (inf *InferenceSubPrinter) JSON() []byte { 68 | return printer.MarshalObject(inf, "json") 69 | } 70 | 71 | // YAML ... 72 | func (inf *InferenceSubPrinter) YAML() []byte { 73 | return printer.MarshalObject(inf, "yaml") 74 | } 75 | 76 | // Columns ... 77 | func (inf *InferenceSubPrinter) Columns() [][]string { 78 | return [][]string{0: { 79 | "ID", 80 | "DATE CREATED", 81 | "LABEL", 82 | "API KEY", 83 | }} 84 | } 85 | 86 | // Data ... 87 | func (inf *InferenceSubPrinter) Data() [][]string { 88 | var data [][]string 89 | data = append(data, []string{ 90 | inf.InferenceSub.ID, 91 | inf.InferenceSub.DateCreated, 92 | inf.InferenceSub.Label, 93 | inf.InferenceSub.APIKey, 94 | }) 95 | 96 | return data 97 | } 98 | 99 | // Paging ... 100 | func (inf *InferenceSubPrinter) Paging() [][]string { 101 | return nil 102 | } 103 | 104 | // ====================================== 105 | 106 | // UsagePrinter ... 107 | type UsagePrinter struct { 108 | Usage *govultr.InferenceUsage `json:"usage"` 109 | } 110 | 111 | // JSON ... 112 | func (u *UsagePrinter) JSON() []byte { 113 | return printer.MarshalObject(u, "json") 114 | } 115 | 116 | // YAML ... 117 | func (u *UsagePrinter) YAML() []byte { 118 | return printer.MarshalObject(u, "yaml") 119 | } 120 | 121 | // Columns ... 122 | func (u *UsagePrinter) Columns() [][]string { 123 | return nil 124 | } 125 | 126 | // Data ... 127 | func (u *UsagePrinter) Data() [][]string { 128 | var data [][]string 129 | data = append(data, 130 | []string{"CHAT USAGE"}, 131 | []string{"CURRENT TOKENS", strconv.FormatInt(int64(u.Usage.Chat.CurrentTokens), 10)}, 132 | []string{"MONTHLY ALLOTMENT", strconv.FormatInt(int64(u.Usage.Chat.MonthlyAllotment), 10)}, 133 | []string{"OVERAGE", strconv.FormatInt(int64(u.Usage.Chat.Overage), 10)}, 134 | []string{" "}, 135 | []string{"AUDIO USAGE"}, 136 | []string{"TTS CHARACTERS", strconv.FormatInt(int64(u.Usage.Audio.TTSCharacters), 10)}, 137 | []string{"TTS (SM) CHARACTERS", strconv.FormatInt(int64(u.Usage.Audio.TTSSMCharacters), 10)}, 138 | ) 139 | 140 | return data 141 | } 142 | 143 | // Paging ... 144 | func (u *UsagePrinter) Paging() [][]string { 145 | return nil 146 | } 147 | -------------------------------------------------------------------------------- /cmd/vpc2/printer.go: -------------------------------------------------------------------------------- 1 | package vpc2 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | "github.com/vultr/vultr-cli/v3/cmd/printer" 8 | ) 9 | 10 | // VPC2sPrinter ... 11 | type VPC2sPrinter struct { 12 | VPC2s []govultr.VPC2 `json:"vpcs"` //nolint:staticcheck 13 | Meta *govultr.Meta `json:"meta"` 14 | } 15 | 16 | // JSON ... 17 | func (s *VPC2sPrinter) JSON() []byte { 18 | return printer.MarshalObject(s, "json") 19 | } 20 | 21 | // YAML ... 22 | func (s *VPC2sPrinter) YAML() []byte { 23 | return printer.MarshalObject(s, "yaml") 24 | } 25 | 26 | // Columns ... 27 | func (s *VPC2sPrinter) Columns() [][]string { 28 | return [][]string{0: { 29 | "ID", 30 | "DATE CREATED", 31 | "REGION", 32 | "DESCRIPTION", 33 | "IP BLOCK", 34 | "PREFIX LENGTH", 35 | }} 36 | } 37 | 38 | // Data ... 39 | func (s *VPC2sPrinter) Data() [][]string { 40 | if len(s.VPC2s) == 0 { 41 | return [][]string{0: {"---", "---", "---", "---", "---", "---"}} 42 | } 43 | 44 | var data [][]string 45 | for i := range s.VPC2s { 46 | data = append(data, []string{ 47 | s.VPC2s[i].ID, 48 | s.VPC2s[i].DateCreated, 49 | s.VPC2s[i].Region, 50 | s.VPC2s[i].Description, 51 | s.VPC2s[i].IPBlock, 52 | strconv.Itoa(s.VPC2s[i].PrefixLength), 53 | }) 54 | } 55 | 56 | return data 57 | } 58 | 59 | // Paging ... 60 | func (s *VPC2sPrinter) Paging() [][]string { 61 | return printer.NewPagingFromMeta(s.Meta).Compose() 62 | } 63 | 64 | // ====================================== 65 | 66 | // VPC2Printer ... 67 | type VPC2Printer struct { 68 | VPC2 *govultr.VPC2 `json:"vpc"` //nolint:staticcheck 69 | } 70 | 71 | // JSON ... 72 | func (s *VPC2Printer) JSON() []byte { 73 | return printer.MarshalObject(s, "json") 74 | } 75 | 76 | // YAML ... 77 | func (s *VPC2Printer) YAML() []byte { 78 | return printer.MarshalObject(s, "yaml") 79 | } 80 | 81 | // Columns ... 82 | func (s *VPC2Printer) Columns() [][]string { 83 | return [][]string{0: { 84 | "ID", 85 | "DATE CREATED", 86 | "REGION", 87 | "DESCRIPTION", 88 | "IP BLOCK", 89 | "PREFIX LENGTH", 90 | }} 91 | } 92 | 93 | // Data ... 94 | func (s *VPC2Printer) Data() [][]string { 95 | return [][]string{0: { 96 | s.VPC2.ID, 97 | s.VPC2.DateCreated, 98 | s.VPC2.Region, 99 | s.VPC2.Description, 100 | s.VPC2.IPBlock, 101 | strconv.Itoa(s.VPC2.PrefixLength), 102 | }} 103 | } 104 | 105 | // Paging ... 106 | func (s *VPC2Printer) Paging() [][]string { 107 | return nil 108 | } 109 | 110 | // ====================================== 111 | 112 | // VPC2NodesPrinter ... 113 | type VPC2NodesPrinter struct { 114 | Nodes []govultr.VPC2Node `json:"nodes"` 115 | Meta *govultr.Meta `json:"meta"` 116 | } 117 | 118 | // JSON ... 119 | func (s *VPC2NodesPrinter) JSON() []byte { 120 | return printer.MarshalObject(s, "json") 121 | } 122 | 123 | // YAML ... 124 | func (s *VPC2NodesPrinter) YAML() []byte { 125 | return printer.MarshalObject(s, "yaml") 126 | } 127 | 128 | // Columns ... 129 | func (s *VPC2NodesPrinter) Columns() [][]string { 130 | return [][]string{0: { 131 | "ID", 132 | "IP ADDRESS", 133 | "MAC ADDRESS", 134 | "DESCRIPTION", 135 | "TYPE", 136 | "NODE STATUS", 137 | }} 138 | } 139 | 140 | // Data ... 141 | func (s *VPC2NodesPrinter) Data() [][]string { 142 | if len(s.Nodes) == 0 { 143 | return [][]string{0: {"---", "---", "---", "---", "---", "---"}} 144 | } 145 | 146 | var data [][]string 147 | for i := range s.Nodes { 148 | data = append(data, []string{ 149 | s.Nodes[i].ID, 150 | s.Nodes[i].IPAddress, 151 | strconv.Itoa(s.Nodes[i].MACAddress), 152 | s.Nodes[i].Description, 153 | s.Nodes[i].Type, 154 | s.Nodes[i].NodeStatus, 155 | }) 156 | } 157 | 158 | return data 159 | } 160 | 161 | // Paging ... 162 | func (s *VPC2NodesPrinter) Paging() [][]string { 163 | return printer.NewPagingFromMeta(s.Meta).Compose() 164 | } 165 | -------------------------------------------------------------------------------- /cmd/regions/regions.go: -------------------------------------------------------------------------------- 1 | // Package regions provides the functionality for the CLI to access regions 2 | package regions 3 | 4 | import ( 5 | "context" 6 | "errors" 7 | "fmt" 8 | 9 | "github.com/spf13/cobra" 10 | "github.com/vultr/govultr/v3" 11 | "github.com/vultr/vultr-cli/v3/cmd/utils" 12 | "github.com/vultr/vultr-cli/v3/pkg/cli" 13 | ) 14 | 15 | var ( 16 | regionLong = `Get all available regions for Vultr.` 17 | regionExample = ` 18 | # Full example 19 | vultr-cli regions 20 | ` 21 | 22 | listLong = `List all regions that Vultr has available.` 23 | listExample = ` 24 | # Full example 25 | vultr-cli regions list 26 | 27 | # Full example with paging 28 | vultr-cli regions list --per-page=1 --cursor="bmV4dF9fQU1T" 29 | 30 | # Shortened with alias commands 31 | vultr-cli r l 32 | ` 33 | 34 | availLong = `Get all available plans in a given region.` 35 | availExample = ` 36 | # Full example 37 | vultr-cli regions availability ewr 38 | 39 | # Full example with paging 40 | vultr-cli regions availability ewr 41 | 42 | # Shortened with alias commands 43 | vultr-cli r a ewr 44 | ` 45 | ) 46 | 47 | // NewCmdRegion creates a cobra command for Regions 48 | func NewCmdRegion(base *cli.Base) *cobra.Command { 49 | o := &options{Base: base} 50 | 51 | cmd := &cobra.Command{ 52 | Use: "regions", 53 | Short: "Display regions information", 54 | Aliases: []string{"r", "region"}, 55 | Long: regionLong, 56 | Example: regionExample, 57 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 58 | utils.SetOptions(o.Base, cmd, args) 59 | return nil 60 | }, 61 | } 62 | 63 | list := &cobra.Command{ 64 | Use: "list", 65 | Short: "List regions", 66 | Aliases: []string{"l"}, 67 | Long: listLong, 68 | Example: listExample, 69 | RunE: func(cmd *cobra.Command, args []string) error { 70 | o.Base.Options = utils.GetPaging(cmd) 71 | 72 | regions, meta, err := o.list() 73 | if err != nil { 74 | return fmt.Errorf("error retrieving region list : %v", err) 75 | } 76 | 77 | data := &RegionsPrinter{Regions: regions, Meta: meta} 78 | o.Base.Printer.Display(data, err) 79 | 80 | return nil 81 | }, 82 | } 83 | list.Flags().StringP("cursor", "c", "", "(optional) cursor for paging.") 84 | list.Flags().IntP( 85 | "per-page", 86 | "p", 87 | utils.PerPageDefault, 88 | fmt.Sprintf( 89 | "(optional) Number of items requested per page. Default is %d and Max is 500.", 90 | utils.PerPageDefault, 91 | ), 92 | ) 93 | 94 | availability := &cobra.Command{ 95 | Use: "availability ", 96 | Short: "List available plans by region", 97 | Aliases: []string{"a"}, 98 | Long: availLong, 99 | Example: availExample, 100 | Args: func(cmd *cobra.Command, args []string) error { 101 | if len(args) < 1 { 102 | return errors.New("please provide a region ID") 103 | } 104 | return nil 105 | }, 106 | RunE: func(cmd *cobra.Command, args []string) error { 107 | avail, err := o.availability() 108 | if err != nil { 109 | return fmt.Errorf("error retrieving region availability : %v", err) 110 | } 111 | 112 | data := &RegionsAvailabilityPrinter{Plans: avail} 113 | o.Base.Printer.Display(data, err) 114 | 115 | return nil 116 | }, 117 | } 118 | availability.Flags().StringP( 119 | "type", 120 | "t", 121 | "", 122 | `type of plans for which to include availability. Possible values: 123 | 'vc2', 'vdc, 'vhf', 'vbm'. Defaults to all Instances plans.`, 124 | ) 125 | 126 | cmd.AddCommand( 127 | list, 128 | availability, 129 | ) 130 | 131 | return cmd 132 | } 133 | 134 | type options struct { 135 | Base *cli.Base 136 | PlanType string 137 | } 138 | 139 | func (o *options) list() ([]govultr.Region, *govultr.Meta, error) { 140 | list, meta, _, err := o.Base.Client.Region.List(context.Background(), o.Base.Options) 141 | return list, meta, err 142 | } 143 | 144 | func (o *options) availability() (*govultr.PlanAvailability, error) { 145 | avail, _, err := o.Base.Client.Region.Availability(context.Background(), o.Base.Args[0], o.PlanType) 146 | return avail, err 147 | } 148 | -------------------------------------------------------------------------------- /cmd/plans/printer.go: -------------------------------------------------------------------------------- 1 | package plans 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | "github.com/vultr/vultr-cli/v3/cmd/printer" 8 | "github.com/vultr/vultr-cli/v3/cmd/utils" 9 | ) 10 | 11 | // PlansPrinter represents the plans data from the API 12 | type PlansPrinter struct { 13 | Plans []govultr.Plan `json:"plans"` 14 | Meta *govultr.Meta `json:"meta"` 15 | } 16 | 17 | // JSON provides the JSON formatted byte data 18 | func (p *PlansPrinter) JSON() []byte { 19 | return printer.MarshalObject(p, "json") 20 | } 21 | 22 | // YAML provides the YAML formatted byte data 23 | func (p *PlansPrinter) YAML() []byte { 24 | return printer.MarshalObject(p, "yaml") 25 | } 26 | 27 | // Columns provides the plan columns for the printer 28 | func (p *PlansPrinter) Columns() [][]string { 29 | return [][]string{0: { 30 | "ID", 31 | "VCPU COUNT", 32 | "RAM", 33 | "DISK", 34 | "DISK COUNT", 35 | "BANDWIDTH GB", 36 | "PRICE PER MONTH", 37 | "TYPE", 38 | "GPU VRAM", 39 | "GPU TYPE", 40 | "REGIONS", 41 | }} 42 | } 43 | 44 | // Data provides the plan data for the printer 45 | func (p *PlansPrinter) Data() [][]string { 46 | data := [][]string{} 47 | 48 | if len(p.Plans) == 0 { 49 | data = append(data, []string{"---", "---", "---", "---", "---", "---", "---", "---", "---", "---", "---"}) 50 | return data 51 | } 52 | 53 | for i := range p.Plans { 54 | data = append(data, []string{ 55 | p.Plans[i].ID, 56 | strconv.Itoa(p.Plans[i].VCPUCount), 57 | strconv.Itoa(p.Plans[i].RAM), 58 | strconv.Itoa(p.Plans[i].Disk), 59 | strconv.Itoa(p.Plans[i].DiskCount), 60 | strconv.Itoa(p.Plans[i].Bandwidth), 61 | strconv.FormatFloat(float64(p.Plans[i].MonthlyCost), 'f', utils.FloatPrecision, 32), 62 | p.Plans[i].Type, 63 | strconv.Itoa(p.Plans[i].GPUVRAM), 64 | p.Plans[i].GPUType, 65 | printer.ArrayOfStringsToString(p.Plans[i].Locations), 66 | }) 67 | } 68 | 69 | return data 70 | } 71 | 72 | // Paging validates and forms the paging data for output 73 | func (p *PlansPrinter) Paging() [][]string { 74 | return printer.NewPagingFromMeta(p.Meta).Compose() 75 | } 76 | 77 | // ====================================== 78 | 79 | // MetalPlansPrinter represents the bare metal plans data from the API 80 | type MetalPlansPrinter struct { 81 | Plans []govultr.BareMetalPlan `json:"plans_metal"` 82 | Meta *govultr.Meta `json:"meta"` 83 | } 84 | 85 | // JSON provides the JSON formatted byte data 86 | func (m *MetalPlansPrinter) JSON() []byte { 87 | return printer.MarshalObject(m, "json") 88 | } 89 | 90 | // YAML provides the YAML formatted byte data 91 | func (m *MetalPlansPrinter) YAML() []byte { 92 | return printer.MarshalObject(m, "yaml") 93 | } 94 | 95 | // Columns provides the plan columns for the printer 96 | func (m *MetalPlansPrinter) Columns() [][]string { 97 | return [][]string{0: { 98 | "ID", 99 | "CPU COUNT", 100 | "CPU MODEL", 101 | "CPU THREADS", 102 | "RAM", 103 | "DISK", 104 | "DISK COUNT", 105 | "BANDWIDTH GB", 106 | "PRICE PER MONTH", 107 | "TYPE", 108 | "REGIONS", 109 | }} 110 | } 111 | 112 | // Data provides the plan data for the printer 113 | func (m *MetalPlansPrinter) Data() [][]string { 114 | data := [][]string{} 115 | 116 | if len(m.Plans) == 0 { 117 | data = append(data, []string{"---", "---", "---", "---", "---", "---", "---", "---", "---", "---", "---"}) 118 | return data 119 | } 120 | 121 | for i := range m.Plans { 122 | data = append(data, []string{ 123 | m.Plans[i].ID, 124 | strconv.Itoa(m.Plans[i].CPUCount), 125 | m.Plans[i].CPUModel, 126 | strconv.Itoa(m.Plans[i].CPUThreads), 127 | strconv.Itoa(m.Plans[i].RAM), 128 | strconv.Itoa(m.Plans[i].Disk), 129 | strconv.Itoa(m.Plans[i].DiskCount), 130 | strconv.Itoa(m.Plans[i].Bandwidth), 131 | strconv.FormatFloat(float64(m.Plans[i].MonthlyCost), 'f', utils.FloatPrecision, 32), 132 | m.Plans[i].Type, 133 | printer.ArrayOfStringsToString(m.Plans[i].Locations), 134 | }) 135 | } 136 | 137 | return data 138 | } 139 | 140 | // Paging validates and forms the paging data for output 141 | func (m *MetalPlansPrinter) Paging() [][]string { 142 | return printer.NewPagingFromMeta(m.Meta).Compose() 143 | } 144 | -------------------------------------------------------------------------------- /cmd/plans/plans.go: -------------------------------------------------------------------------------- 1 | // Package plans provides the functionality for the CLI to access plans 2 | package plans 3 | 4 | import ( 5 | "context" 6 | "fmt" 7 | 8 | "github.com/spf13/cobra" 9 | "github.com/vultr/govultr/v3" 10 | "github.com/vultr/vultr-cli/v3/cmd/utils" 11 | "github.com/vultr/vultr-cli/v3/pkg/cli" 12 | ) 13 | 14 | var ( 15 | planLong = `Plans will retrieve available plans for instances or bare metal.` 16 | planExample = ` 17 | # Example 18 | vultr-cli plans 19 | ` 20 | 21 | listLong = `List all available instances plans on Vultr.` 22 | listExample = ` 23 | # Full example 24 | vultr-cli plans list 25 | 26 | # Full example with paging 27 | vultr-cli plans list --type="vhf" --per-page=1 --cursor="bmV4dF9fdmhmLTFjLTFnYg==" 28 | 29 | # Shortened with alias commands 30 | vultr-cli p l 31 | ` 32 | 33 | metalListLong = `Get plans for bare-metal servers` 34 | metalListExample = ` 35 | # Full example 36 | vultr-cli plans metal 37 | 38 | # Full example with paging 39 | vultr-cli plans metal --per-page=1 --cursor="bmV4dF9fdmJtLTRjLTMyZ2I=" 40 | 41 | # Shortened with alias commands 42 | vultr-cli p m 43 | ` 44 | ) 45 | 46 | // NewCmdPlan returns the cobra command for Plans 47 | func NewCmdPlan(base *cli.Base) *cobra.Command { 48 | o := &options{Base: base} 49 | 50 | cmd := &cobra.Command{ 51 | Use: "plans", 52 | Short: "Display available plan information", 53 | Aliases: []string{"p", "plan"}, 54 | Long: planLong, 55 | Example: planExample, 56 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 57 | utils.SetOptions(o.Base, cmd, args) 58 | return nil 59 | }, 60 | } 61 | 62 | list := &cobra.Command{ 63 | Use: "list", 64 | Short: "List all instance plans", 65 | Aliases: []string{"l"}, 66 | Long: listLong, 67 | Example: listExample, 68 | RunE: func(cmd *cobra.Command, args []string) error { 69 | o.Base.Options = utils.GetPaging(cmd) 70 | 71 | planType, errTy := cmd.Flags().GetString("type") 72 | if errTy != nil { 73 | return fmt.Errorf("error parsing flag 'type' for plan list: %v", errTy) 74 | } 75 | 76 | o.PlanType = planType 77 | 78 | plans, meta, err := o.list() 79 | if err != nil { 80 | return fmt.Errorf("error getting plans : %v", err) 81 | } 82 | 83 | data := &PlansPrinter{Plans: plans, Meta: meta} 84 | o.Base.Printer.Display(data, err) 85 | 86 | return nil 87 | }, 88 | } 89 | 90 | list.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.") 91 | list.Flags().IntP( 92 | "per-page", 93 | "p", 94 | utils.PerPageDefault, 95 | fmt.Sprintf( 96 | "(optional) Number of items requested per page. Default is %d and Max is 500.", 97 | utils.PerPageDefault, 98 | ), 99 | ) 100 | list.Flags().StringP( 101 | "type", 102 | "t", 103 | "", 104 | `(optional) The type of plans to return. Possible values: 'vc2', 'vdc', 'vhf', 'dedicated'. 105 | Defaults to all Instances plans.`, 106 | ) 107 | 108 | metal := &cobra.Command{ 109 | Use: "metal", 110 | Short: "List all bare metal plans", 111 | Aliases: []string{"m"}, 112 | Long: metalListLong, 113 | Example: metalListExample, 114 | RunE: func(cmd *cobra.Command, args []string) error { 115 | o.Base.Options = utils.GetPaging(cmd) 116 | 117 | m, meta, err := o.metalList() 118 | if err != nil { 119 | return fmt.Errorf("error getting bare metal plans : %v", err) 120 | } 121 | 122 | data := &MetalPlansPrinter{Plans: m, Meta: meta} 123 | o.Base.Printer.Display(data, err) 124 | 125 | return nil 126 | }, 127 | } 128 | 129 | metal.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.") 130 | metal.Flags().IntP( 131 | "per-page", 132 | "p", 133 | utils.PerPageDefault, 134 | fmt.Sprintf( 135 | "(optional) Number of items requested per page. Default is %d and Max is 500.", 136 | utils.PerPageDefault, 137 | ), 138 | ) 139 | 140 | cmd.AddCommand(list, metal) 141 | return cmd 142 | } 143 | 144 | type options struct { 145 | Base *cli.Base 146 | PlanType string 147 | } 148 | 149 | func (o *options) list() ([]govultr.Plan, *govultr.Meta, error) { 150 | plans, meta, _, err := o.Base.Client.Plan.List(context.Background(), o.PlanType, o.Base.Options) 151 | return plans, meta, err 152 | } 153 | 154 | func (o *options) metalList() ([]govultr.BareMetalPlan, *govultr.Meta, error) { 155 | plans, meta, _, err := o.Base.Client.Plan.ListBareMetal(context.Background(), o.Base.Options) 156 | return plans, meta, err 157 | } 158 | -------------------------------------------------------------------------------- /cmd/logs/logs.go: -------------------------------------------------------------------------------- 1 | // Package logs provides the functionality for the CLI to access logs from the API 2 | package logs 3 | 4 | import ( 5 | "context" 6 | "errors" 7 | "fmt" 8 | "os" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/vultr/govultr/v3" 12 | "github.com/vultr/vultr-cli/v3/cmd/utils" 13 | "github.com/vultr/vultr-cli/v3/pkg/cli" 14 | ) 15 | 16 | var ( 17 | logsLong = `All commands related to the logs functionality` 18 | logsExample = ` 19 | vultr-cli logs 20 | ` 21 | 22 | listLong = `Retrieve all logs between the start and end timestamps, filtered by UUID, type or log level` 23 | listExample = ` 24 | # Full example 25 | vultr-cli logs list --start '2025-08-26T00:00:00Z' --end '2025-09-13T00:30:00Z' \ 26 | --uuid '8b903420-b2e3-4e4f-9f88-19efb30e1237' --type 'instances' 27 | 28 | # Shortened with aliased commands 29 | vultr-cli logs list -s '2025-08-26T00:00:00Z' -e '2025-09-13T00:30:00Z' \ 30 | -u '8b903420-b2e3-4e4f-9f88-19efb30e1237' -t 'instances' 31 | ` 32 | ) 33 | 34 | // NewCmdLogs provides the logs command to the CLI 35 | func NewCmdLogs(base *cli.Base) *cobra.Command { 36 | o := &options{Base: base} 37 | 38 | cmd := &cobra.Command{ 39 | Use: "logs", 40 | Short: "Commands to view logs", 41 | Aliases: []string{"log"}, 42 | Long: logsLong, 43 | Example: logsExample, 44 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 45 | utils.SetOptions(o.Base, cmd, args) 46 | if !o.Base.HasAuth { 47 | return errors.New(utils.APIKeyError) 48 | } 49 | 50 | return nil 51 | }, 52 | } 53 | 54 | // List 55 | list := &cobra.Command{ 56 | Use: "list", 57 | Short: "Retrieve logs", 58 | Aliases: []string{"l", "get"}, 59 | Long: listLong, 60 | Example: listExample, 61 | RunE: func(cmd *cobra.Command, args []string) error { 62 | start, err := cmd.Flags().GetString("start") 63 | if err != nil { 64 | return fmt.Errorf("error parsing flag 'start' for logs list : %v", err) 65 | } 66 | 67 | end, err := cmd.Flags().GetString("end") 68 | if err != nil { 69 | return fmt.Errorf("error parsing flag 'end' for logs list : %v", err) 70 | } 71 | 72 | level, err := cmd.Flags().GetString("level") 73 | if err != nil { 74 | return fmt.Errorf("error parsing flag 'level' for logs list : %v", err) 75 | } 76 | 77 | resType, err := cmd.Flags().GetString("type") 78 | if err != nil { 79 | return fmt.Errorf("error parsing flag 'type' for logs list : %v", err) 80 | } 81 | 82 | uuid, err := cmd.Flags().GetString("uuid") 83 | if err != nil { 84 | return fmt.Errorf("error parsing flag 'uuid' for logs list : %v", err) 85 | } 86 | 87 | o.LogsOptions = govultr.LogsOptions{ 88 | StartTime: start, 89 | EndTime: end, 90 | LogLevel: level, 91 | ResourceType: resType, 92 | ResourceID: uuid, 93 | } 94 | 95 | logs, meta, err := o.list() 96 | if err != nil { 97 | return fmt.Errorf("error retrieving logs list : %v", err) 98 | } 99 | 100 | data := &LogsPrinter{Logs: logs, Meta: meta} 101 | o.Base.Printer.Display(data, nil) 102 | 103 | return nil 104 | }, 105 | } 106 | list.Flags().StringP("start", "s", "", ` 107 | a UTC timestamp for the start of the time period from which to return logs (ex. 2025-06-26T00:00:00Z) 108 | `) 109 | if err := list.MarkFlagRequired("start"); err != nil { 110 | fmt.Printf("error marking logs list 'start' flag required: %v", err) 111 | os.Exit(1) 112 | } 113 | 114 | list.Flags().StringP("end", "e", "", ` 115 | a UTC timestamp for the end of the time period from which to return logs (ex. 2025-06-28T00:00:00Z). 116 | Must be later than the start timestamp and may not exceed 30 days and 1 hour difference from start. 117 | `) 118 | if err := list.MarkFlagRequired("end"); err != nil { 119 | fmt.Printf("error marking logs list 'end' flag required: %v", err) 120 | os.Exit(1) 121 | } 122 | 123 | list.Flags().StringP("level", "l", "", "filter logs by a level (info, debug, warning, error, critical)") 124 | list.Flags().StringP("type", "t", "", "filter logs by a resource type") 125 | list.Flags().StringP("uuid", "u", "", "filter logs by a resource UUID") 126 | 127 | cmd.AddCommand( 128 | list, 129 | ) 130 | 131 | return cmd 132 | } 133 | 134 | type options struct { 135 | Base *cli.Base 136 | LogsOptions govultr.LogsOptions 137 | } 138 | 139 | func (o *options) list() ([]govultr.Log, *govultr.LogsMeta, error) { 140 | logs, meta, _, err := o.Base.Client.Logs.List(context.Background(), o.LogsOptions) 141 | return logs, meta, err 142 | } 143 | -------------------------------------------------------------------------------- /cmd/iso/iso.go: -------------------------------------------------------------------------------- 1 | // Package iso provides the ISO related commands to the CLI 2 | package iso 3 | 4 | import ( 5 | "errors" 6 | "fmt" 7 | "os" 8 | 9 | "github.com/spf13/cobra" 10 | "github.com/vultr/govultr/v3" 11 | "github.com/vultr/vultr-cli/v3/cmd/printer" 12 | "github.com/vultr/vultr-cli/v3/cmd/utils" 13 | "github.com/vultr/vultr-cli/v3/pkg/cli" 14 | ) 15 | 16 | // NewCmdISO provides the CLI command for ISO functions 17 | func NewCmdISO(base *cli.Base) *cobra.Command { 18 | o := &options{Base: base} 19 | 20 | cmd := &cobra.Command{ 21 | Use: "iso", 22 | Short: "Commands to manage ISOs", 23 | Long: ``, 24 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 25 | utils.SetOptions(o.Base, cmd, args) 26 | if !o.Base.HasAuth { 27 | return errors.New(utils.APIKeyError) 28 | } 29 | return nil 30 | }, 31 | } 32 | 33 | // List 34 | list := &cobra.Command{ 35 | Use: "list", 36 | Short: "List all private ISOs available", 37 | Long: ``, 38 | RunE: func(cmd *cobra.Command, args []string) error { 39 | o.Base.Options = utils.GetPaging(cmd) 40 | 41 | isos, meta, err := o.list() 42 | if err != nil { 43 | return fmt.Errorf("error retrieving private ISO list : %v", err) 44 | } 45 | 46 | data := &ISOsPrinter{ISOs: isos, Meta: meta} 47 | o.Base.Printer.Display(data, nil) 48 | 49 | return nil 50 | }, 51 | } 52 | 53 | list.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.") 54 | list.Flags().IntP( 55 | "per-page", 56 | "p", 57 | utils.PerPageDefault, 58 | fmt.Sprintf( 59 | "(optional) Number of items requested per page. Default is %d and Max is 500.", 60 | utils.PerPageDefault, 61 | ), 62 | ) 63 | 64 | // Get 65 | get := &cobra.Command{ 66 | Use: "get ", 67 | Short: "Get a private ISO by ID", 68 | Long: ``, 69 | Args: func(cmd *cobra.Command, args []string) error { 70 | if len(args) < 1 { 71 | return errors.New("please provide an ISO ID") 72 | } 73 | return nil 74 | }, 75 | RunE: func(cmd *cobra.Command, args []string) error { 76 | iso, err := o.get() 77 | if err != nil { 78 | return fmt.Errorf("error getting ISO : %v", err) 79 | } 80 | 81 | data := &ISOPrinter{ISO: *iso} 82 | o.Base.Printer.Display(data, nil) 83 | 84 | return nil 85 | }, 86 | } 87 | 88 | // Create 89 | create := &cobra.Command{ 90 | Use: "create", 91 | Short: "Create an ISO from url", 92 | Long: ``, 93 | RunE: func(cmd *cobra.Command, args []string) error { 94 | url, errUR := cmd.Flags().GetString("url") 95 | if errUR != nil { 96 | return fmt.Errorf("error parsing flag 'url' for ISO create : %v", errUR) 97 | } 98 | 99 | o.CreateReq = &govultr.ISOReq{URL: url} 100 | 101 | iso, err := o.create() 102 | if err != nil { 103 | return fmt.Errorf("error creating ISO : %v", err) 104 | } 105 | 106 | data := &ISOPrinter{ISO: *iso} 107 | o.Base.Printer.Display(data, nil) 108 | 109 | return nil 110 | }, 111 | } 112 | 113 | create.Flags().StringP("url", "u", "", "url from where the ISO will be downloaded") 114 | if err := create.MarkFlagRequired("url"); err != nil { 115 | printer.Error(fmt.Errorf("error marking iso create 'url' flag required : %v", err)) 116 | os.Exit(1) 117 | } 118 | 119 | // Delete 120 | del := &cobra.Command{ 121 | Use: "delete ", 122 | Short: "Delete a private ISO", 123 | Aliases: []string{"destroy"}, 124 | Long: ``, 125 | Args: func(cmd *cobra.Command, args []string) error { 126 | if len(args) < 1 { 127 | return errors.New("please provide an ISO ID") 128 | } 129 | return nil 130 | }, 131 | RunE: func(cmd *cobra.Command, args []string) error { 132 | if err := o.del(); err != nil { 133 | return fmt.Errorf("error deleting ISO : %v", err) 134 | } 135 | 136 | o.Base.Printer.Display(printer.Info("ISO has been deleted"), nil) 137 | return nil 138 | }, 139 | } 140 | 141 | // Public ISOs 142 | public := &cobra.Command{ 143 | Use: "public", 144 | Short: "List all public ISOs", 145 | Long: ``, 146 | RunE: func(cmd *cobra.Command, args []string) error { 147 | o.Base.Options = utils.GetPaging(cmd) 148 | 149 | isos, meta, err := o.listPublic() 150 | if err != nil { 151 | return fmt.Errorf("error retrieving public ISO list : %v", err) 152 | } 153 | 154 | data := &PublicISOsPrinter{ISOs: isos, Meta: meta} 155 | o.Base.Printer.Display(data, nil) 156 | 157 | return nil 158 | }, 159 | } 160 | 161 | cmd.AddCommand(list, get, create, del, public) 162 | 163 | return cmd 164 | } 165 | 166 | type options struct { 167 | Base *cli.Base 168 | CreateReq *govultr.ISOReq 169 | } 170 | 171 | func (o *options) list() ([]govultr.ISO, *govultr.Meta, error) { 172 | isos, meta, _, err := o.Base.Client.ISO.List(o.Base.Context, o.Base.Options) 173 | return isos, meta, err 174 | } 175 | 176 | func (o *options) get() (*govultr.ISO, error) { 177 | iso, _, err := o.Base.Client.ISO.Get(o.Base.Context, o.Base.Args[0]) 178 | return iso, err 179 | } 180 | 181 | func (o *options) create() (*govultr.ISO, error) { 182 | iso, _, err := o.Base.Client.ISO.Create(o.Base.Context, o.CreateReq) 183 | return iso, err 184 | } 185 | 186 | func (o *options) del() error { 187 | return o.Base.Client.ISO.Delete(o.Base.Context, o.Base.Args[0]) 188 | } 189 | 190 | func (o *options) listPublic() ([]govultr.PublicISO, *govultr.Meta, error) { 191 | isos, meta, _, err := o.Base.Client.ISO.ListPublic(o.Base.Context, o.Base.Options) 192 | return isos, meta, err 193 | } 194 | -------------------------------------------------------------------------------- /cmd/firewall/printer.go: -------------------------------------------------------------------------------- 1 | package firewall 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | "github.com/vultr/vultr-cli/v3/cmd/printer" 8 | "github.com/vultr/vultr-cli/v3/cmd/utils" 9 | ) 10 | 11 | // FirewallGroupsPrinter ... 12 | type FirewallGroupsPrinter struct { 13 | Groups []govultr.FirewallGroup `json:"firewall_groups"` 14 | Meta *govultr.Meta `json:"meta"` 15 | } 16 | 17 | // JSON ... 18 | func (f *FirewallGroupsPrinter) JSON() []byte { 19 | return printer.MarshalObject(f, "json") 20 | } 21 | 22 | // YAML ... 23 | func (f *FirewallGroupsPrinter) YAML() []byte { 24 | return printer.MarshalObject(f, "yaml") 25 | } 26 | 27 | // Columns ... 28 | func (f *FirewallGroupsPrinter) Columns() [][]string { 29 | return [][]string{0: { 30 | "ID", 31 | "DATE CREATED", 32 | "DATE MODIFIED", 33 | "INSTANCE COUNT", 34 | "RULE COUNT", 35 | "MAX RULE COUNT", 36 | "DESCRIPTION", 37 | }} 38 | } 39 | 40 | // Data ... 41 | func (f *FirewallGroupsPrinter) Data() [][]string { 42 | if len(f.Groups) == 0 { 43 | return [][]string{0: {"---", "---", "---", "---", "---", "---", "---"}} 44 | } 45 | 46 | var data [][]string 47 | for i := range f.Groups { 48 | data = append(data, []string{ 49 | f.Groups[i].ID, 50 | f.Groups[i].DateCreated, 51 | f.Groups[i].DateModified, 52 | strconv.Itoa(f.Groups[i].InstanceCount), 53 | strconv.Itoa(f.Groups[i].RuleCount), 54 | strconv.Itoa(f.Groups[i].MaxRuleCount), 55 | f.Groups[i].Description, 56 | }) 57 | } 58 | 59 | return data 60 | } 61 | 62 | // Paging ... 63 | func (f *FirewallGroupsPrinter) Paging() [][]string { 64 | return printer.NewPagingFromMeta(f.Meta).Compose() 65 | } 66 | 67 | // ====================================== 68 | 69 | // FirewallGroupPrinter ... 70 | type FirewallGroupPrinter struct { 71 | Group govultr.FirewallGroup `json:"firewall_group"` 72 | } 73 | 74 | // JSON ... 75 | func (f *FirewallGroupPrinter) JSON() []byte { 76 | return printer.MarshalObject(f, "json") 77 | } 78 | 79 | // YAML ... 80 | func (f *FirewallGroupPrinter) YAML() []byte { 81 | return printer.MarshalObject(f, "yaml") 82 | } 83 | 84 | // Columns ... 85 | func (f *FirewallGroupPrinter) Columns() [][]string { 86 | return [][]string{0: { 87 | "ID", 88 | "DATE CREATED", 89 | "DATE MODIFIED", 90 | "INSTANCE COUNT", 91 | "RULE COUNT", 92 | "MAX RULE COUNT", 93 | "DESCRIPTION", 94 | }} 95 | } 96 | 97 | // Data ... 98 | func (f *FirewallGroupPrinter) Data() [][]string { 99 | return [][]string{0: { 100 | f.Group.ID, 101 | f.Group.DateCreated, 102 | f.Group.DateModified, 103 | strconv.Itoa(f.Group.InstanceCount), 104 | strconv.Itoa(f.Group.RuleCount), 105 | strconv.Itoa(f.Group.MaxRuleCount), 106 | f.Group.Description, 107 | }} 108 | } 109 | 110 | // Paging ... 111 | func (f *FirewallGroupPrinter) Paging() [][]string { 112 | return nil 113 | } 114 | 115 | // ====================================== 116 | 117 | // FirewallRulesPrinter ... 118 | type FirewallRulesPrinter struct { 119 | Rules []govultr.FirewallRule `json:"firewall_rules"` 120 | Meta *govultr.Meta `json:"meta"` 121 | } 122 | 123 | // JSON ... 124 | func (f *FirewallRulesPrinter) JSON() []byte { 125 | return printer.MarshalObject(f, "json") 126 | } 127 | 128 | // YAML ... 129 | func (f *FirewallRulesPrinter) YAML() []byte { 130 | return printer.MarshalObject(f, "yaml") 131 | } 132 | 133 | // Columns ... 134 | func (f *FirewallRulesPrinter) Columns() [][]string { 135 | return [][]string{0: { 136 | "RULE NUMBER", 137 | "ACTION", 138 | "TYPE", 139 | "PROTOCOL", 140 | "PORT", 141 | "NETWORK", 142 | "SOURCE", 143 | "NOTES", 144 | }} 145 | } 146 | 147 | // Data ... 148 | func (f *FirewallRulesPrinter) Data() [][]string { 149 | if len(f.Rules) == 0 { 150 | return [][]string{0: {"---", "---", "---", "---", "---", "---", "---", "---"}} 151 | } 152 | 153 | var data [][]string 154 | for i := range f.Rules { 155 | data = append(data, []string{ 156 | strconv.Itoa(f.Rules[i].ID), 157 | f.Rules[i].Action, 158 | f.Rules[i].IPType, 159 | f.Rules[i].Protocol, 160 | f.Rules[i].Port, 161 | utils.FormatFirewallNetwork(f.Rules[i].Subnet, f.Rules[i].SubnetSize), 162 | utils.GetFirewallSource(f.Rules[i].Source), 163 | f.Rules[i].Notes, 164 | }) 165 | } 166 | 167 | return data 168 | } 169 | 170 | // Paging ... 171 | func (f *FirewallRulesPrinter) Paging() [][]string { 172 | return printer.NewPagingFromMeta(f.Meta).Compose() 173 | } 174 | 175 | // ====================================== 176 | 177 | // FirewallRulePrinter ... 178 | type FirewallRulePrinter struct { 179 | Rule govultr.FirewallRule `json:"firewall_rule"` 180 | } 181 | 182 | // JSON ... 183 | func (f *FirewallRulePrinter) JSON() []byte { 184 | return printer.MarshalObject(f, "json") 185 | } 186 | 187 | // YAML ... 188 | func (f *FirewallRulePrinter) YAML() []byte { 189 | return printer.MarshalObject(f, "yaml") 190 | } 191 | 192 | // Columns ... 193 | func (f *FirewallRulePrinter) Columns() [][]string { 194 | return [][]string{0: { 195 | "RULE NUMBER", 196 | "ACTION", 197 | "TYPE", 198 | "PROTOCOL", 199 | "PORT", 200 | "NETWORK", 201 | "SOURCE", 202 | "NOTES", 203 | }} 204 | } 205 | 206 | // Data ... 207 | func (f *FirewallRulePrinter) Data() [][]string { 208 | return [][]string{0: { 209 | strconv.Itoa(f.Rule.ID), 210 | f.Rule.Action, 211 | f.Rule.IPType, 212 | f.Rule.Protocol, 213 | f.Rule.Port, 214 | utils.FormatFirewallNetwork(f.Rule.Subnet, f.Rule.SubnetSize), 215 | utils.GetFirewallSource(f.Rule.Source), 216 | f.Rule.Notes, 217 | }} 218 | } 219 | 220 | // Paging ... 221 | func (f *FirewallRulePrinter) Paging() [][]string { 222 | return nil 223 | } 224 | -------------------------------------------------------------------------------- /cmd/account/printer.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | 7 | "github.com/vultr/govultr/v3" 8 | "github.com/vultr/vultr-cli/v3/cmd/printer" 9 | "github.com/vultr/vultr-cli/v3/cmd/utils" 10 | ) 11 | 12 | // AccountPrinter ... 13 | type AccountPrinter struct { 14 | Account *govultr.Account `json:"account"` 15 | } 16 | 17 | // JSON ... 18 | func (a *AccountPrinter) JSON() []byte { 19 | return printer.MarshalObject(a, "json") 20 | } 21 | 22 | // YAML ... 23 | func (a *AccountPrinter) YAML() []byte { 24 | return printer.MarshalObject(a, "yaml") 25 | } 26 | 27 | // Columns ... 28 | func (a *AccountPrinter) Columns() [][]string { 29 | return [][]string{0: { 30 | "BALANCE", 31 | "PENDING CHARGES", 32 | "LAST PAYMENT DATE", 33 | "LAST PAYMENT AMOUNT", 34 | "NAME", 35 | "EMAIL", 36 | "ACLS", 37 | }} 38 | } 39 | 40 | // Data ... 41 | func (a *AccountPrinter) Data() [][]string { 42 | return [][]string{0: { 43 | strconv.FormatFloat(float64(a.Account.Balance), 'f', utils.FloatPrecision, 32), 44 | strconv.FormatFloat(float64(a.Account.PendingCharges), 'f', utils.FloatPrecision, 32), 45 | a.Account.LastPaymentDate, 46 | strconv.FormatFloat(float64(a.Account.LastPaymentAmount), 'f', utils.FloatPrecision, 32), 47 | a.Account.Name, 48 | a.Account.Email, 49 | printer.ArrayOfStringsToString(a.Account.ACL), 50 | }} 51 | } 52 | 53 | // Paging ... 54 | func (a *AccountPrinter) Paging() [][]string { 55 | return nil 56 | } 57 | 58 | // ====================================== 59 | 60 | // AccountPrinter ... 61 | type AccountBandwidthPrinter struct { 62 | Bandwidth *govultr.AccountBandwidth `json:"account_bandwidth"` 63 | } 64 | 65 | // JSON ... 66 | func (a *AccountBandwidthPrinter) JSON() []byte { 67 | return printer.MarshalObject(a, "json") 68 | } 69 | 70 | // YAML ... 71 | func (a *AccountBandwidthPrinter) YAML() []byte { 72 | return printer.MarshalObject(a, "yaml") 73 | } 74 | 75 | // Columns ... 76 | func (a *AccountBandwidthPrinter) Columns() [][]string { 77 | return [][]string{0: { 78 | "PERIOD", 79 | "GB IN", 80 | "GB OUT", 81 | "INSTANCE HOURS", 82 | "INSTANCE COUNT", 83 | "CREDITS INSTANCE", 84 | "CREDITS FREE", 85 | "CREDITS PURCHASED", 86 | "OVERAGE", 87 | "OVERAGE UNIT COST", 88 | "OVERAGE COST", 89 | }} 90 | } 91 | 92 | // Data ... 93 | func (a *AccountBandwidthPrinter) Data() [][]string { 94 | previousPeriod := fmt.Sprintf( 95 | "%s - %s", 96 | utils.ParseAPITimestamp(a.Bandwidth.PreviousMonth.TimestampStart), 97 | utils.ParseAPITimestamp(a.Bandwidth.PreviousMonth.TimestampEnd), 98 | ) 99 | 100 | currentPeriod := fmt.Sprintf( 101 | "%s - %s", 102 | utils.ParseAPITimestamp(a.Bandwidth.CurrentMonthToDate.TimestampStart), 103 | utils.ParseAPITimestamp(a.Bandwidth.CurrentMonthToDate.TimestampEnd), 104 | ) 105 | 106 | projectedPeriod := fmt.Sprintf( 107 | "%s - %s", 108 | utils.ParseAPITimestamp(a.Bandwidth.CurrentMonthProjected.TimestampStart), 109 | utils.ParseAPITimestamp(a.Bandwidth.CurrentMonthProjected.TimestampEnd), 110 | ) 111 | 112 | return [][]string{ 113 | 0: { 114 | previousPeriod, 115 | strconv.Itoa(a.Bandwidth.PreviousMonth.GBIn), 116 | strconv.Itoa(a.Bandwidth.PreviousMonth.GBOut), 117 | strconv.Itoa(a.Bandwidth.PreviousMonth.TotalInstanceHours), 118 | strconv.Itoa(a.Bandwidth.PreviousMonth.TotalInstanceCount), 119 | strconv.Itoa(a.Bandwidth.PreviousMonth.InstanceBandwidthCredits), 120 | strconv.Itoa(a.Bandwidth.PreviousMonth.FreeBandwidthCredits), 121 | strconv.Itoa(a.Bandwidth.PreviousMonth.PurchasedBandwidthCredits), 122 | strconv.FormatFloat(float64(a.Bandwidth.PreviousMonth.Overage), 'f', utils.FloatPrecision, 32), 123 | strconv.FormatFloat(float64(a.Bandwidth.PreviousMonth.OverageUnitCost), 'f', utils.FloatPrecision, 32), 124 | strconv.FormatFloat(float64(a.Bandwidth.PreviousMonth.OverageCost), 'f', utils.FloatPrecision, 32), 125 | }, 126 | 1: { 127 | currentPeriod, 128 | strconv.Itoa(a.Bandwidth.CurrentMonthToDate.GBIn), 129 | strconv.Itoa(a.Bandwidth.CurrentMonthToDate.GBOut), 130 | strconv.Itoa(a.Bandwidth.CurrentMonthToDate.TotalInstanceHours), 131 | strconv.Itoa(a.Bandwidth.CurrentMonthToDate.TotalInstanceCount), 132 | strconv.Itoa(a.Bandwidth.CurrentMonthToDate.InstanceBandwidthCredits), 133 | strconv.Itoa(a.Bandwidth.CurrentMonthToDate.FreeBandwidthCredits), 134 | strconv.Itoa(a.Bandwidth.CurrentMonthToDate.PurchasedBandwidthCredits), 135 | strconv.FormatFloat(float64(a.Bandwidth.CurrentMonthToDate.Overage), 'f', utils.FloatPrecision, 32), 136 | strconv.FormatFloat(float64(a.Bandwidth.CurrentMonthToDate.OverageUnitCost), 'f', utils.FloatPrecision, 32), 137 | strconv.FormatFloat(float64(a.Bandwidth.CurrentMonthToDate.OverageCost), 'f', utils.FloatPrecision, 32), 138 | }, 139 | 2: { 140 | projectedPeriod, 141 | strconv.Itoa(a.Bandwidth.CurrentMonthProjected.GBIn), 142 | strconv.Itoa(a.Bandwidth.CurrentMonthProjected.GBOut), 143 | strconv.Itoa(a.Bandwidth.CurrentMonthProjected.TotalInstanceHours), 144 | strconv.Itoa(a.Bandwidth.CurrentMonthProjected.TotalInstanceCount), 145 | strconv.Itoa(a.Bandwidth.CurrentMonthProjected.InstanceBandwidthCredits), 146 | strconv.Itoa(a.Bandwidth.CurrentMonthProjected.FreeBandwidthCredits), 147 | strconv.Itoa(a.Bandwidth.CurrentMonthProjected.PurchasedBandwidthCredits), 148 | strconv.FormatFloat(float64(a.Bandwidth.CurrentMonthProjected.Overage), 'f', utils.FloatPrecision, 32), 149 | strconv.FormatFloat(float64(a.Bandwidth.CurrentMonthProjected.OverageUnitCost), 'f', utils.FloatPrecision, 32), 150 | strconv.FormatFloat(float64(a.Bandwidth.CurrentMonthProjected.OverageCost), 'f', utils.FloatPrecision, 32), 151 | }, 152 | } 153 | } 154 | 155 | // Paging ... 156 | func (a *AccountBandwidthPrinter) Paging() [][]string { 157 | return nil 158 | } 159 | -------------------------------------------------------------------------------- /cmd/billing/printer.go: -------------------------------------------------------------------------------- 1 | // Package billing provides the account billing operations and 2 | // functionality for the CLI 3 | package billing 4 | 5 | import ( 6 | "strconv" 7 | 8 | "github.com/vultr/govultr/v3" 9 | "github.com/vultr/vultr-cli/v3/cmd/printer" 10 | "github.com/vultr/vultr-cli/v3/cmd/utils" 11 | ) 12 | 13 | // BillingHistoryPrinter ... 14 | type BillingHistoryPrinter struct { 15 | Billing []govultr.History `json:"billing_history"` 16 | Meta *govultr.Meta `json:"meta"` 17 | } 18 | 19 | // JSON ... 20 | func (b *BillingHistoryPrinter) JSON() []byte { 21 | return printer.MarshalObject(b, "json") 22 | } 23 | 24 | // YAML ... 25 | func (b *BillingHistoryPrinter) YAML() []byte { 26 | return printer.MarshalObject(b, "yaml") 27 | } 28 | 29 | // Columns ... 30 | func (b *BillingHistoryPrinter) Columns() [][]string { 31 | return [][]string{0: { 32 | "ID", 33 | "DATE", 34 | "TYPE", 35 | "DESCRIPTION", 36 | "AMOUNT", 37 | "BALANCE", 38 | }} 39 | } 40 | 41 | // Data ... 42 | func (b *BillingHistoryPrinter) Data() [][]string { 43 | if len(b.Billing) == 0 { 44 | return [][]string{0: {"---", "---", "---", "---", "---", "---"}} 45 | } 46 | 47 | var data [][]string 48 | for i := range b.Billing { 49 | data = append(data, []string{ 50 | strconv.Itoa(b.Billing[i].ID), 51 | b.Billing[i].Date, 52 | b.Billing[i].Type, 53 | b.Billing[i].Description, 54 | strconv.FormatFloat(float64(b.Billing[i].Amount), 'f', utils.FloatPrecision, 32), 55 | strconv.FormatFloat(float64(b.Billing[i].Balance), 'f', utils.FloatPrecision, 32), 56 | }) 57 | } 58 | return data 59 | } 60 | 61 | // Paging ... 62 | func (b *BillingHistoryPrinter) Paging() [][]string { 63 | return printer.NewPagingFromMeta(b.Meta).Compose() 64 | } 65 | 66 | // ====================================== 67 | 68 | // BillingInvoicesPrinter ... 69 | type BillingInvoicesPrinter struct { 70 | Invoices []govultr.Invoice `json:"billing_invoices"` 71 | Meta *govultr.Meta 72 | } 73 | 74 | // JSON ... 75 | func (b *BillingInvoicesPrinter) JSON() []byte { 76 | return printer.MarshalObject(b, "json") 77 | } 78 | 79 | // YAML ... 80 | func (b *BillingInvoicesPrinter) YAML() []byte { 81 | return printer.MarshalObject(b, "yaml") 82 | } 83 | 84 | // Columns ... 85 | func (b *BillingInvoicesPrinter) Columns() [][]string { 86 | return [][]string{0: { 87 | "ID", 88 | "DATE", 89 | "DESCRIPTION", 90 | "AMOUNT", 91 | "BALANCE", 92 | }} 93 | } 94 | 95 | // Data ... 96 | func (b *BillingInvoicesPrinter) Data() [][]string { 97 | if len(b.Invoices) == 0 { 98 | return [][]string{0: {"---", "---", "---", "---", "---"}} 99 | } 100 | 101 | var data [][]string 102 | for i := range b.Invoices { 103 | data = append(data, []string{ 104 | strconv.Itoa(b.Invoices[i].ID), 105 | b.Invoices[i].Date, 106 | b.Invoices[i].Description, 107 | strconv.FormatFloat(float64(b.Invoices[i].Amount), 'f', utils.FloatPrecision, 32), 108 | strconv.FormatFloat(float64(b.Invoices[i].Balance), 'f', utils.FloatPrecision, 32), 109 | }) 110 | } 111 | return data 112 | } 113 | 114 | // Paging ... 115 | func (b *BillingInvoicesPrinter) Paging() [][]string { 116 | return printer.NewPagingFromMeta(b.Meta).Compose() 117 | } 118 | 119 | // ====================================== 120 | 121 | // BillingInvoicePrinter ... 122 | type BillingInvoicePrinter struct { 123 | Invoice govultr.Invoice `json:"billing_invoice"` 124 | } 125 | 126 | // JSON ... 127 | func (b *BillingInvoicePrinter) JSON() []byte { 128 | return printer.MarshalObject(b, "json") 129 | } 130 | 131 | // YAML ... 132 | func (b *BillingInvoicePrinter) YAML() []byte { 133 | return printer.MarshalObject(b, "yaml") 134 | } 135 | 136 | // Columns ... 137 | func (b *BillingInvoicePrinter) Columns() [][]string { 138 | return [][]string{0: { 139 | "ID", 140 | "DATE", 141 | "DESCRIPTION", 142 | "AMOUNT", 143 | "BALANCE", 144 | }} 145 | } 146 | 147 | // Data ... 148 | func (b *BillingInvoicePrinter) Data() [][]string { 149 | return [][]string{0: { 150 | strconv.Itoa(b.Invoice.ID), 151 | b.Invoice.Date, 152 | b.Invoice.Description, 153 | strconv.FormatFloat(float64(b.Invoice.Amount), 'f', utils.FloatPrecision, 32), 154 | strconv.FormatFloat(float64(b.Invoice.Balance), 'f', utils.FloatPrecision, 32), 155 | }} 156 | } 157 | 158 | // Paging ... 159 | func (b *BillingInvoicePrinter) Paging() [][]string { 160 | return nil 161 | } 162 | 163 | // ====================================== 164 | 165 | // BillingInvoiceItemsPrinter ... 166 | type BillingInvoiceItemsPrinter struct { 167 | InvoiceItems []govultr.InvoiceItem `json:"invoice_items"` 168 | Meta *govultr.Meta `json:"meta"` 169 | } 170 | 171 | // JSON ... 172 | func (b *BillingInvoiceItemsPrinter) JSON() []byte { 173 | return printer.MarshalObject(b, "json") 174 | } 175 | 176 | // YAML ... 177 | func (b *BillingInvoiceItemsPrinter) YAML() []byte { 178 | return printer.MarshalObject(b, "yaml") 179 | } 180 | 181 | // Columns ... 182 | func (b *BillingInvoiceItemsPrinter) Columns() [][]string { 183 | return [][]string{0: { 184 | "DESCRIPTION", 185 | "PRODUCT", 186 | "START DATE", 187 | "END DATE", 188 | "UNITS", 189 | "UNIT TYPE", 190 | "UNIT PRICE", 191 | "TOTAL", 192 | }} 193 | } 194 | 195 | // Data ... 196 | func (b *BillingInvoiceItemsPrinter) Data() [][]string { 197 | if len(b.InvoiceItems) == 0 { 198 | return [][]string{0: {"---", "---", "---", "---", "---", "---", "---", "---"}} 199 | } 200 | 201 | var data [][]string 202 | for i := range b.InvoiceItems { 203 | data = append(data, []string{ 204 | b.InvoiceItems[i].Description, 205 | b.InvoiceItems[i].Product, 206 | b.InvoiceItems[i].StartDate, 207 | b.InvoiceItems[i].EndDate, 208 | strconv.Itoa(b.InvoiceItems[i].Units), 209 | b.InvoiceItems[i].UnitType, 210 | strconv.FormatFloat(float64(b.InvoiceItems[i].UnitPrice), 'f', utils.FloatPrecision, 32), 211 | strconv.FormatFloat(float64(b.InvoiceItems[i].Total), 'f', utils.FloatPrecision, 32), 212 | }) 213 | } 214 | 215 | return data 216 | } 217 | 218 | // Paging ... 219 | func (b *BillingInvoiceItemsPrinter) Paging() [][]string { 220 | return printer.NewPagingFromMeta(b.Meta).Compose() 221 | } 222 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | // Package cmd implements the command line commands relevant to the vultr-cli 2 | package cmd 3 | 4 | import ( 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | 9 | "github.com/spf13/cobra" 10 | "github.com/spf13/viper" 11 | "github.com/vultr/vultr-cli/v3/cmd/account" 12 | "github.com/vultr/vultr-cli/v3/cmd/applications" 13 | "github.com/vultr/vultr-cli/v3/cmd/backups" 14 | "github.com/vultr/vultr-cli/v3/cmd/baremetal" 15 | "github.com/vultr/vultr-cli/v3/cmd/billing" 16 | "github.com/vultr/vultr-cli/v3/cmd/blockstorage" 17 | "github.com/vultr/vultr-cli/v3/cmd/cdn" 18 | "github.com/vultr/vultr-cli/v3/cmd/containerregistry" 19 | "github.com/vultr/vultr-cli/v3/cmd/database" 20 | "github.com/vultr/vultr-cli/v3/cmd/dns" 21 | "github.com/vultr/vultr-cli/v3/cmd/firewall" 22 | "github.com/vultr/vultr-cli/v3/cmd/inference" 23 | "github.com/vultr/vultr-cli/v3/cmd/instance" 24 | "github.com/vultr/vultr-cli/v3/cmd/iso" 25 | "github.com/vultr/vultr-cli/v3/cmd/kubernetes" 26 | "github.com/vultr/vultr-cli/v3/cmd/loadbalancer" 27 | "github.com/vultr/vultr-cli/v3/cmd/logs" 28 | "github.com/vultr/vultr-cli/v3/cmd/marketplace" 29 | "github.com/vultr/vultr-cli/v3/cmd/objectstorage" 30 | "github.com/vultr/vultr-cli/v3/cmd/operatingsystems" 31 | "github.com/vultr/vultr-cli/v3/cmd/plans" 32 | "github.com/vultr/vultr-cli/v3/cmd/regions" 33 | "github.com/vultr/vultr-cli/v3/cmd/reservedip" 34 | "github.com/vultr/vultr-cli/v3/cmd/script" 35 | "github.com/vultr/vultr-cli/v3/cmd/snapshot" 36 | "github.com/vultr/vultr-cli/v3/cmd/sshkeys" 37 | "github.com/vultr/vultr-cli/v3/cmd/users" 38 | "github.com/vultr/vultr-cli/v3/cmd/version" 39 | "github.com/vultr/vultr-cli/v3/cmd/vpc" 40 | "github.com/vultr/vultr-cli/v3/cmd/vpc2" 41 | "github.com/vultr/vultr-cli/v3/pkg/cli" 42 | ) 43 | 44 | const ( 45 | userAgent = "vultr-cli/" + version.Version 46 | perPageDefault int = 100 47 | ) 48 | 49 | var ( 50 | cfgFile string 51 | output string 52 | ) 53 | 54 | // rootCmd represents the base command when called without any subcommands 55 | var rootCmd = &cobra.Command{ 56 | Use: "vultr-cli", 57 | Short: "vultr-cli is a command line interface for the Vultr API", 58 | Long: ``, 59 | SilenceUsage: true, 60 | } 61 | 62 | // Execute adds all child commands to the root command and sets flags appropriately. 63 | // This is called by main.main(). It only needs to happen once to the rootCmd. 64 | func Execute() { 65 | if err := rootCmd.Execute(); err != nil { 66 | os.Exit(1) 67 | } 68 | } 69 | 70 | func init() { 71 | configPath := configHome() 72 | 73 | // init the config file with viper 74 | initConfig() 75 | 76 | rootCmd.PersistentFlags().StringVar(&cfgFile, "config", configPath, "config file (default is $HOME/.vultr-cli.yaml)") 77 | if err := viper.BindPFlag("config", rootCmd.PersistentFlags().Lookup("config")); err != nil { 78 | fmt.Printf("error binding root pflag 'config': %v\n", err) 79 | } 80 | 81 | rootCmd.PersistentFlags().StringVarP(&output, "output", "o", "text", "output format [ text | json | yaml ]") 82 | if err := viper.BindPFlag("output", rootCmd.PersistentFlags().Lookup("output")); err != nil { 83 | fmt.Printf("error binding root pflag 'output': %v\n", err) 84 | } 85 | 86 | base := cli.NewCLIBase( 87 | os.Getenv("VULTR_API_KEY"), 88 | userAgent, 89 | output, 90 | ) 91 | 92 | rootCmd.AddCommand( 93 | account.NewCmdAccount(base), 94 | applications.NewCmdApplications(base), 95 | backups.NewCmdBackups(base), 96 | baremetal.NewCmdBareMetal(base), 97 | billing.NewCmdBilling(base), 98 | blockstorage.NewCmdBlockStorage(base), 99 | containerregistry.NewCmdContainerRegistry(base), 100 | cdn.NewCmdCDN(base), 101 | database.NewCmdDatabase(base), 102 | dns.NewCmdDNS(base), 103 | firewall.NewCmdFirewall(base), 104 | inference.NewCmdInference(base), 105 | iso.NewCmdISO(base), 106 | kubernetes.NewCmdKubernetes(base), 107 | loadbalancer.NewCmdLoadBalancer(base), 108 | logs.NewCmdLogs(base), 109 | marketplace.NewCmdMarketplace(base), 110 | operatingsystems.NewCmdOS(base), 111 | objectstorage.NewCmdObjectStorage(base), 112 | plans.NewCmdPlan(base), 113 | regions.NewCmdRegion(base), 114 | reservedip.NewCmdReservedIP(base), 115 | script.NewCmdScript(base), 116 | instance.NewCmdInstance(base), 117 | snapshot.NewCmdSnapshot(base), 118 | sshkeys.NewCmdSSHKey(base), 119 | users.NewCmdUser(base), 120 | version.NewCmdVersion(base), 121 | vpc.NewCmdVPC(base), 122 | vpc2.NewCmdVPC2(base), 123 | ) 124 | } 125 | 126 | // initConfig reads in config file to viper if it exists 127 | func initConfig() { 128 | configPath := viper.GetString("config") 129 | 130 | if configPath == "" { 131 | cfgDir, err := os.UserHomeDir() 132 | if err != nil { 133 | os.Exit(1) 134 | } 135 | configPath = fmt.Sprintf("%s/.vultr-cli.yaml", cfgDir) 136 | } 137 | 138 | viper.AutomaticEnv() 139 | viper.SetConfigType("yaml") 140 | viper.SetConfigFile(configPath) 141 | 142 | if err := viper.ReadInConfig(); err != nil { 143 | fmt.Println("Error Reading in file:", viper.ConfigFileUsed()) 144 | } 145 | } 146 | 147 | func configHome() string { 148 | // check for a config file in the user config directory 149 | configFolder, errConfig := os.UserConfigDir() 150 | if errConfig != nil { 151 | fmt.Printf("Unable to determine default user config directory : %v", errConfig) 152 | os.Exit(1) 153 | } 154 | 155 | configFile := fmt.Sprintf("%s/vultr-cli.yaml", configFolder) 156 | if _, err := os.Stat(configFile); err == nil { 157 | // if one exists, return the path 158 | return configFile 159 | } 160 | 161 | // check for a config file at ~/.vultr-cli.yaml 162 | configFolder, errHome := os.UserHomeDir() 163 | if errHome != nil { 164 | fmt.Printf("Unable to check user config in home directory: %v", errHome) 165 | os.Exit(1) 166 | } 167 | 168 | configFile = fmt.Sprintf("%s/.vultr-cli.yaml", configFolder) 169 | if _, err := os.Stat(configFile); err != nil { 170 | // if it doesn't exist, create one 171 | f, err := os.Create(filepath.Clean(configFile)) 172 | if err != nil { 173 | fmt.Printf("Unable to create default config file : %v", err) 174 | os.Exit(1) 175 | } 176 | 177 | defer func() { 178 | if errCls := f.Close(); errCls != nil { 179 | fmt.Printf("failed to close config file.. error: %v", errCls) 180 | } 181 | }() 182 | } 183 | 184 | return configFile 185 | } 186 | -------------------------------------------------------------------------------- /cmd/dns/printer.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | "github.com/vultr/vultr-cli/v3/cmd/printer" 8 | ) 9 | 10 | // DNSRecordsPrinter ... 11 | type DNSRecordsPrinter struct { 12 | Records []govultr.DomainRecord `json:"records"` 13 | Meta *govultr.Meta `json:"meta"` 14 | } 15 | 16 | // JSON ... 17 | func (d *DNSRecordsPrinter) JSON() []byte { 18 | return printer.MarshalObject(d, "json") 19 | } 20 | 21 | // YAML ... 22 | func (d *DNSRecordsPrinter) YAML() []byte { 23 | return printer.MarshalObject(d, "yaml") 24 | } 25 | 26 | // Columns ... 27 | func (d *DNSRecordsPrinter) Columns() [][]string { 28 | return [][]string{0: { 29 | "ID", 30 | "TYPE", 31 | "NAME", 32 | "DATA", 33 | "PRIORITY", 34 | "TTL", 35 | }} 36 | } 37 | 38 | // Data ... 39 | func (d *DNSRecordsPrinter) Data() [][]string { 40 | if len(d.Records) == 0 { 41 | return [][]string{0: {"---", "---", "---", "---", "---", "---"}} 42 | } 43 | 44 | var data [][]string 45 | for i := range d.Records { 46 | data = append(data, []string{ 47 | d.Records[i].ID, 48 | d.Records[i].Type, 49 | d.Records[i].Name, 50 | d.Records[i].Data, 51 | strconv.Itoa(d.Records[i].Priority), 52 | strconv.Itoa(d.Records[i].TTL), 53 | }) 54 | } 55 | 56 | return data 57 | } 58 | 59 | // Paging ... 60 | func (d *DNSRecordsPrinter) Paging() [][]string { 61 | return printer.NewPagingFromMeta(d.Meta).Compose() 62 | } 63 | 64 | // ====================================== 65 | 66 | // DNSRecordPrinter ... 67 | type DNSRecordPrinter struct { 68 | Record govultr.DomainRecord `json:"records"` 69 | } 70 | 71 | // JSON ... 72 | func (d *DNSRecordPrinter) JSON() []byte { 73 | return printer.MarshalObject(d, "json") 74 | } 75 | 76 | // YAML ... 77 | func (d *DNSRecordPrinter) YAML() []byte { 78 | return printer.MarshalObject(d, "yaml") 79 | } 80 | 81 | // Columns ... 82 | func (d *DNSRecordPrinter) Columns() [][]string { 83 | return [][]string{0: { 84 | "ID", 85 | "TYPE", 86 | "NAME", 87 | "DATA", 88 | "PRIORITY", 89 | "TTL", 90 | }} 91 | } 92 | 93 | // Data ... 94 | func (d *DNSRecordPrinter) Data() [][]string { 95 | return [][]string{0: { 96 | d.Record.ID, 97 | d.Record.Type, 98 | d.Record.Name, 99 | d.Record.Data, 100 | strconv.Itoa(d.Record.Priority), 101 | strconv.Itoa(d.Record.TTL), 102 | }} 103 | } 104 | 105 | // Paging ... 106 | func (d *DNSRecordPrinter) Paging() [][]string { 107 | return nil 108 | } 109 | 110 | // ====================================== 111 | 112 | // DNSDomainsPrinter ... 113 | type DNSDomainsPrinter struct { 114 | Domains []govultr.Domain `json:"domains"` 115 | Meta *govultr.Meta `json:"meta"` 116 | } 117 | 118 | // JSON ... 119 | func (d *DNSDomainsPrinter) JSON() []byte { 120 | return printer.MarshalObject(d, "json") 121 | } 122 | 123 | // YAML ... 124 | func (d *DNSDomainsPrinter) YAML() []byte { 125 | return printer.MarshalObject(d, "yaml") 126 | } 127 | 128 | // Columns ... 129 | func (d *DNSDomainsPrinter) Columns() [][]string { 130 | return [][]string{0: { 131 | "DOMAIN", 132 | "DATE CREATED", 133 | "DNSSEC", 134 | }} 135 | } 136 | 137 | // Data ... 138 | func (d *DNSDomainsPrinter) Data() [][]string { 139 | if len(d.Domains) == 0 { 140 | return [][]string{0: {"---", "---", "---"}} 141 | } 142 | 143 | var data [][]string 144 | for i := range d.Domains { 145 | data = append(data, []string{ 146 | d.Domains[i].Domain, 147 | d.Domains[i].DateCreated, 148 | d.Domains[i].DNSSec, 149 | }) 150 | } 151 | 152 | return data 153 | } 154 | 155 | // Paging ... 156 | func (d *DNSDomainsPrinter) Paging() [][]string { 157 | return printer.NewPagingFromMeta(d.Meta).Compose() 158 | } 159 | 160 | // ====================================== 161 | 162 | // DNSDomainPrinter ... 163 | type DNSDomainPrinter struct { 164 | Domain govultr.Domain `json:"domain"` 165 | } 166 | 167 | // JSON ... 168 | func (d *DNSDomainPrinter) JSON() []byte { 169 | return printer.MarshalObject(d, "json") 170 | } 171 | 172 | // YAML ... 173 | func (d *DNSDomainPrinter) YAML() []byte { 174 | return printer.MarshalObject(d, "yaml") 175 | } 176 | 177 | // Columns ... 178 | func (d *DNSDomainPrinter) Columns() [][]string { 179 | return [][]string{0: { 180 | "DOMAIN", 181 | "DATE CREATED", 182 | "DNS SEC", 183 | }} 184 | } 185 | 186 | // Data ... 187 | func (d *DNSDomainPrinter) Data() [][]string { 188 | return [][]string{0: { 189 | d.Domain.Domain, 190 | d.Domain.DateCreated, 191 | d.Domain.DNSSec, 192 | }} 193 | } 194 | 195 | // Paging ... 196 | func (d *DNSDomainPrinter) Paging() [][]string { 197 | return nil 198 | } 199 | 200 | // ====================================== 201 | 202 | // DNSSOAPrinter ... 203 | type DNSSOAPrinter struct { 204 | SOA govultr.Soa `json:"dns_soa"` 205 | } 206 | 207 | // JSON ... 208 | func (d *DNSSOAPrinter) JSON() []byte { 209 | return printer.MarshalObject(d, "json") 210 | } 211 | 212 | // YAML ... 213 | func (d *DNSSOAPrinter) YAML() []byte { 214 | return printer.MarshalObject(d, "yaml") 215 | } 216 | 217 | // Columns ... 218 | func (d *DNSSOAPrinter) Columns() [][]string { 219 | return [][]string{0: { 220 | "NS PRIMARY", 221 | "EMAIL", 222 | }} 223 | } 224 | 225 | // Data ... 226 | func (d *DNSSOAPrinter) Data() [][]string { 227 | return [][]string{0: { 228 | d.SOA.NSPrimary, 229 | d.SOA.Email, 230 | }} 231 | } 232 | 233 | // Paging ... 234 | func (d *DNSSOAPrinter) Paging() [][]string { 235 | return nil 236 | } 237 | 238 | // ====================================== 239 | 240 | // DNSSECPrinter ... 241 | type DNSSECPrinter struct { 242 | SEC []string `json:"dns_sec"` 243 | } 244 | 245 | // JSON ... 246 | func (d *DNSSECPrinter) JSON() []byte { 247 | return printer.MarshalObject(d, "json") 248 | } 249 | 250 | // YAML ... 251 | func (d *DNSSECPrinter) YAML() []byte { 252 | return printer.MarshalObject(d, "yaml") 253 | } 254 | 255 | // Columns ... 256 | func (d *DNSSECPrinter) Columns() [][]string { 257 | return [][]string{0: { 258 | "DNSSEC INFO", 259 | }} 260 | } 261 | 262 | // Data ... 263 | func (d *DNSSECPrinter) Data() [][]string { 264 | if len(d.SEC) == 0 { 265 | return [][]string{0: {"---"}} 266 | } 267 | 268 | var data [][]string 269 | for i := range d.SEC { 270 | data = append(data, []string{d.SEC[i]}) 271 | } 272 | 273 | return data 274 | } 275 | 276 | // Paging ... 277 | func (d *DNSSECPrinter) Paging() [][]string { 278 | return nil 279 | } 280 | -------------------------------------------------------------------------------- /cmd/baremetal/printer.go: -------------------------------------------------------------------------------- 1 | package baremetal 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/vultr/govultr/v3" 7 | 8 | "github.com/vultr/vultr-cli/v3/cmd/printer" 9 | ) 10 | 11 | // BareMetalsPrinter ... 12 | type BareMetalsPrinter struct { 13 | BareMetals []govultr.BareMetalServer `json:"bare_metals"` 14 | Meta *govultr.Meta `json:"meta"` 15 | } 16 | 17 | // JSON ... 18 | func (b *BareMetalsPrinter) JSON() []byte { 19 | return printer.MarshalObject(b, "json") 20 | } 21 | 22 | // YAML ... 23 | func (b *BareMetalsPrinter) YAML() []byte { 24 | return printer.MarshalObject(b, "yaml") 25 | } 26 | 27 | // Columns ... 28 | func (b *BareMetalsPrinter) Columns() [][]string { 29 | return [][]string{0: { 30 | "ID", 31 | "IP", 32 | "MAC ADDRESS", 33 | "LABEL", 34 | "OS", 35 | "STATUS", 36 | "REGION", 37 | "CPU", 38 | "RAM", 39 | "DISK", 40 | "FEATURES", 41 | "TAGS", 42 | }} 43 | } 44 | 45 | // Data ... 46 | func (b *BareMetalsPrinter) Data() [][]string { 47 | var data [][]string 48 | for i := range b.BareMetals { 49 | data = append(data, []string{ 50 | b.BareMetals[i].ID, 51 | b.BareMetals[i].MainIP, 52 | strconv.Itoa(b.BareMetals[i].MacAddress), 53 | b.BareMetals[i].Label, 54 | b.BareMetals[i].Os, 55 | b.BareMetals[i].Status, 56 | b.BareMetals[i].Region, 57 | strconv.Itoa(b.BareMetals[i].CPUCount), 58 | b.BareMetals[i].RAM, 59 | b.BareMetals[i].Disk, 60 | printer.ArrayOfStringsToString(b.BareMetals[i].Features), 61 | printer.ArrayOfStringsToString(b.BareMetals[i].Tags), 62 | }) 63 | } 64 | return data 65 | } 66 | 67 | // Paging ... 68 | func (b *BareMetalsPrinter) Paging() [][]string { 69 | return printer.NewPagingFromMeta(b.Meta).Compose() 70 | } 71 | 72 | // ====================================== 73 | 74 | // BareMetalPrinter ... 75 | type BareMetalPrinter struct { 76 | BareMetal govultr.BareMetalServer `json:"bare_metal"` 77 | } 78 | 79 | // JSON ... 80 | func (b *BareMetalPrinter) JSON() []byte { 81 | return printer.MarshalObject(b, "json") 82 | } 83 | 84 | // YAML ... 85 | func (b *BareMetalPrinter) YAML() []byte { 86 | return printer.MarshalObject(b, "yaml") 87 | } 88 | 89 | // Columns ... 90 | func (b *BareMetalPrinter) Columns() [][]string { 91 | return [][]string{0: {"BARE METAL INFO"}} 92 | } 93 | 94 | // Data ... 95 | func (b *BareMetalPrinter) Data() [][]string { 96 | var data [][]string 97 | data = append(data, 98 | []string{"ID", b.BareMetal.ID}, 99 | []string{"IP", b.BareMetal.MainIP}, 100 | []string{"USER SCHEME", b.BareMetal.UserScheme}, 101 | ) 102 | 103 | if b.BareMetal.DefaultPassword != "" { 104 | data = append(data, []string{"PASSWORD", b.BareMetal.DefaultPassword}) 105 | } else { 106 | data = append(data, []string{"PASSWORD", "UNAVAILABLE"}) 107 | } 108 | 109 | data = append(data, 110 | []string{"MAC ADDRESS", strconv.Itoa(b.BareMetal.MacAddress)}, 111 | []string{"LABEL", b.BareMetal.Label}, 112 | []string{"OS", b.BareMetal.Os}, 113 | []string{"SNAPSHOT ID", b.BareMetal.SnapshotID}, 114 | []string{"STATUS", b.BareMetal.Status}, 115 | []string{"REGION", b.BareMetal.Region}, 116 | []string{"CPU", strconv.Itoa(b.BareMetal.CPUCount)}, 117 | []string{"RAM", b.BareMetal.RAM}, 118 | []string{"DISK", b.BareMetal.Disk}, 119 | []string{"FEATURES", printer.ArrayOfStringsToString(b.BareMetal.Features)}, 120 | []string{"TAGS", printer.ArrayOfStringsToString(b.BareMetal.Tags)}, 121 | ) 122 | 123 | return data 124 | } 125 | 126 | // Paging ... 127 | func (b *BareMetalPrinter) Paging() [][]string { 128 | return nil 129 | } 130 | 131 | // ====================================== 132 | 133 | // BareMetalVNCPrinter ... 134 | type BareMetalVNCPrinter struct { 135 | VNC govultr.VNCUrl `json:"vnc"` 136 | } 137 | 138 | // JSON ... 139 | func (b *BareMetalVNCPrinter) JSON() []byte { 140 | return printer.MarshalObject(b, "json") 141 | } 142 | 143 | // YAML ... 144 | func (b *BareMetalVNCPrinter) YAML() []byte { 145 | return printer.MarshalObject(b, "yaml") 146 | } 147 | 148 | // Columns ... 149 | func (b *BareMetalVNCPrinter) Columns() [][]string { 150 | return [][]string{0: { 151 | "URL", 152 | }} 153 | } 154 | 155 | // Data ... 156 | func (b *BareMetalVNCPrinter) Data() [][]string { 157 | return [][]string{0: { 158 | b.VNC.URL, 159 | }} 160 | } 161 | 162 | // Paging ... 163 | func (b *BareMetalVNCPrinter) Paging() [][]string { 164 | return nil 165 | } 166 | 167 | // ====================================== 168 | 169 | // BareMetalBandwidthPrinter ... 170 | type BareMetalBandwidthPrinter struct { 171 | Bandwidth govultr.Bandwidth `json:"all_bandwidth"` 172 | } 173 | 174 | // JSON ... 175 | func (b *BareMetalBandwidthPrinter) JSON() []byte { 176 | return printer.MarshalObject(b, "json") 177 | } 178 | 179 | // YAML ... 180 | func (b *BareMetalBandwidthPrinter) YAML() []byte { 181 | return printer.MarshalObject(b, "yaml") 182 | } 183 | 184 | // Columns ... 185 | func (b *BareMetalBandwidthPrinter) Columns() [][]string { 186 | return [][]string{0: { 187 | "DATE", 188 | "INCOMING BYTES", 189 | "OUTGOING BYTES", 190 | }} 191 | } 192 | 193 | // Data ... 194 | func (b *BareMetalBandwidthPrinter) Data() [][]string { 195 | var data [][]string 196 | for k := range b.Bandwidth.Bandwidth { 197 | data = append(data, []string{ 198 | k, 199 | strconv.Itoa(b.Bandwidth.Bandwidth[k].IncomingBytes), 200 | strconv.Itoa(b.Bandwidth.Bandwidth[k].OutgoingBytes), 201 | }) 202 | } 203 | 204 | return data 205 | } 206 | 207 | // Paging ... 208 | func (b *BareMetalBandwidthPrinter) Paging() [][]string { 209 | return nil 210 | } 211 | 212 | // ====================================== 213 | 214 | // BareMetalVPC2sPrinter ... 215 | type BareMetalVPC2sPrinter struct { 216 | VPC2s []govultr.VPC2Info `json:"vpcs"` //nolint:staticcheck 217 | } 218 | 219 | // JSON ... 220 | func (b *BareMetalVPC2sPrinter) JSON() []byte { 221 | return printer.MarshalObject(b, "json") 222 | } 223 | 224 | // YAML ... 225 | func (b *BareMetalVPC2sPrinter) YAML() []byte { 226 | return printer.MarshalObject(b, "yaml") 227 | } 228 | 229 | // Columns ... 230 | func (b *BareMetalVPC2sPrinter) Columns() [][]string { 231 | return [][]string{0: { 232 | "ID", 233 | "MAC ADDRESS", 234 | "IP ADDRESS", 235 | }} 236 | } 237 | 238 | // Data ... 239 | func (b *BareMetalVPC2sPrinter) Data() [][]string { 240 | var data [][]string 241 | 242 | if len(b.VPC2s) == 0 { 243 | return [][]string{0: {"---", "---", "---"}} 244 | } 245 | 246 | for i := range b.VPC2s { 247 | data = append(data, []string{ 248 | b.VPC2s[i].ID, 249 | b.VPC2s[i].MacAddress, 250 | b.VPC2s[i].IPAddress, 251 | }) 252 | } 253 | 254 | return data 255 | } 256 | 257 | // Paging ... 258 | func (b *BareMetalVPC2sPrinter) Paging() [][]string { 259 | return nil 260 | } 261 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= 5 | github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= 6 | github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= 7 | github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 8 | github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= 9 | github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= 10 | github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= 11 | github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 12 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 13 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 14 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 15 | github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= 16 | github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 17 | github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= 18 | github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= 19 | github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= 20 | github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= 21 | github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= 22 | github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= 23 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 24 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 25 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 26 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 27 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 28 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 29 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 30 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 31 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 32 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 33 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 34 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 35 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 36 | github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= 37 | github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= 38 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 39 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 40 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= 41 | github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 42 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 43 | github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= 44 | github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= 45 | github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= 46 | github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= 47 | github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= 48 | github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= 49 | github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= 50 | github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= 51 | github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= 52 | github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= 53 | github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 54 | github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= 55 | github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 56 | github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= 57 | github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= 58 | github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= 59 | github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 60 | github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= 61 | github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= 62 | github.com/vultr/govultr/v3 v3.25.0 h1:rS8/Vdy8HlHArwmD4MtLY+hbbpYAbcnZueZrE6b0oUg= 63 | github.com/vultr/govultr/v3 v3.25.0/go.mod h1:9WwnWGCKnwDlNjHjtt+j+nP+0QWq6hQXzaHgddqrLWY= 64 | go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= 65 | go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= 66 | golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= 67 | golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= 68 | golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= 69 | golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 70 | golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= 71 | golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= 72 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 73 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 74 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 75 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 76 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 77 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 78 | -------------------------------------------------------------------------------- /cmd/snapshot/snapshot.go: -------------------------------------------------------------------------------- 1 | // Package snapshot provides functionality for the CLI to control snapshots 2 | package snapshot 3 | 4 | import ( 5 | "errors" 6 | "fmt" 7 | "os" 8 | 9 | "github.com/spf13/cobra" 10 | "github.com/vultr/govultr/v3" 11 | "github.com/vultr/vultr-cli/v3/cmd/printer" 12 | "github.com/vultr/vultr-cli/v3/cmd/utils" 13 | "github.com/vultr/vultr-cli/v3/pkg/cli" 14 | ) 15 | 16 | // NewCmdSnapshot provides the CLI command for snapshot functions 17 | func NewCmdSnapshot(base *cli.Base) *cobra.Command { //nolint:gocyclo 18 | o := &options{Base: base} 19 | 20 | cmd := &cobra.Command{ 21 | Use: "snapshot", 22 | Short: "Commands to interact with snapshots", 23 | Aliases: []string{"sn"}, 24 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 25 | utils.SetOptions(o.Base, cmd, args) 26 | if !o.Base.HasAuth { 27 | return errors.New(utils.APIKeyError) 28 | } 29 | return nil 30 | }, 31 | } 32 | 33 | // List 34 | list := &cobra.Command{ 35 | Use: "list", 36 | Short: "List all snapshots", 37 | RunE: func(cmd *cobra.Command, args []string) error { 38 | o.Base.Options = utils.GetPaging(cmd) 39 | 40 | snaps, meta, err := o.list() 41 | if err != nil { 42 | return fmt.Errorf("error retrieving snapshot list : %v", err) 43 | } 44 | 45 | data := &SnapshotsPrinter{Snapshots: snaps, Meta: meta} 46 | o.Base.Printer.Display(data, nil) 47 | 48 | return nil 49 | }, 50 | } 51 | 52 | // Get 53 | get := &cobra.Command{ 54 | Use: "get ", 55 | Short: "Get a snapshot", 56 | Args: func(cmd *cobra.Command, args []string) error { 57 | if len(args) < 1 { 58 | return errors.New("please provide a snapshot ID") 59 | } 60 | return nil 61 | }, 62 | RunE: func(cmd *cobra.Command, args []string) error { 63 | snapshot, err := o.get() 64 | if err != nil { 65 | return fmt.Errorf("error retrieving snapshot : %v", err) 66 | } 67 | 68 | data := &SnapshotPrinter{Snapshot: snapshot} 69 | o.Base.Printer.Display(data, nil) 70 | 71 | return nil 72 | }, 73 | } 74 | 75 | // Create 76 | create := &cobra.Command{ 77 | Use: "create", 78 | Short: "Create a snapshot", 79 | RunE: func(cmd *cobra.Command, args []string) error { 80 | id, errID := cmd.Flags().GetString("id") 81 | if errID != nil { 82 | return fmt.Errorf("error parsing flag 'id' for create : %v", errID) 83 | } 84 | 85 | desc, errDe := cmd.Flags().GetString("description") 86 | if errDe != nil { 87 | return fmt.Errorf("error parsing flag 'description' for create : %v", errDe) 88 | } 89 | 90 | o.Req = &govultr.SnapshotReq{ 91 | InstanceID: id, 92 | Description: desc, 93 | } 94 | 95 | snapshot, err := o.create() 96 | if err != nil { 97 | return fmt.Errorf("error creating snapshot : %v", err) 98 | } 99 | 100 | data := &SnapshotPrinter{Snapshot: snapshot} 101 | o.Base.Printer.Display(data, nil) 102 | 103 | return nil 104 | }, 105 | } 106 | 107 | create.Flags().StringP("id", "i", "", "ID of the virtual machine to create a snapshot from.") 108 | if err := create.MarkFlagRequired("id"); err != nil { 109 | fmt.Printf("error marking snapshot create 'id' flag required: %v", err) 110 | os.Exit(1) 111 | } 112 | 113 | create.Flags().StringP("description", "d", "", "(optional) Description of snapshot contents") 114 | 115 | // Create URL 116 | createURL := &cobra.Command{ 117 | Use: "create-url", 118 | Short: "Create a snapshot from a URL", 119 | RunE: func(cmd *cobra.Command, args []string) error { 120 | url, errUR := cmd.Flags().GetString("url") 121 | if errUR != nil { 122 | return fmt.Errorf("error parsing flag 'url' for createURL : %v", errUR) 123 | } 124 | 125 | o.URLReq = &govultr.SnapshotURLReq{ 126 | URL: url, 127 | } 128 | 129 | if desc, err := cmd.Flags().GetString("description"); err != nil { 130 | return fmt.Errorf("error parsing flag 'description' for createURL : %v", err) 131 | } else { 132 | o.URLReq.Description = desc 133 | } 134 | 135 | if cmd.Flags().Changed("uefi") { 136 | if b, err := cmd.Flags().GetBool("uefi"); err != nil { 137 | return fmt.Errorf("error parsing flag 'uefi' for createURL : %v", err) 138 | } else { 139 | o.URLReq.UEFI = &b 140 | } 141 | } 142 | 143 | snapshot, err := o.createURL() 144 | if err != nil { 145 | return fmt.Errorf("error creating snapshot from URL : %v", err) 146 | } 147 | 148 | data := &SnapshotPrinter{Snapshot: snapshot} 149 | o.Base.Printer.Display(data, nil) 150 | 151 | return nil 152 | }, 153 | } 154 | 155 | createURL.Flags().StringP("url", "u", "", "Remote URL from where the snapshot will be downloaded.") 156 | createURL.Flags().StringP("description", "d", "", "Set snapshot description (defaults to filename from request URL).") 157 | createURL.Flags().Bool("uefi", false, "Mark snapshot as UEFI.") 158 | if err := createURL.MarkFlagRequired("url"); err != nil { 159 | fmt.Printf("error marking snapshot create 'url' flag required: %v", err) 160 | os.Exit(1) 161 | } 162 | 163 | // Delete 164 | del := &cobra.Command{ 165 | Use: "delete ", 166 | Short: "Delete a snapshot", 167 | Aliases: []string{"destroy"}, 168 | Args: func(cmd *cobra.Command, args []string) error { 169 | if len(args) < 1 { 170 | return errors.New("please provide a snapshot ID") 171 | } 172 | return nil 173 | }, 174 | RunE: func(cmd *cobra.Command, args []string) error { 175 | if err := o.del(); err != nil { 176 | return fmt.Errorf("error deleting snapshot : %v", err) 177 | } 178 | 179 | o.Base.Printer.Display(printer.Info("snapshot has been deleted"), nil) 180 | 181 | return nil 182 | }, 183 | } 184 | 185 | cmd.AddCommand( 186 | list, 187 | get, 188 | create, 189 | createURL, 190 | del, 191 | ) 192 | 193 | return cmd 194 | } 195 | 196 | type options struct { 197 | Base *cli.Base 198 | Req *govultr.SnapshotReq 199 | URLReq *govultr.SnapshotURLReq 200 | } 201 | 202 | func (o *options) list() ([]govultr.Snapshot, *govultr.Meta, error) { 203 | snapshots, meta, _, err := o.Base.Client.Snapshot.List(o.Base.Context, o.Base.Options) 204 | return snapshots, meta, err 205 | } 206 | 207 | func (o *options) get() (*govultr.Snapshot, error) { 208 | snapshot, _, err := o.Base.Client.Snapshot.Get(o.Base.Context, o.Base.Args[0]) 209 | return snapshot, err 210 | } 211 | 212 | func (o *options) create() (*govultr.Snapshot, error) { 213 | snapshot, _, err := o.Base.Client.Snapshot.Create(o.Base.Context, o.Req) 214 | return snapshot, err 215 | } 216 | 217 | func (o *options) createURL() (*govultr.Snapshot, error) { 218 | snapshot, _, err := o.Base.Client.Snapshot.CreateFromURL(o.Base.Context, o.URLReq) 219 | return snapshot, err 220 | } 221 | 222 | func (o *options) del() error { 223 | return o.Base.Client.Snapshot.Delete(o.Base.Context, o.Base.Args[0]) 224 | } 225 | -------------------------------------------------------------------------------- /cmd/printer/printer.go: -------------------------------------------------------------------------------- 1 | // Package printer provides the console printing functionality for the CLI 2 | package printer 3 | 4 | import ( 5 | "encoding/json" 6 | "fmt" 7 | "os" 8 | "strconv" 9 | "strings" 10 | "text/tabwriter" 11 | 12 | "github.com/vultr/govultr/v3" 13 | "gopkg.in/yaml.v3" 14 | ) 15 | 16 | const ( 17 | twMinWidth int = 0 18 | twTabWidth int = 8 19 | twPadding int = 2 20 | twPadChar byte = '\t' 21 | twFlags uint = 0 22 | emptyPlaceholder string = "---" 23 | JSONIndent string = " " 24 | ) 25 | 26 | type ResourceOutput interface { 27 | JSON() []byte 28 | YAML() []byte 29 | Columns() [][]string 30 | Data() [][]string 31 | Paging() [][]string 32 | } 33 | 34 | type Printer interface { 35 | display(values columns, lengths []int) 36 | flush() 37 | } 38 | 39 | type Output struct { 40 | Type string 41 | Resource ResourceOutput 42 | Output string 43 | } 44 | 45 | type columns []interface{} 46 | 47 | var tw = new(tabwriter.Writer) 48 | 49 | func init() { 50 | tw.Init( 51 | os.Stdout, 52 | twMinWidth, 53 | twTabWidth, 54 | twPadding, 55 | twPadChar, 56 | twFlags, 57 | ) 58 | } 59 | 60 | // Display confirms the output format then displays the ResourceOutput data to 61 | // the CLI. If there is an error, that is displayed instead via Error 62 | func (o *Output) Display(r ResourceOutput, err error) { 63 | defer o.flush() 64 | 65 | if err != nil { 66 | // todo move this so it can follow the flow of the other printers and support json/yaml 67 | Error(err) 68 | } 69 | 70 | if strings.ToLower(o.Output) == "json" { 71 | o.displayNonText(r.JSON()) 72 | os.Exit(0) 73 | } else if strings.ToLower(o.Output) == "yaml" { 74 | o.displayNonText(r.YAML()) 75 | os.Exit(0) 76 | } 77 | 78 | o.display(r.Columns()) 79 | o.display(r.Data()) 80 | if r.Paging() != nil { 81 | o.display(r.Paging()) 82 | } 83 | } 84 | 85 | func (o *Output) display(d [][]string) { 86 | for n := range d { 87 | for i := range d[n] { 88 | format := "\t%s" 89 | if i == 0 { 90 | format = "%s" 91 | } 92 | fmt.Fprintf(tw, format, fmt.Sprintf("%v", d[n][i])) 93 | } 94 | fmt.Fprintf(tw, "\n") 95 | } 96 | } 97 | 98 | func (o *Output) flush() { 99 | if err := tw.Flush(); err != nil { 100 | panic(fmt.Errorf("unable to flush display : %v", err)) 101 | } 102 | } 103 | 104 | func (o *Output) displayNonText(data []byte) { 105 | fmt.Printf("%s\n", string(data)) 106 | } 107 | 108 | // Paging struct holds the values used by the Meta section in the printer 109 | // output 110 | type Paging struct { 111 | Total int 112 | CursorNext string 113 | CursorPrev string 114 | } 115 | 116 | // NewPagingFromMeta validates and initializes the paging data, from a govultr.Meta struct. 117 | func NewPagingFromMeta(m *govultr.Meta) *Paging { 118 | if m == nil { 119 | // If no metadata, then no paging to show. 120 | return nil 121 | } 122 | if m.Links == nil { 123 | return NewPaging(m.Total, "", "") 124 | } 125 | return NewPaging(m.Total, m.Links.Next, m.Links.Prev) 126 | } 127 | 128 | // NewPaging validates and initializes the paging data. 129 | func NewPaging(total int, next, prev string) *Paging { 130 | p := &Paging{ 131 | Total: total, 132 | CursorNext: emptyPlaceholder, 133 | CursorPrev: emptyPlaceholder, 134 | } 135 | 136 | if next != "" { 137 | p.CursorNext = next 138 | } 139 | 140 | if prev != "" { 141 | p.CursorPrev = prev 142 | } 143 | 144 | return p 145 | } 146 | 147 | // Compose returns the paging data for output 148 | func (p *Paging) Compose() [][]string { 149 | if p == nil { 150 | // If no paging information, don't show anything. 151 | return nil 152 | } 153 | 154 | var display [][]string 155 | display = append(display, 156 | []string{"======================================"}, 157 | []string{"TOTAL", "NEXT PAGE", "PREV PAGE"}, 158 | []string{strconv.Itoa(p.Total), p.CursorNext, p.CursorPrev}, 159 | ) 160 | 161 | return display 162 | } 163 | 164 | // Total holds the values used by the Meta section in the printer 165 | // output for outputs that don't include paging cursors 166 | type Total struct { 167 | Total int 168 | } 169 | 170 | // Compose returns the total data for output 171 | func (t *Total) Compose() [][]string { 172 | var display [][]string 173 | display = append(display, 174 | []string{"======================================"}, 175 | []string{"TOTAL"}, 176 | []string{strconv.Itoa(t.Total)}, 177 | ) 178 | 179 | return display 180 | } 181 | 182 | // MarshalObject ... 183 | func MarshalObject(input interface{}, format string) []byte { 184 | var output []byte 185 | switch format { 186 | case "json": 187 | j, errJ := json.MarshalIndent(input, "", JSONIndent) 188 | if errJ != nil { 189 | panic(fmt.Errorf("error marshaling JSON : %v", errJ)) 190 | } 191 | output = j 192 | case "yaml": 193 | y, errY := yaml.Marshal(input) 194 | if errY != nil { 195 | panic(fmt.Errorf("error marshaling YAML : %v", errY)) 196 | } 197 | output = y 198 | } 199 | 200 | return output 201 | } 202 | 203 | // ArrayOfStringsToString will build a delimited string from an array for 204 | // display in the printer functions. It defaults to comma-delimited and 205 | // enclosed in square brackets to maintain consistency with array Fprintf 206 | func ArrayOfStringsToString(a []string) string { 207 | delimiter := ", " 208 | var sb strings.Builder 209 | sb.WriteString("[") 210 | sb.WriteString(strings.Join(a, delimiter)) 211 | sb.WriteString("]") 212 | 213 | return sb.String() 214 | } 215 | 216 | // ArrayOfIntsToString will build a delimited string from an array for 217 | // display in the printer functions. It defaults to comma-delimited and 218 | // enclosed in square brackets to maintain consistency with array Fprintf 219 | func ArrayOfIntsToString(a []int) string { 220 | delimiter := ", " 221 | var sb strings.Builder 222 | sb.WriteString("[") 223 | for i := range a { 224 | sb.WriteString(strconv.Itoa(a[i])) 225 | sb.WriteString(delimiter) 226 | } 227 | sb.WriteString("]") 228 | 229 | return sb.String() 230 | } 231 | 232 | // OLD funcs to be re-written ////////////////////////////////////////////////////////////// 233 | func display(values columns) { 234 | for i, value := range values { 235 | format := "\t%s" 236 | if i == 0 { 237 | format = "%s" 238 | } 239 | fmt.Fprintf(tw, format, fmt.Sprintf("%v", value)) 240 | } 241 | fmt.Fprintf(tw, "\n") 242 | } 243 | 244 | // displayString will `Fprintln` a string to the tabwriter 245 | func displayString(message string) { 246 | fmt.Fprintln(tw, message) 247 | } 248 | 249 | func flush() { 250 | if err := tw.Flush(); err != nil { 251 | panic("could not flush buffer") 252 | } 253 | } 254 | 255 | // Meta prints out the pagination details TODO: old 256 | func Meta(meta *govultr.Meta) { 257 | var pageNext string 258 | var pagePrev string 259 | 260 | if meta.Links.Next == "" { 261 | pageNext = "---" 262 | } else { 263 | pageNext = meta.Links.Next 264 | } 265 | 266 | if meta.Links.Prev == "" { 267 | pagePrev = "---" 268 | } else { 269 | pagePrev = meta.Links.Prev 270 | } 271 | 272 | displayString("======================================") 273 | display(columns{"TOTAL", "NEXT PAGE", "PREV PAGE"}) 274 | display(columns{meta.Total, pageNext, pagePrev}) 275 | } 276 | 277 | // MetaDBaaS prints out the pagination details used by database commands 278 | func MetaDBaaS(meta *govultr.Meta) { 279 | displayString("======================================") 280 | display(columns{"TOTAL"}) 281 | 282 | display(columns{meta.Total}) 283 | } 284 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vultr-cli 2 | 3 | The Vultr Command Line Interface 4 | 5 | ``` 6 | vultr-cli is a command line interface for the Vultr API 7 | 8 | Usage: 9 | vultr-cli [command] 10 | 11 | Available Commands: 12 | account Commands related to account information 13 | apps Display applications 14 | backups Display backups 15 | bare-metal Commands to manage bare metal servers 16 | billing Display billing information 17 | block-storage Commands to manage block storage 18 | cdn Commands to manage your CDN zones 19 | completion Generate the autocompletion script for the specified shell 20 | container-registry Commands to interact with container registries 21 | database Commands to manage databases 22 | dns Commands to control DNS records 23 | firewall Commands to manage firewalls 24 | help Help about any command 25 | inference Commands to manage serverless inference 26 | instance Commands to interact with instances 27 | iso Commands to manage ISOs 28 | kubernetes Commands to manage kubernetes clusters 29 | load-balancer Commands to managed load balancers 30 | marketplace Display marketplace information 31 | object-storage Commands to manage object storage 32 | os Display available operating systems 33 | plans Display available plan information 34 | regions Display regions information 35 | reserved-ip Commands to interact with reserved IPs 36 | script Commands to interact with startup scripts 37 | snapshot Commands to interact with snapshots 38 | ssh-key Commands to manage SSH keys 39 | user Commands to manage users 40 | version Display the vultr-cli version 41 | vpc Commands to manage VPCs 42 | 43 | Flags: 44 | --config string config file (default is $HOME/.vultr-cli.yaml) 45 | -h, --help help for vultr-cli 46 | -o, --output string output format [ text | json | yaml ] (default "text") 47 | 48 | Use "vultr-cli [command] --help" for more information about a command. 49 | ``` 50 | 51 | ## Installation 52 | 53 | These are the options available to install `vultr-cli`: 54 | 1. Download a release from GitHub 55 | 2. From source 56 | 3. Package Manager 57 | - Arch Linux 58 | - Brew 59 | - OpenBSD (-current) 60 | - Snap (Coming soon) 61 | - Chocolatey 62 | 4. Docker 63 | 64 | ### GitHub Release 65 | If you are to visit the `vultr-cli` [releases](https://github.com/vultr/vultr-cli/releases) page. You can download a compiled version of `vultr-cli` for you Linux/MacOS/Windows in 64bit. 66 | 67 | ### Building from source 68 | 69 | You will need Go installed on your machine in order to work with the source (and make if you decide to pull the repo down). 70 | 71 | `go install github.com/vultr/vultr-cli/v3@latest` 72 | 73 | Another way to build from source is to 74 | 75 | ```sh 76 | git clone git@github.com:vultr/vultr-cli.git or git clone https://github.com/vultr/vultr-cli.git 77 | cd vultr-cli 78 | make builds/vultr-cli_(pass name of os + arch, as shown below) 79 | ``` 80 | 81 | The available make build options are 82 | - make builds/vultr-cli_darwin_amd64 83 | - make builds/vultr-cli_darwin_arm64 84 | - make builds/vultr-cli_linux_386 85 | - make builds/vultr-cli_linux_amd64 86 | - make builds/vultr-cli_linux_arm64 87 | - make builds/vultr-cli_windows_386.exe 88 | - make builds/vultr-cli_windows_amd64.exe 89 | - make builds/vultr-cli_linux_arm 90 | 91 | Note that the latter method will install the `vultr-cli` executable in `builds/vultr-cli_(name of os + arch)`. 92 | 93 | ### Installing on Arch Linux 94 | 95 | ```sh 96 | pacman -S vultr-cli 97 | ``` 98 | 99 | ### Installing via Brew 100 | 101 | ```sh 102 | brew install vultr/vultr-cli/vultr-cli 103 | ``` 104 | 105 | ### Installing on Fedora 106 | 107 | ```sh 108 | dnf install vultr-cli 109 | ``` 110 | 111 | ### Installing on OpenBSD 112 | 113 | ```sh 114 | pkg_add vultr-cli 115 | ``` 116 | 117 | ### Docker 118 | You can find the image on [Docker Hub](https://hub.docker.com/repository/docker/vultr/vultr-cli). To install the latest version via `docker`: 119 | 120 | ```sh 121 | docker pull vultr/vultr-cli:latest 122 | ``` 123 | 124 | To pull an older image, you can pass the version string in the tag. For example: 125 | ```sh 126 | docker pull vultr/vultr-cli:v2.15.1 127 | ``` 128 | 129 | The available versions are listed [here](https://github.com/vultr/vultr-cli/releases). 130 | 131 | As described in the next section, you must authenticate in order to use the CLI. To pass the environment variable into docker, you can do so via: 132 | 133 | ```sh 134 | docker run -e VULTR_API_KEY vultr/vultr-cli:latest instance list 135 | ``` 136 | 137 | This assumes you've already set the environment variable in your shell environment, otherwise, you can pass it in via `-e VULTR_API_KEY=` 138 | 139 | ## Using Vultr-cli 140 | 141 | ### Authentication 142 | 143 | In order to use `vultr-cli` you will need to export your [Vultr API KEY](https://my.vultr.com/settings/#settingsapi) 144 | 145 | `export VULTR_API_KEY=` 146 | 147 | ### Examples 148 | 149 | `vultr-cli` can interact with all of your Vultr resources. Here are some basic examples to get you started: 150 | 151 | ##### List all available instances 152 | `vultr-cli instance list` 153 | 154 | ##### Create an instance 155 | `vultr-cli instance create --region --plan --os --host ` 156 | 157 | ##### Create a DNS Domain 158 | `vultr-cli dns domain create --domain --ip ` 159 | 160 | ##### Utilizing a boolean flag 161 | You should use = when using a boolean flag. 162 | 163 | `vultr-cli instance create --region --plan --os --host --notify=true` 164 | 165 | ##### Utilizing the config flag 166 | 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. 167 | 168 | `vultr-cli instance list --config /Users/myuser/vultr-cli.yaml` 169 | 170 | ### Example vultr-cli.yaml config file 171 | 172 | 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: 173 | 174 | `api-key: MYKEY` 175 | 176 | ### CLI Autocompletion 177 | `vultr-cli completion` will return autocompletions, but this feature requires setup. 178 | 179 | Some guides: 180 | 181 |
182 | 

Bash:

183 | $ source <(vultr-cli completion bash) 184 | 185 | To load completions for each session, execute once: 186 | Linux: 187 | $ vultr-cli completion bash > /etc/bash_completion.d/vultr-cli 188 | 189 | macOS: 190 | $ vultr-cli completion bash > /usr/local/etc/bash_completion.d/vultr-cli 191 | 192 |

Zsh:

193 | If shell completion is not already enabled in your environment, 194 | you will need to enable it. You can execute the following once: 195 | 196 | $ echo "autoload -U compinit; compinit" >> ~/.zshrc 197 | 198 | To load completions for each session, execute once: 199 | $ vultr-cli completion zsh > "${fpath[1]}/_vultr-cli" 200 | 201 | You will need to start a new shell for this setup to take effect. 202 | 203 |

fish:

204 | $ vultr-cli completion fish | source 205 | 206 | To load completions for each session, execute once: 207 | $ vultr-cli completion fish > ~/.config/fish/completions/vultr-cli.fish 208 | 209 |

PowerShell:

210 | PS> vultr-cli completion powershell | Out-String | Invoke-Expression 211 | 212 | To load completions for every new session, run: 213 | PS> vultr-cli completion powershell > vultr-cli.ps1 214 | and source this file from your PowerShell profile. 215 |
216 | 217 | ## Contributing 218 | Feel free to send pull requests our way! Please see the [contributing guidelines](CONTRIBUTING.md). 219 | -------------------------------------------------------------------------------- /cmd/script/script.go: -------------------------------------------------------------------------------- 1 | // Package script provides the script commands to the CLI 2 | package script 3 | 4 | import ( 5 | "errors" 6 | "fmt" 7 | "os" 8 | 9 | "github.com/spf13/cobra" 10 | "github.com/vultr/govultr/v3" 11 | "github.com/vultr/vultr-cli/v3/cmd/printer" 12 | "github.com/vultr/vultr-cli/v3/cmd/utils" 13 | "github.com/vultr/vultr-cli/v3/pkg/cli" 14 | ) 15 | 16 | // NewCmdScript provides the CLI command for startup script functions 17 | func NewCmdScript(base *cli.Base) *cobra.Command { //nolint:gocyclo 18 | o := &options{Base: base} 19 | 20 | cmd := &cobra.Command{ 21 | Use: "script", 22 | Short: "Commands to interact with startup scripts", 23 | Aliases: []string{"ss", "startup-script"}, 24 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 25 | utils.SetOptions(o.Base, cmd, args) 26 | if !o.Base.HasAuth { 27 | return errors.New(utils.APIKeyError) 28 | } 29 | return nil 30 | }, 31 | } 32 | 33 | // List 34 | list := &cobra.Command{ 35 | Use: "list", 36 | Short: "List all startup scripts", 37 | RunE: func(cmd *cobra.Command, args []string) error { 38 | o.Base.Options = utils.GetPaging(cmd) 39 | 40 | scripts, meta, err := o.list() 41 | if err != nil { 42 | return fmt.Errorf("error retrieving startup script list : %v", err) 43 | } 44 | 45 | data := &ScriptsPrinter{Scripts: scripts, Meta: meta} 46 | o.Base.Printer.Display(data, nil) 47 | 48 | return nil 49 | }, 50 | } 51 | 52 | list.Flags().StringP("cursor", "c", "", "(optional) Cursor for paging.") 53 | list.Flags().IntP( 54 | "per-page", 55 | "p", 56 | utils.PerPageDefault, 57 | fmt.Sprintf( 58 | "(optional) Number of items requested per page. Default is %d and Max is 500.", 59 | utils.PerPageDefault, 60 | ), 61 | ) 62 | 63 | // Get 64 | get := &cobra.Command{ 65 | Use: "get