├── main.go ├── go.mod ├── .github ├── dependabot.yml └── workflows │ └── release.yml ├── cmd ├── version.go ├── auth.go ├── flags.go ├── utils.go ├── root.go ├── dedicated_server_ip.go └── dedicated_server.go ├── LICENSE ├── .goreleaser.yaml ├── go.sum └── README.md /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/Nmishin/leaseweb-cli/cmd" 5 | ) 6 | 7 | func main() { 8 | cmd.Execute() 9 | } 10 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Nmishin/leaseweb-cli 2 | 3 | go 1.25.1 4 | 5 | require ( 6 | github.com/leaseweb/leaseweb-go-sdk/dedicatedserver/v2 v2.0.7 7 | github.com/spf13/cobra v1.10.1 8 | ) 9 | 10 | require ( 11 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 12 | github.com/spf13/pflag v1.0.9 // indirect 13 | gopkg.in/validator.v2 v2.0.1 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: "github-actions" 5 | directory: / 6 | schedule: 7 | interval: daily 8 | time: "10:00" 9 | commit-message: 10 | prefix: "gh-actions:" 11 | 12 | - package-ecosystem: gomod 13 | directory: / 14 | schedule: 15 | interval: daily 16 | time: "10:00" 17 | commit-message: 18 | prefix: "go:" 19 | -------------------------------------------------------------------------------- /cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | var cliVersion = "dev" 10 | 11 | var versionCmd = &cobra.Command{ 12 | Use: "version", 13 | Short: "Show CLI version information", 14 | Long: "Display the version information for leaseweb-cli", 15 | Run: func(cmd *cobra.Command, args []string) { 16 | fmt.Printf("leaseweb-cli version %s\n", cliVersion) 17 | }, 18 | } 19 | 20 | func init() { 21 | rootCmd.AddCommand(versionCmd) 22 | } 23 | -------------------------------------------------------------------------------- /cmd/auth.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | dedicatedserver "github.com/leaseweb/leaseweb-go-sdk/dedicatedserver/v2" 5 | ) 6 | 7 | var ( 8 | leasewebClient Client 9 | ) 10 | 11 | type Client struct { 12 | DedicatedserverAPI dedicatedserver.DedicatedserverAPI 13 | } 14 | 15 | func InitLeasewebClient(apiKey string) { 16 | cfg := dedicatedserver.NewConfiguration() 17 | 18 | cfg.AddDefaultHeader("X-LSW-Auth", apiKey) 19 | 20 | leasewebClient = Client{ 21 | DedicatedserverAPI: dedicatedserver.NewAPIClient(cfg).DedicatedserverAPI, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cmd/flags.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | var ( 4 | // Filters for dedicated server listing 5 | serverLimit int32 6 | serverOffset int32 7 | reference string 8 | ip string 9 | macAddress string 10 | site string 11 | privateRackId string 12 | privateNetworkCapable string 13 | privateNetworkEnabled string 14 | osOffset int32 15 | osLimit int32 16 | 17 | // Filters for dedicated server IP listing 18 | ipLimit int32 19 | ipOffset int32 20 | networkType string 21 | version string 22 | nullRouted string 23 | ips string 24 | ) 25 | -------------------------------------------------------------------------------- /cmd/utils.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "net/http" 9 | "os" 10 | ) 11 | 12 | func printResponse(resp interface{}) { 13 | jsonData, err := json.MarshalIndent(resp, "", " ") 14 | if err != nil { 15 | fmt.Fprintf(os.Stdout, "Error marshalling response: %v\n", err) 16 | return 17 | } 18 | fmt.Println(string(jsonData)) 19 | } 20 | 21 | func prettyPrintResponse(r *http.Response) { 22 | if r == nil { 23 | fmt.Println("No response received") 24 | return 25 | } 26 | 27 | body, err := io.ReadAll(r.Body) 28 | if err != nil { 29 | fmt.Println("Error reading response body:", err) 30 | return 31 | } 32 | defer r.Body.Close() 33 | 34 | var prettyJSON bytes.Buffer 35 | err = json.Indent(&prettyJSON, body, "", " ") 36 | if err != nil { 37 | fmt.Println("Error formatting JSON:", err) 38 | return 39 | } 40 | 41 | fmt.Println(prettyJSON.String()) 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Nikolai Mishin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | # This GitHub action creates a release when a tag that matches the pattern 4 | # "v*" (e.g. v0.1.0) is created. 5 | on: 6 | push: 7 | tags: 8 | - 'v[0-9]+.[0-9]+.[0-9]+*' 9 | 10 | # Releases need permissions to read and write the repository contents. 11 | # GitHub considers creating releases and uploading assets as writing contents. 12 | permissions: 13 | contents: write 14 | 15 | jobs: 16 | goreleaser: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 20 | with: 21 | # Allow goreleaser to access older tag information. 22 | fetch-depth: 0 23 | - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 24 | with: 25 | go-version-file: 'go.mod' 26 | cache: true 27 | - name: Run GoReleaser 28 | uses: goreleaser/goreleaser-action@v6 29 | with: 30 | distribution: goreleaser 31 | version: "~> v2" 32 | args: release --clean 33 | env: 34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }} 36 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/spf13/cobra" 8 | ) 9 | 10 | var apiKey string 11 | 12 | var rootCmd = &cobra.Command{ 13 | Use: "leaseweb-cli", 14 | SilenceUsage: true, 15 | SilenceErrors: true, 16 | Short: "A CLI tool to interact with Leaseweb API", 17 | Long: "leaseweb-cli allows you to manage Leaseweb servers via the API.", 18 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 19 | skipAPIKeyCommands := []string{"version"} 20 | 21 | for _, skipCmd := range skipAPIKeyCommands { 22 | if cmd.Name() == skipCmd { 23 | return nil 24 | } 25 | } 26 | 27 | if apiKey == "" { 28 | apiKey = os.Getenv("LEASEWEB_API_KEY") 29 | } 30 | 31 | if apiKey == "" { 32 | return fmt.Errorf("API key is required. Set LEASEWEB_API_KEY or use --api-key flag") 33 | } 34 | 35 | InitLeasewebClient(apiKey) 36 | return nil 37 | }, 38 | } 39 | 40 | func Execute() { 41 | rootCmd.CompletionOptions.DisableDefaultCmd = true 42 | rootCmd.SetHelpCommand(&cobra.Command{ 43 | Use: "no-help", 44 | Hidden: true, 45 | }) 46 | if err := rootCmd.Execute(); err != nil { 47 | fmt.Println("Error", err) 48 | os.Exit(1) 49 | } 50 | } 51 | 52 | func init() { 53 | rootCmd.PersistentFlags().StringVar(&apiKey, "api-key", "", "Leaseweb API key (optional, overrides LEASEWEB_API_KEY)") 54 | } 55 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | builds: 4 | - env: 5 | - CGO_ENABLED=0 6 | goos: 7 | - linux 8 | - darwin 9 | ldflags: 10 | - -s -w -X github.com/Nmishin/leaseweb-cli/cmd.cliVersion={{.Tag}} 11 | 12 | archives: 13 | - formats: 14 | - tar.gz 15 | name_template: >- 16 | {{ .ProjectName }}- 17 | {{- .Version }}- 18 | {{- .Os}}- 19 | {{- if eq .Arch "amd64" }}x86_64 20 | {{- else if eq .Arch "386" }}i386 21 | {{- else }}{{ .Arch }}{{ end }} 22 | {{- if .Arm }}v{{ .Arm }}{{ end }} 23 | 24 | changelog: 25 | sort: asc 26 | 27 | brews: 28 | - name: leaseweb-cli 29 | commit_author: 30 | name: goreleaserbot 31 | email: goreleaserbot@nmishin.com 32 | commit_msg_template: "Brew formula update for {{ .ProjectName }} version {{ .Tag }}" 33 | directory: Formula 34 | homepage: "https://github.com/Nmishin/leaseweb-cli" 35 | description: "The command line interface for Leaseweb API" 36 | license: "Apache-2.0" 37 | skip_upload: auto 38 | extra_install: | 39 | chmod 0555, bin/"leaseweb-cli" 40 | repository: 41 | owner: Nmishin 42 | name: homebrew-tap 43 | branch: "{{ .ProjectName }}-{{ .Tag }}" 44 | # see https://goreleaser.com/errors/resource-not-accessible-by-integration 45 | token: "{{ .Env.TAP_GITHUB_TOKEN }}" 46 | pull_request: 47 | enabled: true 48 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 2 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 3 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 4 | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 5 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 6 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 7 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 8 | github.com/leaseweb/leaseweb-go-sdk/dedicatedserver/v2 v2.0.7 h1:Os7QDpEHTI/51RiwRB8jELe4F2AvuEiJQWSJGH1zuNw= 9 | github.com/leaseweb/leaseweb-go-sdk/dedicatedserver/v2 v2.0.7/go.mod h1:D/dX8az1mr8VKxIRL1jrg6wR+vReaF45kp06R2VnvmA= 10 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 11 | github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= 12 | github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= 13 | github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= 14 | github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 15 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 16 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 17 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 18 | gopkg.in/validator.v2 v2.0.1 h1:xF0KWyGWXm/LM2G1TrEjqOu4pa6coO9AlWSf3msVfDY= 19 | gopkg.in/validator.v2 v2.0.1/go.mod h1:lIUZBlB3Im4s/eYp39Ry/wkR02yOPhZ9IwIRBjuPuG8= 20 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Leaseweb CLI 2 | 3 | [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/Nmishin/leaseweb-cli)](https://github.com/Nmishin/leaseweb-cli/releases/latest) 4 | ![GitHub all releases](https://img.shields.io/github/downloads/Nmishin/leaseweb-cli/total?label=GitHub%20Total%20Downloads) 5 | 6 | ## About 7 | 8 | `leaseweb-cli` is unofficial Leaseweb command line tool. 9 | 10 | ## Installation 11 | 12 | ### macOS 13 | 14 | `leaseweb-cli` is available via [Homebrew](https://brew.sh/), and as a downloadable binary from [releases page](https://github.com/Nmishin/leaseweb-cli/releases/latest). 15 | 16 | #### Homebrew 17 | 18 | ```bash 19 | brew tap nmishin/tap 20 | brew install leaseweb-cli 21 | ``` 22 | 23 | ### Linux 24 | 25 | `leaseweb-cli` is available via [Homebrew](https://brew.sh/), and as a downloadable binary from [releases page](https://github.com/Nmishin/leaseweb-cli/releases/latest). 26 | 27 | #### Homebrew 28 | 29 | ```bash 30 | brew tap nmishin/tap 31 | brew install leaseweb-cli 32 | ``` 33 | 34 | ## Usage 35 | 36 | ### Generate your API Key 37 | You can generate your API key at the [Customer Portal](https://secure.leaseweb.com/) 38 | 39 | ### Authentication 40 | For authentication need to export API Key from previous step, or set it as `--api-key` flag. 41 | ```bash 42 | export LEASEWEB_API_KEY=<> 43 | ``` 44 | 45 | ### Supported commands for dedicated-server 46 | ```bash 47 | $ leaseweb-cli dedicated-server -h 48 | 49 | Manage dedicated servers 50 | 51 | Usage: 52 | leaseweb-cli dedicated-server [command] 53 | 54 | Available Commands: 55 | get Retrieve details of the server by ID 56 | get-contract-renewal Retrieve next contract renewal date in milliseconds since epoch by server ID 57 | get-creds Retrieve the server credentials 58 | get-hardware Retrieve hardware details of the server by ID 59 | get-ip Describe the server IP 60 | get-ips List the server IPs 61 | list Retrieve the list of servers 62 | power-off Power off the server 63 | power-on Power on the server 64 | reboot Power cycle the server 65 | 66 | Flags: 67 | -h, --help help for dedicated-server 68 | 69 | Global Flags: 70 | --api-key string Leaseweb API key (optional, overrides LEASEWEB_API_KEY) 71 | 72 | Use "leaseweb-cli dedicated-server [command] --help" for more information about a command. 73 | ``` 74 | -------------------------------------------------------------------------------- /cmd/dedicated_server_ip.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | dedicatedserver "github.com/leaseweb/leaseweb-go-sdk/dedicatedserver/v2" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | func init() { 12 | dedicatedServerCmd.AddCommand(dedicatedServerIpGetCmd) 13 | dedicatedServerCmd.AddCommand(dedicatedServerIpListCmd) 14 | dedicatedServerIpListCmdFlags() 15 | } 16 | 17 | func dedicatedServerIpListCmdFlags() { 18 | dedicatedServerIpListCmd.Flags().StringVar(&networkType, "network-type", "", "Filter by network type") 19 | dedicatedServerIpListCmd.Flags().StringVar(&version, "version", "", "Filter by IP version") 20 | dedicatedServerIpListCmd.Flags().StringVar(&nullRouted, "null-routed", "", "Filter by null-routed status") 21 | dedicatedServerIpListCmd.Flags().StringVar(&ips, "ips", "", "Filter by specific IPs") 22 | dedicatedServerIpListCmd.Flags().Int32Var(&ipLimit, "limit", 0, "Limit the number of results") 23 | dedicatedServerIpListCmd.Flags().Int32Var(&ipOffset, "offset", 0, "Offset for pagination") 24 | } 25 | 26 | var dedicatedServerIpListCmd = &cobra.Command{ 27 | Use: "get-ips ", 28 | Short: "List the server IPs", 29 | Args: cobra.ExactArgs(1), 30 | RunE: func(cmd *cobra.Command, args []string) error { 31 | serverID := args[0] 32 | ctx := context.Background() 33 | 34 | req := leasewebClient.DedicatedserverAPI.GetIpList(ctx, serverID) 35 | req = req.Limit(ipLimit) 36 | if networkType != "" { 37 | req = req.NetworkType(dedicatedserver.NetworkType(networkType)) 38 | } 39 | if version != "" { 40 | req = req.Version(version) 41 | } 42 | if nullRouted != "" { 43 | req = req.NullRouted(nullRouted) 44 | } 45 | if ips != "" { 46 | req = req.Ips(ips) 47 | } 48 | if ipOffset > 0 { 49 | req = req.Offset(ipOffset) 50 | } 51 | 52 | server, _, err := req.Execute() 53 | if err != nil { 54 | return fmt.Errorf("list the server IPs: %w", err) 55 | } 56 | 57 | printResponse(server) 58 | return nil 59 | }, 60 | } 61 | 62 | var dedicatedServerIpGetCmd = &cobra.Command{ 63 | Use: "get-ip ", 64 | Short: "Describe the server IP", 65 | Long: "Describe the server IP by server ID and IP address", 66 | Args: cobra.ExactArgs(2), 67 | RunE: func(cmd *cobra.Command, args []string) error { 68 | serverID := args[0] 69 | ip := args[1] 70 | ctx := context.Background() 71 | 72 | req := leasewebClient.DedicatedserverAPI.GetIp(ctx, serverID, ip) 73 | server, _, err := req.Execute() 74 | if err != nil { 75 | return fmt.Errorf("describe the server IP: %w", err) 76 | } 77 | 78 | printResponse(server) 79 | return nil 80 | }, 81 | } 82 | -------------------------------------------------------------------------------- /cmd/dedicated_server.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "strings" 9 | "time" 10 | 11 | dedicatedserver "github.com/leaseweb/leaseweb-go-sdk/dedicatedserver/v2" 12 | "github.com/spf13/cobra" 13 | ) 14 | 15 | func init() { 16 | registerDedicatedServerCommands() 17 | registerDedicatedServerListFlags() 18 | } 19 | 20 | func registerDedicatedServerCommands() { 21 | dedicatedServerCmd.AddCommand(dedicatedServerlistCmd) 22 | dedicatedServerCmd.AddCommand(dedicatedServerGetOS) 23 | dedicatedServerCmd.AddCommand(dedicatedServerGetCmd) 24 | dedicatedServerCmd.AddCommand(dedicatedServerHardwareGetCmd) 25 | dedicatedServerCmd.AddCommand(dedicatedServerPowerOnCmd) 26 | dedicatedServerCmd.AddCommand(dedicatedServerPowerOffCmd) 27 | dedicatedServerCmd.AddCommand(dedicatedServerCredsGetCmd) 28 | dedicatedServerCmd.AddCommand(dedicatedServerContractRenewalCmd) 29 | dedicatedServerCmd.AddCommand(dedicatedServerPowerCycleCmd) 30 | 31 | rootCmd.AddCommand(dedicatedServerCmd) 32 | } 33 | 34 | func registerDedicatedServerListFlags() { 35 | dedicatedServerlistCmd.Flags().Int32Var(&serverLimit, "limit", 0, "Maximum number of servers to retrieve (default unlimited)") 36 | dedicatedServerlistCmd.Flags().Int32Var(&serverOffset, "offset", 0, "Return results starting from the given offset") 37 | dedicatedServerGetOS.Flags().Int32Var(&osLimit, "limit", 0, "Maximum number of servers to retrieve (default unlimited)") 38 | dedicatedServerGetOS.Flags().Int32Var(&osOffset, "offset", 0, "Return results starting from the given offset") 39 | 40 | // Add filters for dedicated server list 41 | dedicatedServerlistCmd.Flags().StringVar(&reference, "reference", "", "Filter by reference") 42 | dedicatedServerlistCmd.Flags().StringVar(&ip, "ip", "", "Filter by IP address") 43 | dedicatedServerlistCmd.Flags().StringVar(&macAddress, "mac", "", "Filter by MAC address") 44 | dedicatedServerlistCmd.Flags().StringVar(&site, "site", "", "Filter by site") 45 | dedicatedServerlistCmd.Flags().StringVar(&privateRackId, "private-rack-id", "", "Filter by rack ID") 46 | dedicatedServerlistCmd.Flags().StringVar(&privateNetworkCapable, "private-network-capable", "", "Filter for private network capable servers") 47 | dedicatedServerlistCmd.Flags().StringVar(&privateNetworkEnabled, "private-network-enabled", "", "Filter for private network enabled servers") 48 | } 49 | 50 | var dedicatedServerCmd = &cobra.Command{ 51 | Use: "dedicated-server", 52 | Short: "Manage dedicated servers", 53 | } 54 | 55 | var dedicatedServerlistCmd = &cobra.Command{ 56 | Use: "list", 57 | Short: "Retrieve the list of servers", 58 | RunE: func(cmd *cobra.Command, args []string) error { 59 | ctx := context.Background() 60 | allServers := []dedicatedserver.Server{} 61 | 62 | currentOffset := serverOffset 63 | apiMaxLimit := int32(50) 64 | 65 | fetchAll := serverLimit == 0 66 | 67 | for { 68 | batchLimit := apiMaxLimit 69 | if !fetchAll { 70 | if remaining := serverLimit - int32(len(allServers)); remaining < apiMaxLimit && remaining > 0 { 71 | batchLimit = remaining 72 | } 73 | } 74 | 75 | req := leasewebClient.DedicatedserverAPI.GetServerList(ctx). 76 | Limit(batchLimit). 77 | Offset(currentOffset) 78 | 79 | if reference != "" { 80 | req = req.Reference(reference) 81 | } 82 | if ip != "" { 83 | req = req.Ip(ip) 84 | } 85 | if macAddress != "" { 86 | req = req.MacAddress(macAddress) 87 | } 88 | if site != "" { 89 | req = req.Site(site) 90 | } 91 | if privateRackId != "" { 92 | req = req.PrivateRackId(privateRackId) 93 | } 94 | if privateNetworkCapable != "" { 95 | req = req.PrivateNetworkCapable(privateNetworkCapable) 96 | } 97 | if privateNetworkEnabled != "" { 98 | req = req.PrivateNetworkEnabled(privateNetworkEnabled) 99 | } 100 | 101 | serverResponse, _, err := req.Execute() 102 | if err != nil { 103 | return fmt.Errorf("retrieving the list of servers: %w", err) 104 | } 105 | 106 | allServers = append(allServers, serverResponse.Servers...) 107 | 108 | if len(serverResponse.Servers) < int(batchLimit) { 109 | break 110 | } 111 | 112 | if !fetchAll && int32(len(allServers)) >= serverLimit { 113 | break 114 | } 115 | 116 | currentOffset += batchLimit 117 | } 118 | 119 | printResponse(allServers) 120 | return nil 121 | }, 122 | } 123 | 124 | var dedicatedServerGetOS = &cobra.Command{ 125 | Use: "list-os", 126 | Short: "Retrieve the list of available operating systems", 127 | RunE: func(cmd *cobra.Command, args []string) error { 128 | ctx := context.Background() 129 | allOSes := []dedicatedserver.OperatingSystem{} 130 | 131 | currentOffset := osOffset 132 | apiMaxLimit := int32(50) 133 | 134 | fetchAll := osLimit == 0 135 | 136 | for { 137 | batchLimit := apiMaxLimit 138 | if !fetchAll { 139 | if remaining := serverLimit - int32(len(allOSes)); remaining < apiMaxLimit && remaining > 0 { 140 | batchLimit = remaining 141 | } 142 | } 143 | 144 | req := leasewebClient.DedicatedserverAPI.GetOperatingSystemList(ctx). 145 | Limit(batchLimit). 146 | Offset(currentOffset) 147 | 148 | osResponse, _, err := req.Execute() 149 | if err != nil { 150 | return fmt.Errorf("retrieving the list of OSes: %w", err) 151 | } 152 | 153 | allOSes = append(allOSes, osResponse.OperatingSystems...) 154 | 155 | if len(osResponse.OperatingSystems) < int(batchLimit) { 156 | break 157 | } 158 | 159 | if !fetchAll && int32(len(allOSes)) >= serverLimit { 160 | break 161 | } 162 | 163 | currentOffset += batchLimit 164 | } 165 | 166 | printResponse(allOSes) 167 | return nil 168 | }, 169 | } 170 | 171 | var dedicatedServerGetCmd = &cobra.Command{ 172 | Use: "get", 173 | Short: "Retrieve details of the server by ID", 174 | Example: "leaseweb-cli dedicated-server get 12345", 175 | Args: cobra.ExactArgs(1), 176 | RunE: func(cmd *cobra.Command, args []string) error { 177 | ctx := context.Background() 178 | server, _, err := leasewebClient.DedicatedserverAPI.GetServer(ctx, args[0]).Execute() 179 | if err != nil { 180 | return fmt.Errorf("retrieving details of the server: %w", err) 181 | } 182 | 183 | printResponse(server) 184 | return nil 185 | }, 186 | } 187 | 188 | var dedicatedServerHardwareGetCmd = &cobra.Command{ 189 | Use: "get-hardware", 190 | Short: "Retrieve hardware details of the server by ID", 191 | Example: "leaseweb-cli dedicated-server get-hardware 12345", 192 | Args: cobra.ExactArgs(1), 193 | RunE: func(cmd *cobra.Command, args []string) error { 194 | ctx := context.Background() 195 | 196 | _, httpResp, err := leasewebClient.DedicatedserverAPI.GetHardware(ctx, args[0]).Execute() 197 | if err != nil { 198 | return fmt.Errorf("retrieving hardware details: %w", err) 199 | } 200 | 201 | body, err := io.ReadAll(httpResp.Body) 202 | if err != nil { 203 | return fmt.Errorf("reading response body: %w", err) 204 | } 205 | defer httpResp.Body.Close() 206 | 207 | jsonStr := string(body) 208 | jsonStr = strings.ReplaceAll(jsonStr, `"smartctl":true`, `"smartctl":"enabled"`) 209 | jsonStr = strings.ReplaceAll(jsonStr, `"smartctl":false`, `"smartctl":"disabled"`) 210 | 211 | var data interface{} 212 | if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { 213 | return fmt.Errorf("parsing JSON: %w", err) 214 | } 215 | 216 | pretty, err := json.MarshalIndent(data, "", " ") 217 | if err != nil { 218 | return fmt.Errorf("formatting JSON: %w", err) 219 | } 220 | 221 | fmt.Println(string(pretty)) 222 | return nil 223 | }, 224 | } 225 | 226 | var dedicatedServerContractRenewalCmd = &cobra.Command{ 227 | Use: "get-contract-renewal", 228 | Short: "Retrieve next contract renewal date in milliseconds since epoch by server ID", 229 | Args: cobra.ExactArgs(1), 230 | RunE: func(cmd *cobra.Command, args []string) error { 231 | ctx := context.Background() 232 | server, _, err := leasewebClient.DedicatedserverAPI.GetServer(ctx, args[0]).Execute() 233 | if err != nil { 234 | return fmt.Errorf("retrieving next contract renewal date: %w", err) 235 | } 236 | 237 | if server.Contract == nil || server.Contract.StartsAt == nil { 238 | return fmt.Errorf("contract start date is missing in API response") 239 | } 240 | if server.Contract.ContractTerm == nil { 241 | return fmt.Errorf("contract term is missing in API response") 242 | } 243 | 244 | startDate := *server.Contract.StartsAt 245 | contractTerm := int(*server.Contract.ContractTerm) 246 | 247 | now := time.Now() 248 | 249 | renewalDate := startDate 250 | for !renewalDate.After(now) { 251 | renewalDate = renewalDate.AddDate(0, contractTerm, 0) 252 | } 253 | 254 | fmt.Println(renewalDate.UnixMilli()) 255 | return nil 256 | }, 257 | } 258 | 259 | var dedicatedServerCredsGetCmd = &cobra.Command{ 260 | Use: "get-creds ", 261 | Short: "Retrieve the server credentials", 262 | Long: `Retrieve credentials for the server by providing: 263 | 264 | - serverId: The ID of the dedicated server. 265 | - type: The credential type (e.g., "OPERATING_SYSTEM", "REMOTE_MANAGEMENT"). 266 | - username: The username associated with the credential.`, 267 | Example: ` # Get credentials for a OS 268 | leaseweb-cli get-creds 12345 OPERATING_SYSTEM root 269 | 270 | # Get credentials for a remote management 271 | leaseweb-cli get-creds 12345 REMOTE_MANAGEMENT admin`, 272 | Args: cobra.ExactArgs(3), 273 | RunE: func(cmd *cobra.Command, args []string) error { 274 | serverID := args[0] 275 | credType := dedicatedserver.CredentialType(args[1]) 276 | username := args[2] 277 | 278 | ctx := context.Background() 279 | _, r, err := leasewebClient.DedicatedserverAPI. 280 | GetCredential(ctx, serverID, credType, username). 281 | Execute() 282 | 283 | if err != nil { 284 | return fmt.Errorf("retrieving the server credentials: %w", err) 285 | } 286 | 287 | prettyPrintResponse(r) 288 | return nil 289 | }, 290 | } 291 | 292 | var dedicatedServerPowerOnCmd = &cobra.Command{ 293 | Use: "power-on", 294 | Short: "Power on the server", 295 | Args: cobra.ExactArgs(1), 296 | RunE: func(cmd *cobra.Command, args []string) error { 297 | ctx := context.Background() 298 | _, err := leasewebClient.DedicatedserverAPI.PowerOn(ctx, args[0]).Execute() 299 | if err != nil { 300 | return fmt.Errorf("power on the server: %w", err) 301 | } 302 | return nil 303 | }, 304 | } 305 | 306 | var dedicatedServerPowerOffCmd = &cobra.Command{ 307 | Use: "power-off", 308 | Short: "Power off the server", 309 | Args: cobra.ExactArgs(1), 310 | RunE: func(cmd *cobra.Command, args []string) error { 311 | ctx := context.Background() 312 | _, err := leasewebClient.DedicatedserverAPI.PowerOff(ctx, args[0]).Execute() 313 | if err != nil { 314 | return fmt.Errorf("power off the server: %w", err) 315 | } 316 | return nil 317 | }, 318 | } 319 | 320 | var dedicatedServerPowerCycleCmd = &cobra.Command{ 321 | Use: "reboot", 322 | Short: "Power cycle the server", 323 | Args: cobra.ExactArgs(1), 324 | RunE: func(cmd *cobra.Command, args []string) error { 325 | ctx := context.Background() 326 | _, err := leasewebClient.DedicatedserverAPI.PowerCycle(ctx, args[0]).Execute() 327 | if err != nil { 328 | return fmt.Errorf("power cycle the server: %w", err) 329 | } 330 | return nil 331 | }, 332 | } 333 | --------------------------------------------------------------------------------