move to v2 of gsclient-go

release/release-0.3.0
parent 1a976e0bcd
commit 531b601dbd
No known key found for this signature in database
GPG Key ID: 0B266738824CE0F0

@ -4,7 +4,9 @@ go 1.13
require (
github.com/google/uuid v1.1.1 // indirect
github.com/gridscale/gsclient-go v1.0.0
github.com/gridscale/gsclient-go/v2 v2.2.1
github.com/jessevdk/go-flags v1.4.0
github.com/sirupsen/logrus v1.4.2 // indirect
github.com/spf13/viper v1.4.0
github.com/stretchr/testify v1.4.0 // indirect
)

@ -14,6 +14,7 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
@ -38,7 +39,10 @@ github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gridscale/gsclient-go v1.0.0 h1:zQrWgeRwrL65dIMFm5X0JOFguitJGFIzNzQOKp5eWVE=
github.com/gridscale/gsclient-go v1.0.0/go.mod h1:GqJohyXKzDhL7XBgOz3+sycVXeF8lXVdZSDcK5y8AIM=
github.com/gridscale/gsclient-go v2.1.0+incompatible h1:RO7nWtt355F2OY86erFD0qVLrRJSCxGT/GLM5eHXm7E=
github.com/gridscale/gsclient-go v2.1.0+incompatible/go.mod h1:GqJohyXKzDhL7XBgOz3+sycVXeF8lXVdZSDcK5y8AIM=
github.com/gridscale/gsclient-go/v2 v2.2.1 h1:fbhFkB69vjcM9G9L6QOtG0qGFa7mwTv8xHWJQuIErRM=
github.com/gridscale/gsclient-go/v2 v2.2.1/go.mod h1:KD1DEHxc/mwyZ4q1i0zTVgav2RZHhOsWza3T7Og6krQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
@ -82,6 +86,8 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
@ -94,9 +100,12 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
@ -125,6 +134,8 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

@ -4,7 +4,7 @@ package main
import (
"fmt"
"github.com/gridscale/gsclient-go"
"github.com/gridscale/gsclient-go/v2"
"github.com/jessevdk/go-flags"
"github.com/spf13/viper"
"log"
@ -44,12 +44,7 @@ func config(configFile string) {
Config.UserId = viper.GetString("gridscale.userid")
Config.Token = viper.GetString("gridscale.token")
gsConfig := gsclient.NewConfiguration(
"https://api.gridscale.io",
Config.UserId,
Config.Token,
true,
)
gsConfig := gsclient.DefaultConfiguration(Config.UserId, Config.Token)
Config.Client = gsclient.NewClient(gsConfig)
@ -63,12 +58,7 @@ func main() {
Config.UserId = os.Getenv("GRIDSCALE_USER")
Config.Token = os.Getenv("GRIDSCALE_TOKEN")
gsConfig := gsclient.NewConfiguration(
"https://api.gridscale.io",
Config.UserId,
Config.Token,
true,
)
gsConfig := gsclient.DefaultConfiguration(Config.UserId, Config.Token)
Config.Client = gsclient.NewClient(gsConfig)

@ -3,6 +3,7 @@
package main
import (
"context"
"fmt"
)
@ -15,7 +16,8 @@ func (x *ListServersCommand) Execute(args []string) error {
config(Checker.ConfigFile)
servers, error := Config.Client.GetServerList()
ctx := context.Background()
servers, error := Config.Client.GetServerList(ctx)
if error != nil {
Unknown(fmt.Sprintf("Error while retrieving servers: %s", error))

@ -3,6 +3,7 @@
package main
import (
"context"
"fmt"
)
@ -21,9 +22,11 @@ var serversStatusCommand ServersStatusCommand
func (x *ServersStatusCommand) Execute(args []string) error {
config(Checker.ConfigFile)
ctx := context.Background()
if x.Type == "server.status" {
server, err := Config.Client.GetServer(x.ServerUUID)
server, err := Config.Client.GetServer(ctx, x.ServerUUID)
if err != nil {
Unknown(fmt.Sprintf("%s: %s", "Error retrieving server", err))
}
@ -37,12 +40,12 @@ func (x *ServersStatusCommand) Execute(args []string) error {
if x.Type == "firewall.template" {
publicNet, err := Config.Client.GetNetworkPublic()
publicNet, err := Config.Client.GetNetworkPublic(ctx)
if err != nil {
Unknown(fmt.Sprintf("%s: %s", "Error retrieving public network", err))
}
networkRel, err := Config.Client.GetServerNetwork(x.ServerUUID, publicNet.Properties.ObjectUUID)
networkRel, err := Config.Client.GetServerNetwork(ctx, x.ServerUUID, publicNet.Properties.ObjectUUID)
if networkRel.FirewallTemplateUUID == x.Relation {
Ok(fmt.Sprintf("Expected firewall template '%s' is active", networkRel.FirewallTemplateUUID))
@ -52,7 +55,7 @@ func (x *ServersStatusCommand) Execute(args []string) error {
}
if x.Type == "server.cores" {
server, err := Config.Client.GetServer(x.ServerUUID)
server, err := Config.Client.GetServer(ctx, x.ServerUUID)
if err != nil {
Unknown(fmt.Sprintf("%s: %s", "Error retrieving server", err))
@ -72,7 +75,7 @@ func (x *ServersStatusCommand) Execute(args []string) error {
}
if x.Type == "server.memory" {
server, err := Config.Client.GetServer(x.ServerUUID)
server, err := Config.Client.GetServer(ctx, x.ServerUUID)
if err != nil {
Unknown(fmt.Sprintf("%s: %s", "Error retrieving server", err))
@ -92,7 +95,7 @@ func (x *ServersStatusCommand) Execute(args []string) error {
}
if x.Type == "ip.assigned" {
ipRel, err := Config.Client.GetServerIPList(x.ServerUUID)
ipRel, err := Config.Client.GetServerIPList(ctx, x.ServerUUID)
if err != nil {
Unknown(fmt.Sprintf("%s: %s", "Error retrieving server", err))
}

@ -3,10 +3,11 @@
package main
import (
"context"
"fmt"
"time"
"github.com/gridscale/gsclient-go"
"github.com/gridscale/gsclient-go/v2"
)
type SnapshotsAgeCommand struct {
@ -22,7 +23,8 @@ func (x *SnapshotsAgeCommand) Execute(args []string) error {
config(Checker.ConfigFile)
snapshotList, error := Config.Client.GetStorageSnapshotList(x.StorageUUID)
ctx := context.Background()
snapshotList, error := Config.Client.GetStorageSnapshotList(ctx, x.StorageUUID)
if error != nil {
Unknown("Error retrieving snapshots")
@ -35,7 +37,7 @@ func (x *SnapshotsAgeCommand) Execute(args []string) error {
storageSnapshot := gsclient.StorageSnapshot{}
for _, v := range snapshotList {
if v.Properties.CreateTime > timestamp {
if v.Properties.CreateTime.After(timestamp.Time) {
timestamp = v.Properties.CreateTime
storageSnapshot = v
}
@ -59,7 +61,7 @@ func init() {
func checkAge(snapshot gsclient.StorageSnapshot, warning time.Duration, critical time.Duration) error {
snapshotCreateTime, err := time.Parse("2019-09-02T12:44:48Z", snapshot.Properties.CreateTime)
snapshotCreateTime, err := time.Parse("2019-09-02T12:44:48Z", snapshot.Properties.CreateTime.String())
if err != nil {
Unknown("Error converting CreateTime of snapshot")

@ -3,8 +3,9 @@
package main
import (
"context"
"fmt"
"github.com/gridscale/gsclient-go"
"github.com/gridscale/gsclient-go/v2"
)
type SnapshotsCountCommand struct {
@ -19,7 +20,8 @@ func (x *SnapshotsCountCommand) Execute(args []string) error {
config(Checker.ConfigFile)
snapshots, error := Config.Client.GetStorageSnapshotList(x.StorageUUID)
ctx := context.Background()
snapshots, error := Config.Client.GetStorageSnapshotList(ctx, x.StorageUUID)
if error != nil {
Unknown("Error retrieving snapshots")

@ -3,6 +3,7 @@
package main
import (
"context"
"fmt"
)
@ -15,7 +16,8 @@ func (x *StorageListCommand) Execute(args []string) error {
config(Checker.ConfigFile)
storages, error := Config.Client.GetStorageList()
ctx := context.Background()
storages, error := Config.Client.GetStorageList(ctx)
if error != nil {
Unknown(fmt.Sprintf("Error while retrieving storages: %s", error))

@ -1,5 +1,35 @@
# Changelog
## 2.1.0 (November 05, 2019)
IMPROVEMENTS:
* Errors that are from http requests now include request UUIDs
* No need to create structs when exporting snapshots to S3
* Waiting for asynchronous requests is now faster and more memory-friendly
BUG FIXES:
* Fix README
* Fix missing JSON properties
## 2.0.0 (October 07, 2019)
FEATURES:
* Add `sync` mode
* The library now can be fully controlled through `context`
* Auto retry when server returns 5xx and 424 http codes
* Add a default configuration for the client
IMPROVEMENTS:
* Server type is now limited to pre-defined values
* Storage type is now limited to pre-defined values
* IP address family is now limited to pre-defined values
* Loadbalancer algorithm is now limited to pre-defined values
* All time-related properties are now type of GSTime (a custom type of time.Time)
* Friendly godoc.
BUG FIXES:
* Fixed bugs when unmarshalling JSON to concrete type (mismatched type)
## 1.0.0 (September 05, 2019)
FEATURES:

@ -30,7 +30,20 @@ import (
To get access to the functions of the Go client, a Client type needs to be created. This requires a Config type. Both of these can be created with the following code:
```go
config := gsclient.NewConfiguration("User-UUID", "API-token")
//Using default config
config := gsclient.DefaultConfiguration("User-UUID", "API-token")
//OR Custom config
config := gsclient.NewConfiguration(
"API-URL",
"User-UUID",
"API-token"),
false, //Set debug mode
true, //Set sync mode
120, //Timeout (in seconds) of checking requests
500, //Delay (in milliseconds) between requests
100, //Maximum number of retries
)
client := gsclient.NewClient(config)
```
@ -38,21 +51,25 @@ Make sure to replace the user-UUID and API-token strings with valid credentials
## Using API endpoints
***Note: `context` has to be passed to all APIs of `gsclient-go` as the first parameter.
After having created a Client type, as shown above, it will be possible to interact with the API. An example would be the [Servers Get endpoint](https://gridscale.io/en/api-documentation/index.html#servers-get):
```go
servers := client.GetServerList()
cxt := context.Background()
servers := client.GetServerList(ctx)
```
For creating and updating/patching objects in gridscale, it will be required to use the respective CreateRequest and UpdateRequest types. For creating an SSH-key that would be SshkeyCreateRequest and SshkeyUpdateRequest. Here an example:
```go
cxt := context.Background()
requestBody := gsclient.IPCreateRequest {
Family: 6,
Family: gsclient.IPv6Type,
Name: "IPTest",
}
client.CreateIP(requestBody)
client.CreateIP(ctx, requestBody)
```
What options are available for each create and update request can be found in the source code. After installing it should be located in:

@ -1,6 +1,17 @@
package gsclient
import (
"context"
"errors"
"fmt"
"github.com/sirupsen/logrus"
"net/http"
"path"
"time"
)
const (
requestBase = "/requests/"
apiServerBase = "/objects/servers"
apiStorageBase = "/objects/storages"
apiNetworkBase = "/objects/networks"
@ -30,3 +41,79 @@ func NewClient(c *Config) *Client {
}
return client
}
//Logger returns logger
func (c *Client) Logger() logrus.Logger {
return c.cfg.logger
}
//HttpClient returns http client
func (c *Client) HttpClient() *http.Client {
return c.cfg.httpClient
}
//Synchronous returns if the client is sync or not
func (c *Client) Synchronous() bool {
return c.cfg.sync
}
//RequestCheckTimeout returns request check timeout
func (c *Client) RequestCheckTimeout() time.Duration {
return c.cfg.requestCheckTimeoutSecs
}
//DelayInterval returns request delay interval
func (c *Client) DelayInterval() time.Duration {
return c.cfg.delayInterval
}
//MaxNumberOfRetries returns max number of retries
func (c *Client) MaxNumberOfRetries() int {
return c.cfg.maxNumberOfRetries
}
//APIURL returns api URL
func (c *Client) APIURL() string {
return c.cfg.apiURL
}
//UserAgent returns user agent
func (c *Client) UserAgent() string {
return c.cfg.userAgent
}
//UserUUID returns user UUID
func (c *Client) UserUUID() string {
return c.cfg.userUUID
}
//APIToken returns api token
func (c *Client) APIToken() string {
return c.cfg.apiToken
}
//waitForRequestCompleted allows to wait for a request to complete
func (c *Client) waitForRequestCompleted(ctx context.Context, id string) error {
if !isValidUUID(id) {
return errors.New("'id' is invalid")
}
return retryWithTimeout(func() (bool, error) {
r := request{
uri: path.Join(requestBase, id),
method: "GET",
skipCheckingRequest: true,
}
var response RequestStatus
err := r.execute(ctx, *c, &response)
if err != nil {
return false, err
}
if response[id].Status == requestDoneStatus {
return false, nil
} else if response[id].Status == requestFailStatus {
errMessage := fmt.Sprintf("request %s failed with error %s", id, response[id].Message)
return false, errors.New(errMessage)
}
return true, nil
}, c.RequestCheckTimeout(), c.DelayInterval())
}

@ -1,9 +1,56 @@
package gsclient
import "github.com/google/uuid"
import (
"errors"
"github.com/google/uuid"
"time"
)
type isContinue func() (bool, error)
//isValidUUID validates the uuid
func isValidUUID(u string) bool {
_, err := uuid.Parse(u)
return err == nil
}
//retryWithTimeout reruns a function within a period of time
func retryWithTimeout(targetFunc isContinue, timeout, delay time.Duration) error {
timer := time.After(timeout)
var err error
var continueRetrying bool
for {
select {
case <-timer:
if err != nil {
return err
}
return errors.New("timeout reached")
default:
time.Sleep(delay) //delay between retries
continueRetrying, err = targetFunc()
if !continueRetrying {
return err
}
}
}
}
//retryWithLimitedNumOfRetries reruns a function within a number of retries
func retryWithLimitedNumOfRetries(targetFunc isContinue, numOfRetries int, delay time.Duration) error {
retryNo := 0
var err error
var continueRetrying bool
for retryNo <= numOfRetries {
time.Sleep(delay) //delay between retries
continueRetrying, err = targetFunc()
if !continueRetrying {
return err
}
retryNo++
}
if err != nil {
return err
}
return errors.New("timeout reached")
}

@ -1,23 +1,53 @@
package gsclient
import (
"github.com/sirupsen/logrus"
"net/http"
"os"
"runtime"
"time"
)
"github.com/sirupsen/logrus"
const (
defaultCheckRequestTimeoutSecs = 120
defaultMaxNumberOfRetries = 5
defaultDelayIntervalMilliSecs = 500
version = "2.1.0"
defaultAPIURL = "https://api.gridscale.io"
resourceActiveStatus = "active"
requestDoneStatus = "done"
requestFailStatus = "failed"
bodyType = "application/json"
)
//Config config for client
type Config struct {
APIUrl string
UserUUID string
APIToken string
HTTPClient *http.Client
logger logrus.Logger
apiURL string
userUUID string
apiToken string
userAgent string
sync bool
httpClient *http.Client
requestCheckTimeoutSecs time.Duration
delayInterval time.Duration
maxNumberOfRetries int
logger logrus.Logger
}
//NewConfiguration creates a new config
func NewConfiguration(apiURL string, uuid string, token string, debugMode bool) *Config {
//
//- Parameters:
// + apiURL string: base URL of API.
// + uuid string: UUID of user.
// + token string: API token.
// + debugMode bool: true => run client in debug mode.
// + sync bool: true => client is in synchronous mode. The client will block until Create/Update/Delete processes
// are completely finished. It is safer to set this parameter to `true`.
// + requestCheckTimeoutSecs int: Timeout (in second) for checking requests (for synchronous feature)
// + delayIntervalMilliSecs int: delay (in MilliSecond) between requests when checking request (or retry 5xx, 424 error code)
// + maxNumberOfRetries int: number of retries when server returns 5xx, 424 error code.
func NewConfiguration(apiURL string, uuid string, token string, debugMode, sync bool, requestCheckTimeoutSecs,
delayIntervalMilliSecs, maxNumberOfRetries int) *Config {
logLevel := logrus.InfoLevel
if debugMode {
logLevel = logrus.DebugLevel
@ -33,11 +63,41 @@ func NewConfiguration(apiURL string, uuid string, token string, debugMode bool)
}
cfg := &Config{
APIUrl: apiURL,
UserUUID: uuid,
APIToken: token,
HTTPClient: http.DefaultClient,
logger: logger,
apiURL: apiURL,
userUUID: uuid,
apiToken: token,
userAgent: "gsclient-go/" + version + " (" + runtime.GOOS + ")",
sync: sync,
httpClient: http.DefaultClient,
logger: logger,
requestCheckTimeoutSecs: time.Duration(requestCheckTimeoutSecs) * time.Second,
delayInterval: time.Duration(delayIntervalMilliSecs) * time.Millisecond,
maxNumberOfRetries: maxNumberOfRetries,
}
return cfg
}
//DefaultConfiguration creates a default configuration
func DefaultConfiguration(uuid string, token string) *Config {
logger := logrus.Logger{
Out: os.Stderr,
Level: logrus.InfoLevel,
Formatter: &logrus.TextFormatter{
FullTimestamp: true,
DisableColors: false,
},
}
cfg := &Config{
apiURL: defaultAPIURL,
userUUID: uuid,
apiToken: token,
userAgent: "gsclient-go/" + version + " (" + runtime.GOOS + ")",
sync: true,
httpClient: http.DefaultClient,
logger: logger,
requestCheckTimeoutSecs: time.Duration(defaultCheckRequestTimeoutSecs) * time.Second,
delayInterval: time.Duration(defaultDelayIntervalMilliSecs) * time.Millisecond,
maxNumberOfRetries: defaultMaxNumberOfRetries,
}
return cfg
}

@ -1,39 +1,64 @@
package gsclient
import "net/http"
import (
"context"
"net/http"
)
//EventList is JSON struct of a list of events
type EventList struct {
//Array of events
List []EventProperties `json:"events"`
}
//Event is JSOn struct of a single firewall's event
type Event struct {
//Properties of an event
Properties EventProperties `json:"event"`
}
//EventProperties is JSON struct of an event properties
type EventProperties struct {
ObjectType string `json:"object_type"`
RequestUUID string `json:"request_uuid"`
ObjectUUID string `json:"object_uuid"`
Activity string `json:"activity"`
RequestType string `json:"request_type"`
//Type of object (server, storage, IP) etc
ObjectType string `json:"object_type"`
//The UUID of the event
RequestUUID string `json:"request_uuid"`
//The UUID of the objects the event was executed on
ObjectUUID string `json:"object_uuid"`
//The type of change
Activity string `json:"activity"`
//The type of request
RequestType string `json:"request_type"`
//True or false, whether the request was successful or not
RequestStatus string `json:"request_status"`
Change string `json:"change"`
Timestamp string `json:"timestamp"`
UserUUID string `json:"user_uuid"`
//A detailed description of the change.
Change string `json:"change"`
//Time the event was triggered
Timestamp GSTime `json:"timestamp"`
//The UUID of the user that triggered the event
UserUUID string `json:"user_uuid"`
}
//GetEventList gets a list of events
func (c *Client) GetEventList() ([]Event, error) {
r := Request{
uri: apiEventBase,
method: http.MethodGet,
//
//See: https://gridscale.io/en//api-documentation/index.html#operation/EventGetAll
func (c *Client) GetEventList(ctx context.Context) ([]Event, error) {
r := request{
uri: apiEventBase,
method: http.MethodGet,
skipCheckingRequest: true,
}
var response EventList
var events []Event
err := r.execute(*c, &response)
err := r.execute(ctx, *c, &response)
for _, properties := range response.List {
events = append(events, Event{Properties: properties})
}

@ -1,6 +1,7 @@
package gsclient
import (
"context"
"errors"
"net/http"
"path"
@ -8,92 +9,167 @@ import (
//FirewallList is JSON structure of a list of firewalls
type FirewallList struct {
//Array of firewalls
List map[string]FirewallProperties `json:"firewalls"`
}
//Firewall is JSON structure of a single firewall
type Firewall struct {
//Properties of a firewall
Properties FirewallProperties `json:"firewall"`
}
//FirewallProperties is JSON struct of a firewall's properties
type FirewallProperties struct {
Status string `json:"status"`
Labels []string `json:"labels"`
ObjectUUID string `json:"object_uuid"`
ChangeTime string `json:"change_time"`
Rules FirewallRules `json:"rules"`
CreateTime string `json:"create_time"`
Private bool `json:"private"`
Relations FirewallRelation `json:"relations"`
Description string `json:"description"`
LocationName string `json:"location_name"`
Name string `json:"name"`
//Status indicates the status of the object
Status string `json:"status"`
//List of labels
Labels []string `json:"labels"`
//The UUID of an object is always unique, and refers to a specific object
ObjectUUID string `json:"object_uuid"`
//Defines the date and time of the last object change
ChangeTime GSTime `json:"change_time"`
//FirewallRules
Rules FirewallRules `json:"rules"`
//Defines the date and time the object was initially created
CreateTime GSTime `json:"create_time"`
//If this is a private or public Firewall-Template
Private bool `json:"private"`
//The information about other object which are related to this Firewall. The object could be Network.
Relations FirewallRelation `json:"relations"`
//Description of the ISO-Image release
Description string `json:"description"`
//The human-readable name of the location. It supports the full UTF-8 charset, with a maximum of 64 characters.
LocationName string `json:"location_name"`
//The human-readable name of the object. It supports the full UTF-8 charset, with a maximum of 64 characters.
Name string `json:"name"`
}
//FirewallRules is JSON struct of a list of firewall's rules
type FirewallRules struct {
RulesV6In []FirewallRuleProperties `json:"rules-v6-in,omitempty"`
//Firewall template rules for inbound traffic - covers ipv6 addresses.
RulesV6In []FirewallRuleProperties `json:"rules-v6-in,omitempty"`
//Firewall template tules for outbound traffic - covers ipv6 addresses.
RulesV6Out []FirewallRuleProperties `json:"rules-v6-out,omitempty"`
RulesV4In []FirewallRuleProperties `json:"rules-v4-in,omitempty"`
//Firewall template rules for inbound traffic - covers ipv4 addresses.
RulesV4In []FirewallRuleProperties `json:"rules-v4-in,omitempty"`
//Firewall template tules for outbound traffic - covers ipv4 addresses.
RulesV4Out []FirewallRuleProperties `json:"rules-v4-out,omitempty"`
}
//FirewallRuleProperties is JSON struct of a firewall's rule properties
type FirewallRuleProperties struct {
//Enum:"udp" "tcp". Either udp or tcp
Protocol string `json:"protocol,omitempty"`
DstPort string `json:"dst_port,omitempty"`
SrcPort string `json:"src_port,omitempty"`
SrcCidr string `json:"src_cidr,omitempty"`
Action string `json:"action"`
Comment string `json:"comment,omitempty"`
DstCidr string `json:"dst_cidr,omitempty"`
Order int `json:"order"`
//A Number between 1 and 65535, port ranges are seperated by a colon for FTP.
DstPort string `json:"dst_port,omitempty"`
//A Number between 1 and 65535, port ranges are seperated by a colon for FTP.
SrcPort string `json:"src_port,omitempty"`
//A Number between 1 and 65535, port ranges are seperated by a colon for FTP.
SrcCidr string `json:"src_cidr,omitempty"`
//Enum:"accept" "drop". This defines what the firewall will do. Either accept or drop.
Action string `json:"action"`
//Description
Comment string `json:"comment,omitempty"`
//Either an IPv4/6 address or and IP Network in CIDR format. If this field is empty then all IPs have access to this service.
DstCidr string `json:"dst_cidr,omitempty"`
//The order at which the firewall will compare packets against its rules,
// a packet will be compared against the first rule, it will either allow it to pass
// or block it and it won t be matched against any other rules.
// However, if it does no match the rule, then it will proceed onto rule 2.
// Packets that do not match any rules are blocked by default.
Order int `json:"order"`
}
//FirewallRelation is a JSON struct of a list of firewall's relations
type FirewallRelation struct {
//Array of object (NetworkinFirewall)
Networks []NetworkInFirewall `json:"networks"`
}
//NetworkInFirewall is a JSON struct of a firewall's relation
type NetworkInFirewall struct {
CreateTime string `json:"create_time"`
//Defines the date and time the object was initially created.
CreateTime GSTime `json:"create_time"`
//The UUID of the network you're requesting.
NetworkUUID string `json:"network_uuid"`
//The human-readable name of the object. It supports the full UTF-8 charset, with a maximum of 64 characters.
NetworkName string `json:"network_name"`
ObjectUUID string `json:"object_uuid"`
ObjectName string `json:"object_name"`
//The UUID of an object is always unique, and refers to a specific object.
ObjectUUID string `json:"object_uuid"`
//The human-readable name of the object. It supports the full UTF-8 charset, with a maximum of 64 characters.
ObjectName string `json:"object_name"`
}
//FirewallCreateRequest is JSON struct of a request for creating a firewall
type FirewallCreateRequest struct {
Name string `json:"name"`
Labels []string `json:"labels,omitempty"`
Rules FirewallRules `json:"rules"`
//Name of firewall being created
Name string `json:"name"`
//Labels. Can be nil
Labels []string `json:"labels,omitempty"`
//FirewallRules
Rules FirewallRules `json:"rules"`
}
//FirewallCreateResponse is JSON struct of a response for creating a firewall
type FirewallCreateResponse struct {
//Request UUID
RequestUUID string `json:"request_uuid"`
ObjectUUID string `json:"object_uuid"`
//The UUID of the firewall being created
ObjectUUID string `json:"object_uuid"`
}
//FirewallUpdateRequest is JSON struct of a request for updating a firewall
type FirewallUpdateRequest struct {
Name string `json:"name,omitempty"`
Labels []string `json:"labels,omitempty"`
Rules FirewallRules `json:"rules,omitempty"`
//New name. Leave it if you do not want to update the name
Name string `json:"name,omitempty"`
//New list of labels. Leave it if you do not want to update the Labels
Labels []string `json:"labels,omitempty"`
//FirewallRules. Leave it if you do not want to update the firewall rules
Rules *FirewallRules `json:"rules,omitempty"`
}
//GetFirewallList gets a list of available firewalls
func (c *Client) GetFirewallList() ([]Firewall, error) {
r := Request{
uri: path.Join(apiFirewallBase),
method: http.MethodGet,
//
//See: https://gridscale.io/en//api-documentation/index.html#operation/getFirewalls
func (c *Client) GetFirewallList(ctx context.Context) ([]Firewall, error) {
r := request{
uri: path.Join(apiFirewallBase),
method: http.MethodGet,
skipCheckingRequest: true,
}
var response FirewallList
var firewalls []Firewall
err := r.execute(*c, &response)
err := r.execute(ctx, *c, &response)
for _, properties := range response.List {
firewalls = append(firewalls, Firewall{Properties: properties})
}
@ -101,72 +177,80 @@ func (c *Client) GetFirewallList() ([]Firewall, error) {
}
//GetFirewall gets a specific firewall based on given id
func (c *Client) GetFirewall(id string) (Firewall, error) {
//
//See: https://gridscale.io/en//api-documentation/index.html#operation/getFirewall
func (c *Client) GetFirewall(ctx context.Context, id string) (Firewall, error) {
if !isValidUUID(id) {
return Firewall{}, errors.New("'id' is invalid")
}
r := Request{
uri: path.Join(apiFirewallBase, id),
method: http.MethodGet,
r := request{
uri: path.Join(apiFirewallBase, id),
method: http.MethodGet,
skipCheckingRequest: true,
}
var response Firewall
err := r.execute(*c, &response)
err := r.execute(ctx, *c, &response)
return response, err
}
//CreateFirewall creates a new firewall
func (c *Client) CreateFirewall(body FirewallCreateRequest) (FirewallCreateResponse, error) {
r := Request{
//
//See: https://gridscale.io/en//api-documentation/index.html#operation/createFirewall
func (c *Client) CreateFirewall(ctx context.Context, body FirewallCreateRequest) (FirewallCreateResponse, error) {
r := request{
uri: path.Join(apiFirewallBase),
method: http.MethodPost,
body: body,
}
var response FirewallCreateResponse
err := r.execute(*c, &response)
if err != nil {
return FirewallCreateResponse{}, err
}
err = c.WaitForRequestCompletion(response.RequestUUID)
err := r.execute(ctx, *c, &response)
return response, err
}
//UpdateFirewall update a specific firewall
func (c *Client) UpdateFirewall(id string, body FirewallUpdateRequest) error {
//
//See: https://gridscale.io/en//api-documentation/index.html#operation/updateFirewall
func (c *Client) UpdateFirewall(ctx context.Context, id string, body FirewallUpdateRequest) error {
if !isValidUUID(id) {
return errors.New("'id' is invalid")
}
r := Request{
r := request{
uri: path.Join(apiFirewallBase, id),
method: http.MethodPatch,
body: body,
}
return r.execute(*c, nil)
return r.execute(ctx, *c, nil)
}
//DeleteFirewall delete a specific firewall
func (c *Client) DeleteFirewall(id string) error {
//
//See: https://gridscale.io/en//api-documentation/index.html#operation/deleteFirewall
func (c *Client) DeleteFirewall(ctx context.Context, id string) error {
if !isValidUUID(id) {
return errors.New("'id' is invalid")
}
r := Request{
r := request{
uri: path.Join(apiFirewallBase, id),
method: http.MethodDelete,
}
return r.execute(*c, nil)
return r.execute(ctx, *c, nil)
}
//GetFirewallEventList get list of a firewall's events
func (c *Client) GetFirewallEventList(id string) ([]Event, error) {
//
//See: https://gridscale.io/en//api-documentation/index.html#operation/getFirewallEvents
func (c *Client) GetFirewallEventList(ctx context.Context, id string) ([]Event, error) {
if !isValidUUID(id) {
return nil, errors.New("'id' is invalid")
}
r := Request{
uri: path.Join(apiFirewallBase, id, "events"),
method: http.MethodGet,
r := request{
uri: path.Join(apiFirewallBase, id, "events"),
method: http.MethodGet,
skipCheckingRequest: true,
}
var response EventList
var firewallEvents []Event
err := r.execute(*c, &response)
err := r.execute(ctx, *c, &response)
for _, properties := range response.List {
firewallEvents = append(firewallEvents, Event{Properties: properties})
}

@ -1,6 +1,7 @@
package gsclient
import (
"context"
"errors"
"net/http"
"path"
@ -8,116 +9,210 @@ import (
//IPList is JSON struct of a list of IPs
type IPList struct {
//Array of IP addresses
List map[string]IPProperties `json:"ips"`
}
//DeletedIPList is JSON struct of a list of deleted IPs
type DeletedIPList struct {
//Array of deleted IP addresses
List map[string]IPProperties `json:"deleted_ips"`
}
//IP is JSON struct if a single IP
type IP struct {
//Properties of an IP address
Properties IPProperties `json:"ip"`
}
//IPProperties is JSON struct of an IP's properties
type IPProperties struct {
Name string `json:"name"`
LocationCountry string `json:"location_country"`
LocationUUID string `json:"location_uuid"`
ObjectUUID string `json:"object_uuid"`
ReverseDNS string `json:"reverse_dns"`
Family int `json:"family"`
Status string `json:"status"`
CreateTime string `json:"create_time"`
Failover bool `json:"failover"`
ChangeTime string `json:"change_time"`
LocationIata string `json:"location_iata"`
LocationName string `json:"location_name"`
Prefix string `json:"prefix"`
IP string `json:"ip"`
DeleteBlock string `json:"delete_block"`
UsagesInMinutes float64 `json:"usage_in_minutes"`
CurrentPrice float64 `json:"current_price"`
Labels []string `json:"labels"`
Relations IPRelations `json:"relations"`
//The human-readable name of the object. It supports the full UTF-8 charset, with a maximum of 64 characters.
Name string `json:"name"`
//The human-readable name of the location. It supports the full UTF-8 charset, with a maximum of 64 characters.
LocationCountry string `json:"location_country"`
//Helps to identify which datacenter an object belongs to.
LocationUUID string `json:"location_uuid"`
//The UUID of an object is always unique, and refers to a specific object.
ObjectUUID string `json:"object_uuid"`
//Defines the reverse DNS entry for the IP Address (PTR Resource Record).
ReverseDNS string `json:"reverse_dns"`
//Enum:4 6. The IP Address family (v4 or v6)
Family int `json:"family"`
//Status indicates the status of the object.
Status string `json:"status"`
//Defines the date and time the object was initially created.
CreateTime GSTime `json:"create_time"`
//Sets failover mode for this IP. If true, then this IP is no longer available for DHCP and can no longer be related to any server.
Failover bool `json:"failover"`
//Defines the date and time of the last object change.
ChangeTime GSTime `json:"change_time"`
//Uses IATA airport code, which works as a location identifier.
LocationIata string `json:"location_iata"`
//The human-readable name of the location. It supports the full UTF-8 charset, with a maximum of 64 characters.
LocationName string `json:"location_name"`
//The IP prefix.
Prefix string `json:"prefix"`
//Defines the IP Address (v4 or v6).
IP string `json:"ip"`
//Defines if the object is administratively blocked. If true, it can not be deleted by the user.
DeleteBlock bool `json:"delete_block"`
//Total minutes the object has been running.
UsagesInMinutes float64 `json:"usage_in_minutes"`
//The price for the current period since the last bill.
CurrentPrice float64 `json:"current_price"`
//List of labels.
Labels []string `json:"labels"`
//The information about other object which are related to this IP. the object could be servers and/or loadbalancer.
Relations IPRelations `json:"relations"`
}
//IPRelations is JSON struct of a list of an IP's relations
type IPRelations struct {
Loadbalancers []IPLoadbalancer `json:"loadbalancers"`
Servers []IPServer `json:"servers"`
PublicIPs []ServerIPRelationProperties `json:"public_ips"`
Storages []ServerStorageRelationProperties `json:"storages"`
//Array of object (IPLoadbalancer)
Loadbalancers []IPLoadbalancer `json:"loadbalancers"`
//Array of object (IPServer)
Servers []IPServer `json:"servers"`
//Array of object (ServerIPRelationProperties)
PublicIPs []ServerIPRelationProperties `json:"public_ips"`
//Array of object (ServerStorageRelationProperties)
Storages []ServerStorageRelationProperties `json:"storages"`
}
//IPLoadbalancer is JSON struct of the relation between an IP and a Load Balancer
type IPLoadbalancer struct {
CreateTime string `json:"create_time"`
//Defines the date and time the object was initially created.
CreateTime GSTime `json:"create_time"`
//The human-readable name of the object. It supports the full UTF-8 charset, with a maximum of 64 characters.
LoadbalancerName string `json:"loadbalancer_name"`
//The UUID of loadbalancer.
LoadbalancerUUID string `json:"loadbalancer_uuid"`
}
//IPServer is JSON struct of the relation between an IP and a Server
type IPServer struct {
CreateTime string `json:"create_time"`
//Defines the date and time the object was initially created.
CreateTime GSTime `json:"create_time"`
//The human-readable name of the object. It supports the full UTF-8 charset, with a maximum of 64 characters.
ServerName string `json:"server_name"`
//The UUID of the server.
ServerUUID string `json:"server_uuid"`
}
//IPCreateResponse is JSON struct of a response for creating an IP
type IPCreateResponse struct {
//Request's UUID
RequestUUID string `json:"request_uuid"`
ObjectUUID string `json:"object_uuid"`
Prefix string `json:"prefix"`
IP string `json:"ip"`
//UUID of the IP address being created
ObjectUUID string `json:"object_uuid"`
//The IP prefix.
Prefix string `json:"prefix"`
//The IP Address (v4 or v6).
IP string `json:"ip"`
}
//IPCreateRequest is JSON struct of a request for creating an IP
type IPCreateRequest struct {
Name string `json:"name,omitempty"`
Family int `json:"family"`
LocationUUID string `json:"location_uuid"`
Failover bool `json:"failover,omitempty"`
ReverseDNS string `json:"reverse_dns,omitempty"`
Labels []string `json:"labels,omitempty"`
//Name of an IP address being created. Can be an empty string
Name string `json:"name,omitempty"`
//IP address family. Can only be either `IPv4Type` or `IPv6Type`
Family ipAddressType `json:"family"`
//Helps to identify which datacenter an object belongs to.
LocationUUID string `json:"location_uuid"`
//Sets failover mode for this IP. If true, then this IP is no longer available for DHCP and can no longer be related to any server.
Failover bool `json:"failover,omitempty"`
//Defines the reverse DNS entry for the IP Address (PTR Resource Record).
ReverseDNS string `json:"reverse_dns,omitempty"`
//List of labels.
Labels []string `json:"labels,omitempty"`
}
//IPUpdateRequest is JSON struct of a request for updating an IP
type IPUpdateRequest struct {
Name string `json:"name,omitempty"`
Failover bool `json:"failover"`
ReverseDNS string `json:"reverse_dns,omitempty"`
Labels []string `json:"labels,omitempty"`
//New name. Leave it if you do not want to update the name
Name string `json:"name,omitempty"`
//Sets failover mode for this IP. If true, then this IP is no longer available for DHCP and can no longer be related to any server.
Failover bool `json:"failover"`
//Defines the reverse DNS entry for the IP Address (PTR Resource Record). Leave it if you do not want to update the reverse DNS.
ReverseDNS string `json:"reverse_dns,omitempty"`
//List of labels. Leave it if you do not want to update the labels.
Labels []string `json:"labels,omitempty"`
}
//Allowed IP address versions
var (
IPv4Type = ipAddressType{4}
IPv6Type = ipAddressType{6}
)
//GetIP get a specific IP based on given id
func (c *Client) GetIP(id string) (IP, error) {
//
//See: https://gridscale.io/en//api-documentation/index.html#operation/getIp
func (c *Client) GetIP(ctx context.Context, id string) (IP, error) {
if !isValidUUID(id) {
return IP{}, errors.New("'id' is invalid")
}
r := Request{
uri: path.Join(apiIPBase, id),
method: http.MethodGet,
r := request{
uri: path.Join(apiIPBase, id),
method: http.MethodGet,
skipCheckingRequest: true,
}
var response IP
err := r.execute(*c, &response)
err := r.execute(ctx, *c, &response)
return response, err
}
//GetIPList gets a list of available IPs
func (c *Client) GetIPList() ([]IP, error) {
r := Request{
uri: apiIPBase,
method: http.MethodGet,
//
//https://gridscale.io/en//api-documentation/index.html#operation/getIps
func (c *Client) GetIPList(ctx context.Context) ([]IP, error) {
r := request{
uri: apiIPBase,
method: http.MethodGet,
skipCheckingRequest: true,
}
var response IPList
var IPs []IP
err := r.execute(*c, &response)
err := r.execute(ctx, *c, &response)
for _, properties := range response.List {
IPs = append(IPs, IP{Properties: properties})
}
@ -126,63 +221,66 @@ func (c *Client) GetIPList() ([]IP, error) {
}
//CreateIP creates an IP
func (c *Client) CreateIP(body IPCreateRequest) (IPCreateResponse, error) {
r := Request{
//
//Note: IP address family can only be either `IPv4Type` or `IPv6Type`
//
//See: https://gridscale.io/en//api-documentation/index.html#operation/createIp
func (c *Client) CreateIP(ctx context.Context, body IPCreateRequest) (IPCreateResponse, error) {
r := request{
uri: apiIPBase,
method: http.MethodPost,
body: body,
}
var response IPCreateResponse
err := r.execute(*c, &response)
if err != nil {
return IPCreateResponse{}, err
}
err = c.WaitForRequestCompletion(response.RequestUUID)
err := r.execute(ctx, *c, &response)
return response, err
}
//DeleteIP deletes a specific IP based on given id
func (c *Client) DeleteIP(id string) error {
//
//See: https://gridscale.io/en//api-documentation/index.html#operation/deleteIp
func (c *Client) DeleteIP(ctx context.Context, id string) error {
if !isValidUUID(id) {
return errors.New("'id' is invalid")
}
r := Request{
r := request{
uri: path.Join(apiIPBase, id),
method: http.MethodDelete,
}
return r.execute(*c, nil)
return r.execute(ctx, *c, nil)
}
//UpdateIP updates a specific IP based on given id
func (c *Client) UpdateIP(id string, body IPUpdateRequest) error {
//
//See: https://gridscale.io/en//api-documentation/index.html#operation/updateIp
func (c *Client) UpdateIP(ctx context.Context, id string, body IPUpdateRequest) error {
if !isValidUUID(id) {
return errors.New("'id' is invalid")
}
r := Request{
r := request{
uri: path.Join(apiIPBase, id),
method: http.MethodPatch,
body: body,
}
return r.execute(*c, nil)
return r.execute(ctx, *c, nil)
}
//GetIPEventList gets a list of an IP's events
func (c *Client) GetIPEventList(id string) ([]Event, error) {
//
//See: https://gridscale.io/en//api-documentation/index.html#operation/getIpEvents
func (c *Client) GetIPEventList(ctx context.Context, id string) ([]Event, error) {
if !isValidUUID(id) {
return nil, errors.New("'id' is invalid")
}
r := Request{
uri: path.Join(apiIPBase, id, "events"),
method: http.MethodGet,
r := request{
uri: path.Join(apiIPBase, id, "events"),
method: http.MethodGet,
skipCheckingRequest: true,
}
var response EventList
var IPEvents []Event
err := r.execute(*c, &response)
err := r.execute(ctx, *c, &response)
for _, properties := range response.List {
IPEvents = append(IPEvents, Event{Properties: properties})
}
@ -190,8 +288,8 @@ func (c *Client) GetIPEventList(id string) ([]Event, error) {
}
//GetIPVersion gets IP's version, returns 0 if an error was encountered
func (c *Client) GetIPVersion(id string) int {
ip, err := c.GetIP(id)
func (c *Client) GetIPVersion(ctx context.Context, id string) int {
ip, err := c.GetIP(ctx, id)
if err != nil {
return 0
}
@ -199,17 +297,20 @@ func (c *Client) GetIPVersion(id string) int {
}
//GetIPsByLocation gets a list of IPs by location
func (c *Client) GetIPsByLocation(id string) ([]IP, error) {
//
//See: https://gridscale.io/en//api-documentation/index.html#operation/getLocationIps
func (c *Client) GetIPsByLocation(ctx context.Context, id string) ([]IP, error) {
if !isValidUUID(id) {
return nil, errors.New("'id' is invalid")
}
r := Request{
uri: path.Join(apiLocationBase, id, "ips"),
method: http.MethodGet,
r := request{
uri: path.Join(apiLocationBase, id, "ips"),
method: http.MethodGet,
skipCheckingRequest: true,
}
var response IPList
var IPs []IP
err := r.execute(*c, &response)
err := r.execute(ctx, *c, &response)
for _, properties := range response.List {
IPs = append(IPs, IP{Properties: properties})
}
@ -217,14 +318,17 @@ func (c *Client) GetIPsByLocation(id string) ([]IP, error) {
}
//GetDeletedIPs gets a list of deleted IPs
func (c *Client) GetDeletedIPs() ([]IP, error) {
r := Request{
uri: path.Join(apiDeletedBase, "ips"),
method: http.MethodGet,
//
//See: https://gridscale.io/en//api-documentation/index.html#operation/getDeletedIps
func (c *Client) GetDeletedIPs(ctx context.Context) ([]IP, error) {
r := request{
uri: path.Join(apiDeletedBase, "ips"),
method: http.MethodGet,
skipCheckingRequest: true,
}
var response DeletedIPList
var IPs []IP
err := r.execute(*c, &response)
err := r.execute(ctx, *c, &response)
for _, properties := range response.List {
IPs = append(IPs, IP{Properties: properties})
}