Skip to content

Commit bf4cad6

Browse files
committed
feat: implement get cloud
1 parent 7e1d614 commit bf4cad6

18 files changed

+266
-13
lines changed

api/cloud.go

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package api
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
"io/ioutil"
8+
)
9+
10+
type GetCloudInput struct {
11+
GpuCount int `json:"gpuCount"`
12+
MinMemoryInGb int `json:"minMemoryInGb,omitempty"`
13+
MinVcpuCount int `json:"minVcpuCount,omitempty"`
14+
SecureCloud *bool `json:"secureCloud"`
15+
TotalDisk int `json:"totalDisk,omitempty"`
16+
}
17+
18+
func GetCloud(in *GetCloudInput) (gpuTypes []interface{}, err error) {
19+
input := Input{
20+
Query: `
21+
query LowestPrice($input: GpuLowestPriceInput!) {
22+
gpuTypes {
23+
lowestPrice(input: $input) {
24+
gpuName
25+
gpuTypeId
26+
minimumBidPrice
27+
uninterruptablePrice
28+
minMemory
29+
minVcpu
30+
}
31+
}
32+
}
33+
`,
34+
Variables: map[string]interface{}{"input": in},
35+
}
36+
res, err := Query(input)
37+
if err != nil {
38+
return
39+
}
40+
defer res.Body.Close()
41+
rawData, err := ioutil.ReadAll(res.Body)
42+
if err != nil {
43+
return
44+
}
45+
if res.StatusCode != 200 {
46+
err = fmt.Errorf("statuscode %d: %s", res.StatusCode, string(rawData))
47+
return
48+
}
49+
data := make(map[string]interface{})
50+
if err = json.Unmarshal(rawData, &data); err != nil {
51+
return
52+
}
53+
gqlErrors, ok := data["errors"].([]interface{})
54+
if ok && len(gqlErrors) > 0 {
55+
firstErr, _ := gqlErrors[0].(map[string]interface{})
56+
err = errors.New(firstErr["message"].(string))
57+
return
58+
}
59+
gqldata, ok := data["data"].(map[string]interface{})
60+
if !ok || gqldata == nil {
61+
err = fmt.Errorf("data is nil: %s", string(rawData))
62+
return
63+
}
64+
gpuTypes, ok = gqldata["gpuTypes"].([]interface{})
65+
if !ok || gpuTypes == nil {
66+
err = fmt.Errorf("gpuTypes is nil: %s", string(rawData))
67+
return
68+
}
69+
return
70+
}

cmd/cloud/getCloud.go

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package cloud
2+
3+
import (
4+
"cli/api"
5+
"cli/format"
6+
"fmt"
7+
"os"
8+
"strconv"
9+
10+
"github.com/olekukonko/tablewriter"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
var community bool
15+
var disk int
16+
var memory int
17+
var vcpu int
18+
var secure bool
19+
20+
var GetCloudCmd = &cobra.Command{
21+
Use: "cloud [gpuCount]",
22+
Args: cobra.MaximumNArgs(1),
23+
Short: "get all cloud gpus",
24+
Long: "get all cloud gpus available on runpod.io",
25+
Run: func(cmd *cobra.Command, args []string) {
26+
var err error
27+
gpuCount := 1
28+
if len(args) > 0 {
29+
gpuCount, err = strconv.Atoi(args[0])
30+
cobra.CheckErr(err)
31+
if gpuCount <= 0 {
32+
cobra.CheckErr(fmt.Errorf("gpu count must be > 0: %d", gpuCount))
33+
}
34+
}
35+
var secureCloud *bool
36+
if secure != community {
37+
secureCloud = &secure
38+
}
39+
input := &api.GetCloudInput{
40+
GpuCount: gpuCount,
41+
MinMemoryInGb: memory,
42+
MinVcpuCount: vcpu,
43+
SecureCloud: secureCloud,
44+
TotalDisk: disk,
45+
}
46+
gpuTypes, err := api.GetCloud(input)
47+
cobra.CheckErr(err)
48+
49+
data := [][]string{}
50+
for _, gpu := range gpuTypes {
51+
gpuType, ok := gpu.(map[string]interface{})
52+
if !ok {
53+
continue
54+
}
55+
kv, ok := gpuType["lowestPrice"].(map[string]interface{})
56+
if !ok || kv["minMemory"] == nil {
57+
continue
58+
}
59+
spotPrice, ok := kv["minimumBidPrice"].(float64)
60+
spotPriceString := "Reserved"
61+
if ok && spotPrice > 0 {
62+
spotPriceString = fmt.Sprintf("%.3f", spotPrice)
63+
}
64+
onDemandPrice, ok := kv["uninterruptablePrice"].(float64)
65+
onDemandPriceString := "Reserved"
66+
if ok && spotPrice > 0 {
67+
onDemandPriceString = fmt.Sprintf("%.3f", onDemandPrice)
68+
}
69+
row := []string{
70+
fmt.Sprintf("%dx %s", gpuCount, kv["gpuTypeId"].(string)),
71+
fmt.Sprintf("%.f", kv["minMemory"]),
72+
fmt.Sprintf("%.f", kv["minVcpu"]),
73+
spotPriceString,
74+
onDemandPriceString,
75+
}
76+
data = append(data, row)
77+
}
78+
79+
header := []string{"GPU Type", "Mem GB", "vCPU", "Spot $/HR", "OnDemand $/HR"}
80+
tb := tablewriter.NewWriter(os.Stdout)
81+
tb.SetHeader(header)
82+
tb.AppendBulk(data)
83+
format.TableDefaults(tb)
84+
tb.Render()
85+
},
86+
}
87+
88+
func init() {
89+
GetCloudCmd.Flags().BoolVarP(&community, "community", "c", false, "show listings from community cloud only")
90+
GetCloudCmd.Flags().IntVar(&disk, "disk", 0, "minimum disk size in GB you need")
91+
GetCloudCmd.Flags().IntVar(&memory, "mem", 0, "minimum sys memory size in GB you need")
92+
GetCloudCmd.Flags().IntVar(&vcpu, "vcpu", 0, "minimum vCPUs you need")
93+
GetCloudCmd.Flags().BoolVarP(&secure, "secure", "s", false, "show listings from secure cloud only")
94+
}

cmd/get.go

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cmd
22

33
import (
4+
"cli/cmd/cloud"
45
"cli/cmd/pod"
56

67
"github.com/spf13/cobra"
@@ -13,5 +14,6 @@ var getCmd = &cobra.Command{
1314
}
1415

1516
func init() {
17+
getCmd.AddCommand(cloud.GetCloudCmd)
1618
getCmd.AddCommand(pod.GetPodCmd)
1719
}

cmd/pod/createPod.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func init() {
7676
CreatePodCmd.Flags().BoolVar(&communityCloud, "communityCloud", false, "create in community cloud")
7777
CreatePodCmd.Flags().BoolVar(&secureCloud, "secureCloud", false, "create in secure cloud")
7878
CreatePodCmd.Flags().IntVar(&containerDiskInGb, "containerDiskSize", 20, "container disk size in GB")
79-
CreatePodCmd.Flags().Float32Var(&deployCost, "cost", 0, "max $ / hr your willing to pay")
79+
CreatePodCmd.Flags().Float32Var(&deployCost, "cost", 0, "$/hr price ceiling, if not defined, pod will be created with lowest price available")
8080
CreatePodCmd.Flags().StringVar(&dockerArgs, "args", "", "container arguments")
8181
CreatePodCmd.Flags().StringSliceVar(&env, "env", nil, "container arguments")
8282
CreatePodCmd.Flags().IntVar(&gpuCount, "gpuCount", 1, "number of GPUs for the pod")
@@ -89,7 +89,6 @@ func init() {
8989
CreatePodCmd.Flags().IntVar(&volumeInGb, "volumeSize", 1, "persistant volume disk size in GB")
9090
CreatePodCmd.Flags().StringVar(&volumeMountPath, "volumePath", "/runpod", "container volume path")
9191

92-
CreatePodCmd.MarkFlagRequired("cost")
9392
CreatePodCmd.MarkFlagRequired("gpuType")
9493
CreatePodCmd.MarkFlagRequired("imageName")
9594
}

doc/runpodctl.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ runpodctl is a CLI tool to manage your pods for runpod.io
1515
### SEE ALSO
1616

1717
* [runpodctl config](runpodctl_config.md) - CLI Config
18+
* [runpodctl create](runpodctl_create.md) - create a resource
1819
* [runpodctl get](runpodctl_get.md) - get resource
1920
* [runpodctl remove](runpodctl_remove.md) - remove a resource
2021
* [runpodctl start](runpodctl_start.md) - start a resource
2122
* [runpodctl stop](runpodctl_stop.md) - stop a resource
2223
* [runpodctl version](runpodctl_version.md) - runpodctl version
2324

24-
###### Auto generated by spf13/cobra on 11-Apr-2022
25+
###### Auto generated by spf13/cobra on 12-Apr-2022

doc/runpodctl_config.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ runpodctl config [flags]
2222

2323
* [runpodctl](runpodctl.md) - runpodctl for runpod.io
2424

25-
###### Auto generated by spf13/cobra on 11-Apr-2022
25+
###### Auto generated by spf13/cobra on 12-Apr-2022

doc/runpodctl_create.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
## runpodctl create
2+
3+
create a resource
4+
5+
### Synopsis
6+
7+
create a resource in runpod.io
8+
9+
### Options
10+
11+
```
12+
-h, --help help for create
13+
```
14+
15+
### SEE ALSO
16+
17+
* [runpodctl](runpodctl.md) - runpodctl for runpod.io
18+
* [runpodctl create pod](runpodctl_create_pod.md) - start a pod
19+
20+
###### Auto generated by spf13/cobra on 12-Apr-2022

doc/runpodctl_create_pod.md

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
## runpodctl create pod
2+
3+
start a pod
4+
5+
### Synopsis
6+
7+
start a pod from runpod.io
8+
9+
```
10+
runpodctl create pod [flags]
11+
```
12+
13+
### Options
14+
15+
```
16+
--args string container arguments
17+
--communityCloud create in community cloud
18+
--containerDiskSize int container disk size in GB (default 20)
19+
--cost float32 $/hr price ceiling, if not defined, pod will be created with lowest price available
20+
--env strings container arguments
21+
--gpuCount int number of GPUs for the pod (default 1)
22+
--gpuType string gpu type id, e.g. 'NVIDIA GeForce RTX 3090'
23+
-h, --help help for pod
24+
--imageName string container image name
25+
--mem int minimum system memory needed (default 20)
26+
--name string any pod name for easy reference
27+
--ports strings ports to expose; max only 1 http and 1 tcp allowed; e.g. '8888/http'
28+
--secureCloud create in secure cloud
29+
--vcpu int minimum vCPUs needed (default 1)
30+
--volumePath string container volume path (default "/runpod")
31+
--volumeSize int persistant volume disk size in GB (default 1)
32+
```
33+
34+
### SEE ALSO
35+
36+
* [runpodctl create](runpodctl_create.md) - create a resource
37+
38+
###### Auto generated by spf13/cobra on 12-Apr-2022

doc/runpodctl_get.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ get resources for pods
1515
### SEE ALSO
1616

1717
* [runpodctl](runpodctl.md) - runpodctl for runpod.io
18+
* [runpodctl get cloud](runpodctl_get_cloud.md) - get all cloud gpus
1819
* [runpodctl get pod](runpodctl_get_pod.md) - get all pods
1920

20-
###### Auto generated by spf13/cobra on 11-Apr-2022
21+
###### Auto generated by spf13/cobra on 12-Apr-2022

doc/runpodctl_get_cloud.md

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
## runpodctl get cloud
2+
3+
get all cloud gpus
4+
5+
### Synopsis
6+
7+
get all cloud gpus available on runpod.io
8+
9+
```
10+
runpodctl get cloud [gpuCount] [flags]
11+
```
12+
13+
### Options
14+
15+
```
16+
-c, --community show listings from community cloud only
17+
--disk int minimum disk size in GB you need
18+
-h, --help help for cloud
19+
--mem int minimum sys memory size in GB you need
20+
-s, --secure show listings from secure cloud only
21+
--vcpu int minimum vCPUs you need
22+
```
23+
24+
### SEE ALSO
25+
26+
* [runpodctl get](runpodctl_get.md) - get resource
27+
28+
###### Auto generated by spf13/cobra on 12-Apr-2022

doc/runpodctl_get_pod.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ runpodctl get pod [podId] [flags]
2121

2222
* [runpodctl get](runpodctl_get.md) - get resource
2323

24-
###### Auto generated by spf13/cobra on 11-Apr-2022
24+
###### Auto generated by spf13/cobra on 12-Apr-2022

doc/runpodctl_remove.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ remove a resource in runpod.io
1717
* [runpodctl](runpodctl.md) - runpodctl for runpod.io
1818
* [runpodctl remove pod](runpodctl_remove_pod.md) - remove a pod
1919

20-
###### Auto generated by spf13/cobra on 11-Apr-2022
20+
###### Auto generated by spf13/cobra on 12-Apr-2022

doc/runpodctl_remove_pod.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ runpodctl remove pod [podId] [flags]
2020

2121
* [runpodctl remove](runpodctl_remove.md) - remove a resource
2222

23-
###### Auto generated by spf13/cobra on 11-Apr-2022
23+
###### Auto generated by spf13/cobra on 12-Apr-2022

doc/runpodctl_start.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ start a resource in runpod.io
1717
* [runpodctl](runpodctl.md) - runpodctl for runpod.io
1818
* [runpodctl start pod](runpodctl_start_pod.md) - start a pod
1919

20-
###### Auto generated by spf13/cobra on 11-Apr-2022
20+
###### Auto generated by spf13/cobra on 12-Apr-2022

doc/runpodctl_start_pod.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ runpodctl start pod [podId] [flags]
2121

2222
* [runpodctl start](runpodctl_start.md) - start a resource
2323

24-
###### Auto generated by spf13/cobra on 11-Apr-2022
24+
###### Auto generated by spf13/cobra on 12-Apr-2022

doc/runpodctl_stop.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ stop a resource in runpod.io
1717
* [runpodctl](runpodctl.md) - runpodctl for runpod.io
1818
* [runpodctl stop pod](runpodctl_stop_pod.md) - stop a pod
1919

20-
###### Auto generated by spf13/cobra on 11-Apr-2022
20+
###### Auto generated by spf13/cobra on 12-Apr-2022

doc/runpodctl_stop_pod.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ runpodctl stop pod [podId] [flags]
2020

2121
* [runpodctl stop](runpodctl_stop.md) - stop a resource
2222

23-
###### Auto generated by spf13/cobra on 11-Apr-2022
23+
###### Auto generated by spf13/cobra on 12-Apr-2022

doc/runpodctl_version.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ runpodctl version [flags]
2020

2121
* [runpodctl](runpodctl.md) - runpodctl for runpod.io
2222

23-
###### Auto generated by spf13/cobra on 11-Apr-2022
23+
###### Auto generated by spf13/cobra on 12-Apr-2022

0 commit comments

Comments
 (0)