Skip to content

Commit 634f9bf

Browse files
author
Philip Reichenberger
committed
Initial commit
1 parent 00d971b commit 634f9bf

8 files changed

+352
-5
lines changed

README.md

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,2 @@
1-
# paperspace-go
2-
Paperspace API go library
1+
# go-paperspace
32

4-
Coming soon...
5-
6-
Want to contribute? Contact us at [email protected]

api_backend.go

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package paperspace
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"errors"
7+
"fmt"
8+
"io/ioutil"
9+
"log"
10+
"math"
11+
"net/http"
12+
"net/http/httputil"
13+
"time"
14+
)
15+
16+
var DefaultBaseURL = "https://api.paperspace.io"
17+
18+
type APIBackend struct {
19+
BaseURL string
20+
Debug bool
21+
DebugBody bool
22+
HTTPClient *http.Client
23+
RetryCount int
24+
}
25+
26+
func NewAPIBackend() *APIBackend {
27+
return &APIBackend{
28+
BaseURL: DefaultBaseURL,
29+
Debug: false,
30+
HTTPClient: &http.Client{
31+
Timeout: 15 * time.Second,
32+
},
33+
RetryCount: 0,
34+
}
35+
}
36+
37+
func (c *APIBackend) Request(method string, url string,
38+
params, result interface{}, headers map[string]string) (res *http.Response, err error) {
39+
for i := 0; i < c.RetryCount+1; i++ {
40+
retryDuration := time.Duration((math.Pow(2, float64(i))-1)/2*1000) * time.Millisecond
41+
time.Sleep(retryDuration)
42+
43+
res, err = c.request(method, url, params, result, headers)
44+
if res != nil && res.StatusCode == 429 {
45+
continue
46+
} else {
47+
break
48+
}
49+
}
50+
51+
return res, err
52+
}
53+
54+
func (c *APIBackend) request(method string, url string,
55+
params, result interface{}, headers map[string]string) (res *http.Response, err error) {
56+
var data []byte
57+
body := bytes.NewReader(make([]byte, 0))
58+
59+
if params != nil {
60+
data, err = json.Marshal(params)
61+
if err != nil {
62+
return res, err
63+
}
64+
65+
body = bytes.NewReader(data)
66+
}
67+
68+
fullURL := fmt.Sprintf("%s%s", c.BaseURL, url)
69+
req, err := http.NewRequest(method, fullURL, body)
70+
if err != nil {
71+
return res, err
72+
}
73+
74+
req.Header.Add("Accept", "application/json")
75+
req.Header.Add("Content-Type", "application/json")
76+
req.Header.Add("User-Agent", "Go Paperspace Gradient 1.0")
77+
78+
for key, value := range headers {
79+
req.Header.Add(key, value)
80+
}
81+
82+
if c.Debug {
83+
requestDump, err := httputil.DumpRequest(req, c.DebugBody)
84+
if err != nil {
85+
return res, err
86+
}
87+
c.debug(string(requestDump))
88+
}
89+
90+
res, err = c.HTTPClient.Do(req)
91+
if err != nil {
92+
return res, err
93+
}
94+
defer res.Body.Close()
95+
96+
if c.Debug {
97+
responseDump, err := httputil.DumpResponse(res, c.DebugBody)
98+
if err != nil {
99+
return res, err
100+
}
101+
c.debug(string(responseDump))
102+
}
103+
104+
if res.StatusCode != 200 {
105+
defer res.Body.Close()
106+
errorBody, err := ioutil.ReadAll(res.Body)
107+
if err != nil {
108+
return res, err
109+
}
110+
errorReader := bytes.NewReader(errorBody)
111+
112+
paperspaceErrorResponse := PaperspaceErrorResponse{}
113+
paperspaceError := PaperspaceError{}
114+
errorResponseDecoder := json.NewDecoder(errorReader)
115+
if err := errorResponseDecoder.Decode(&paperspaceErrorResponse); err != nil {
116+
c.debug(string(err.Error()))
117+
return res, errors.New("There was a server error, please try your request again")
118+
}
119+
120+
if paperspaceErrorResponse.Error == nil {
121+
errorDecoder := json.NewDecoder(errorReader)
122+
if err := errorDecoder.Decode(&paperspaceErrorResponse); err != nil {
123+
c.debug(string(err.Error()))
124+
return res, errors.New("There was a server error, please try your request again")
125+
}
126+
127+
return res, error(paperspaceError)
128+
}
129+
130+
return res, error(paperspaceErrorResponse.Error)
131+
}
132+
133+
if result != nil {
134+
decoder := json.NewDecoder(res.Body)
135+
if err = decoder.Decode(result); err != nil {
136+
return res, err
137+
}
138+
}
139+
140+
return res, nil
141+
}
142+
143+
func (c *APIBackend) debug(message string) {
144+
if c.Debug {
145+
log.Println(message)
146+
}
147+
}

api_token.go

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package paperspace
2+
3+
type APIToken struct {
4+
Key string `json:"key"`
5+
}

backend.go

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package paperspace
2+
3+
import (
4+
"net/http"
5+
)
6+
7+
type Backend interface {
8+
Request(method, url string, params, result interface{}, headers map[string]string) (*http.Response, error)
9+
}

client.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package paperspace
2+
3+
import (
4+
"net/http"
5+
)
6+
7+
type Client struct {
8+
APIKey string
9+
Backend Backend
10+
}
11+
12+
// client that makes requests to Gradient API
13+
func NewClient() *Client {
14+
return &Client{
15+
Backend: NewAPIBackend(),
16+
}
17+
}
18+
19+
func NewClientWithBackend(backend Backend) *Client {
20+
return &Client{
21+
Backend: backend,
22+
}
23+
}
24+
25+
func (c *Client) Request(method, url string, params, result interface{}) (*http.Response, error) {
26+
headers := map[string]string{
27+
"x-api-key": c.APIKey,
28+
}
29+
return c.Backend.Request(method, url, params, result, headers)
30+
}

cluster.go

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package paperspace
2+
3+
import "fmt"
4+
5+
type ClusterPlatformType string
6+
7+
const (
8+
ClusterPlatformAWS ClusterPlatformType = "aws"
9+
ClusterPlatformMetal ClusterPlatformType = "metal"
10+
)
11+
12+
var ClusterAWSRegions = []string{
13+
"us-east-1",
14+
"us-east-2",
15+
"us-west-2",
16+
"ca-central-1",
17+
"sa-east-1",
18+
"eu-west-1",
19+
"eu-west-2",
20+
"eu-west-3",
21+
"eu-central-1",
22+
"eu-north-1",
23+
"me-south-1",
24+
"ap-east-1",
25+
"ap-northeast-1",
26+
"ap-northeast-2",
27+
"ap-southeast-1",
28+
"ap-southeast-2",
29+
"ap-south-1",
30+
}
31+
32+
var ClusterPlatforms = []ClusterPlatformType{ClusterPlatformAWS, ClusterPlatformMetal}
33+
var DefaultClusterType = 3
34+
35+
type Cluster struct {
36+
APIToken APIToken `json:"apiToken"`
37+
Domain string `json:"fqdn"`
38+
Platform ClusterPlatformType `json:"cloud"`
39+
Name string `json:"name"`
40+
ID string `json:"id"`
41+
Region string `json:"region,omitempty"`
42+
S3Credential S3Credential `json:"s3Credential"`
43+
TeamID string `json:"teamId"`
44+
Type string `json:"type,omitempty"`
45+
}
46+
47+
type ClusterCreateParams struct {
48+
ArtifactsAccessKeyID string `json:"accessKey,omitempty" yaml:"artifactsAccessKeyId,omitempty"`
49+
ArtifactsBucketPath string `json:"bucketPath,omitempty" yaml:"artifactsBucketPath,omitempty"`
50+
ArtifactsSecretAccessKey string `json:"secretKey,omitempty" yaml:"artifactsSecretAccessKey,omitempty"`
51+
Domain string `json:"fqdn" yaml:"domain"`
52+
IsDefault bool `json:"isDefault,omitempty" yaml"isDefault,omitempty"`
53+
Name string `json:"name" yaml:"name"`
54+
Platform string `json:"cloud,omitempty" yaml:"platform,omitempty"`
55+
Region string `json:"region,omitempty, yaml:"region,omitempty"`
56+
Type int `json:"type,omitempty" yaml:"type,omitempty"`
57+
}
58+
59+
type ClusterListParams struct {
60+
Filter map[string]string `json:"filter"`
61+
}
62+
63+
type ClusterUpdateAttributeParams struct {
64+
Domain string `json:"fqdn,omitempty" yaml:"domain"`
65+
Name string `json:"name,omitempty" yaml:"name"`
66+
}
67+
68+
type ClusterUpdateRegistryParams struct {
69+
URL string `json:"url,omitempty"`
70+
Password string `json:"password,omitempty"`
71+
Repository string `json:"repository,omitempty"`
72+
Username string `json:"username,omitempty"`
73+
}
74+
75+
type ClusterUpdateS3Params struct {
76+
AccessKey string `json:"accessKey,omitempty"`
77+
Bucket string `json:"bucket,omitempty"`
78+
SecretKey string `json:"secretKey,omitempty"`
79+
}
80+
81+
type ClusterUpdateParams struct {
82+
Attributes ClusterUpdateAttributeParams `json:"attributes,omitempty"`
83+
CreateNewToken bool `json:"createNewToken,omitempty"`
84+
RegistryAttributes ClusterUpdateRegistryParams `json:"registryAttributes,omitempty"`
85+
ID string `json:"id"`
86+
RetryWorkflow bool `json:"retryWorkflow,omitempty"`
87+
S3Attributes ClusterUpdateS3Params `json:"s3Attributes,omitempty"`
88+
}
89+
90+
func NewClusterListParams() *ClusterListParams {
91+
clusterListParams := ClusterListParams{
92+
Filter: make(map[string]string),
93+
}
94+
95+
return &clusterListParams
96+
}
97+
98+
func (c Client) CreateCluster(params ClusterCreateParams) (Cluster, error) {
99+
cluster := Cluster{}
100+
params.Type = DefaultClusterType
101+
102+
url := fmt.Sprintf("/clusters/createCluster")
103+
_, err := c.Request("POST", url, params, &cluster)
104+
105+
return cluster, err
106+
}
107+
108+
func (c Client) GetCluster(ID string) (Cluster, error) {
109+
cluster := Cluster{}
110+
111+
url := fmt.Sprintf("/clusters/getCluster?id=%s", ID)
112+
_, err := c.Request("GET", url, nil, &cluster)
113+
114+
return cluster, err
115+
}
116+
117+
func (c Client) GetClusters(p ...ClusterListParams) ([]Cluster, error) {
118+
clusters := []Cluster{}
119+
params := NewClusterListParams()
120+
121+
if len(p) > 0 {
122+
params = &p[0]
123+
}
124+
125+
url := fmt.Sprintf("/clusters/getClusters")
126+
_, err := c.Request("GET", url, params, &clusters)
127+
128+
return clusters, err
129+
}
130+
131+
func (c Client) UpdateCluster(id string, p ClusterUpdateParams) (Cluster, error) {
132+
cluster := Cluster{}
133+
134+
url := fmt.Sprintf("/clusters/updateCluster")
135+
_, err := c.Request("POST", url, p, &cluster)
136+
137+
return cluster, err
138+
}

error.go

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package paperspace
2+
3+
type PaperspaceErrorResponse struct {
4+
Error *PaperspaceError `json:"error"`
5+
}
6+
7+
type PaperspaceError struct {
8+
Name string `json:"name"`
9+
Message string `json:"message"`
10+
Status int `json:"status"`
11+
}
12+
13+
func (e PaperspaceError) Error() string {
14+
return e.Message
15+
}

s3_credential.go

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package paperspace
2+
3+
type S3Credential struct {
4+
AccessKey string `json:"accessKey"`
5+
Bucket string `json:"bucket"`
6+
SecretKey string `json:"secretKey,omitempty"`
7+
}

0 commit comments

Comments
 (0)