Switch Vultr to official client (#929)

This commit is contained in:
David Dymko 2019-07-17 15:01:50 -04:00 committed by Ludovic Fernandez
parent 0dbc28193b
commit 87be19588b
47 changed files with 5471 additions and 3029 deletions

26
Gopkg.lock generated
View file

@ -55,14 +55,6 @@
revision = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005" revision = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005"
version = "v0.3.1" version = "v0.3.1"
[[projects]]
digest = "1:ed3fc9992df610d07c85c24e0b792268cc1ce226dd9bf8cb2e6ad9a377b35415"
name = "github.com/JamesClonk/vultr"
packages = ["lib"]
pruneopts = "NUT"
revision = "fa1c0367800db75e4d10d0ec90c49a8731670224"
version = "1.15.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:a4068a93355ba3cff0a719425713123d23c90010cb4d023b40c679a22465736d" digest = "1:a4068a93355ba3cff0a719425713123d23c90010cb4d023b40c679a22465736d"
@ -367,14 +359,6 @@
revision = "1624edc4454b8682399def8740d46db5e4362ba4" revision = "1624edc4454b8682399def8740d46db5e4362ba4"
version = "v1.1.5" version = "v1.1.5"
[[projects]]
digest = "1:8b3234b10eacd5edea45bf0c13a585b608749da23f94aaf29b46d9ef8a8babf4"
name = "github.com/juju/ratelimit"
packages = ["."]
pruneopts = "NUT"
revision = "59fac5042749a5afb9af70e813da1dd5474f0167"
version = "1.0.1"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:ec142582cd3bb5cc29a2bc7181a6e67367b90b19f6a957ce506dcd7d1500bf95" digest = "1:ec142582cd3bb5cc29a2bc7181a6e67367b90b19f6a957ce506dcd7d1500bf95"
@ -599,6 +583,14 @@
revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1" revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1"
version = "v1.20.0" version = "v1.20.0"
[[projects]]
digest = "1:b1d2c51a689eef501cb5726f8d9997c0ca4415cbfa7105fe6e64b1844eddf1fb"
name = "github.com/vultr/govultr"
packages = ["."]
pruneopts = "NUT"
revision = "ca447e056e08d93aa6e5b09e6ae3565dd1825281"
version = "v0.1.4"
[[projects]] [[projects]]
digest = "1:58f2854b50ff8862eb6a347f20dedaac83e1166f4040472e17bc37736841a12f" digest = "1:58f2854b50ff8862eb6a347f20dedaac83e1166f4040472e17bc37736841a12f"
name = "go.opencensus.io" name = "go.opencensus.io"
@ -885,7 +877,6 @@
"github.com/Azure/go-autorest/autorest/azure/auth", "github.com/Azure/go-autorest/autorest/azure/auth",
"github.com/Azure/go-autorest/autorest/to", "github.com/Azure/go-autorest/autorest/to",
"github.com/BurntSushi/toml", "github.com/BurntSushi/toml",
"github.com/JamesClonk/vultr/lib",
"github.com/OpenDNS/vegadns2client", "github.com/OpenDNS/vegadns2client",
"github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v1", "github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v1",
"github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid", "github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid",
@ -934,6 +925,7 @@
"github.com/transip/gotransip", "github.com/transip/gotransip",
"github.com/transip/gotransip/domain", "github.com/transip/gotransip/domain",
"github.com/urfave/cli", "github.com/urfave/cli",
"github.com/vultr/govultr",
"golang.org/x/crypto/ocsp", "golang.org/x/crypto/ocsp",
"golang.org/x/net/context", "golang.org/x/net/context",
"golang.org/x/net/idna", "golang.org/x/net/idna",

View file

@ -132,3 +132,7 @@
[[constraint]] [[constraint]]
name = "github.com/nrdcg/namesilo" name = "github.com/nrdcg/namesilo"
version = "0.2.0" version = "0.2.0"
[[constraint]]
name = "github.com/vultr/govultr"
version = "0.1.4"

View file

@ -53,7 +53,7 @@ More information [here](/lego/dns/#configuration-and-credentials).
## More information ## More information
- [API documentation](https://www.vultr.com/api/#dns) - [API documentation](https://www.vultr.com/api/#dns)
- [Go client](https://github.com/JamesClonk/vultr) - [Go client](https://github.com/vultr/govultr)
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. --> <!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/vultr/vultr.toml --> <!-- providers/dns/vultr/vultr.toml -->

View file

@ -1,18 +1,20 @@
// Package vultr implements a DNS provider for solving the DNS-01 challenge using the vultr DNS. // Package vultr implements a DNS provider for solving the DNS-01 challenge using the Vultr DNS.
// See https://www.vultr.com/api/#dns // See https://www.vultr.com/api/#dns
package vultr package vultr
import ( import (
"context"
"crypto/tls" "crypto/tls"
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"strconv"
"strings" "strings"
"time" "time"
vultr "github.com/JamesClonk/vultr/lib"
"github.com/go-acme/lego/challenge/dns01" "github.com/go-acme/lego/challenge/dns01"
"github.com/go-acme/lego/platform/config/env" "github.com/go-acme/lego/platform/config/env"
"github.com/vultr/govultr"
) )
// Config is used to configure the creation of the DNSProvider // Config is used to configure the creation of the DNSProvider
@ -43,7 +45,7 @@ func NewDefaultConfig() *Config {
// DNSProvider is an implementation of the acme.ChallengeProvider interface. // DNSProvider is an implementation of the acme.ChallengeProvider interface.
type DNSProvider struct { type DNSProvider struct {
config *Config config *Config
client *vultr.Client client *govultr.Client
} }
// NewDNSProvider returns a DNSProvider instance with a configured Vultr client. // NewDNSProvider returns a DNSProvider instance with a configured Vultr client.
@ -70,10 +72,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, fmt.Errorf("vultr: credentials missing") return nil, fmt.Errorf("vultr: credentials missing")
} }
options := &vultr.Options{ client := govultr.NewClient(config.HTTPClient, config.APIKey)
HTTPClient: config.HTTPClient,
}
client := vultr.NewClient(config.APIKey, options)
return &DNSProvider{client: client, config: config}, nil return &DNSProvider{client: client, config: config}, nil
} }
@ -89,7 +88,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
name := d.extractRecordName(fqdn, zoneDomain) name := d.extractRecordName(fqdn, zoneDomain)
err = d.client.CreateDNSRecord(zoneDomain, name, "TXT", `"`+value+`"`, 0, d.config.TTL) err = d.client.DNSRecord.Create(context.Background(), zoneDomain, name, "TXT", value, d.config.TTL, 0)
if err != nil { if err != nil {
return fmt.Errorf("vultr: API call failed: %v", err) return fmt.Errorf("vultr: API call failed: %v", err)
} }
@ -108,7 +107,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
var allErr []string var allErr []string
for _, rec := range records { for _, rec := range records {
err := d.client.DeleteDNSRecord(zoneDomain, rec.RecordID) err := d.client.DNSRecord.Delete(context.Background(), zoneDomain, strconv.Itoa(rec.RecordID))
if err != nil { if err != nil {
allErr = append(allErr, err.Error()) allErr = append(allErr, err.Error())
} }
@ -128,12 +127,12 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
} }
func (d *DNSProvider) getHostedZone(domain string) (string, error) { func (d *DNSProvider) getHostedZone(domain string) (string, error) {
domains, err := d.client.GetDNSDomains() domains, err := d.client.DNSDomain.List(context.Background())
if err != nil { if err != nil {
return "", fmt.Errorf("API call failed: %v", err) return "", fmt.Errorf("API call failed: %v", err)
} }
var hostedDomain vultr.DNSDomain var hostedDomain govultr.DNSDomain
for _, dom := range domains { for _, dom := range domains {
if strings.HasSuffix(domain, dom.Domain) { if strings.HasSuffix(domain, dom.Domain) {
if len(dom.Domain) > len(hostedDomain.Domain) { if len(dom.Domain) > len(hostedDomain.Domain) {
@ -148,14 +147,14 @@ func (d *DNSProvider) getHostedZone(domain string) (string, error) {
return hostedDomain.Domain, nil return hostedDomain.Domain, nil
} }
func (d *DNSProvider) findTxtRecords(domain, fqdn string) (string, []vultr.DNSRecord, error) { func (d *DNSProvider) findTxtRecords(domain, fqdn string) (string, []govultr.DNSRecord, error) {
zoneDomain, err := d.getHostedZone(domain) zoneDomain, err := d.getHostedZone(domain)
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
var records []vultr.DNSRecord var records []govultr.DNSRecord
result, err := d.client.GetDNSRecords(zoneDomain) result, err := d.client.DNSRecord.List(context.Background(), zoneDomain)
if err != nil { if err != nil {
return "", records, fmt.Errorf("API call has failed: %v", err) return "", records, fmt.Errorf("API call has failed: %v", err)
} }

View file

@ -17,4 +17,4 @@ Example = ''''''
[Links] [Links]
API = "https://www.vultr.com/api/#dns" API = "https://www.vultr.com/api/#dns"
GoClient = "https://github.com/JamesClonk/vultr" GoClient = "https://github.com/vultr/govultr"

View file

@ -1,71 +0,0 @@
package lib
import (
"encoding/json"
"fmt"
"strconv"
)
// AccountInfo of Vultr account
type AccountInfo struct {
Balance float64 `json:"balance"`
PendingCharges float64 `json:"pending_charges"`
LastPaymentDate string `json:"last_payment_date"`
LastPaymentAmount float64 `json:"last_payment_amount"`
}
// GetAccountInfo retrieves the Vultr account information about current balance, pending charges, etc..
func (c *Client) GetAccountInfo() (info AccountInfo, err error) {
if err := c.get(`account/info`, &info); err != nil {
return AccountInfo{}, err
}
return
}
// UnmarshalJSON implements json.Unmarshaller on AccountInfo.
// This is needed because the Vultr API is inconsistent in it's JSON responses for account info.
// Some fields can change type, from JSON number to JSON string and vice-versa.
func (a *AccountInfo) UnmarshalJSON(data []byte) (err error) {
if a == nil {
*a = AccountInfo{}
}
var fields map[string]interface{}
if err := json.Unmarshal(data, &fields); err != nil {
return err
}
value := fmt.Sprintf("%v", fields["balance"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
b, err := strconv.ParseFloat(value, 64)
if err != nil {
return err
}
a.Balance = b
value = fmt.Sprintf("%v", fields["pending_charges"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
pc, err := strconv.ParseFloat(value, 64)
if err != nil {
return err
}
a.PendingCharges = pc
value = fmt.Sprintf("%v", fields["last_payment_amount"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
lpa, err := strconv.ParseFloat(value, 64)
if err != nil {
return err
}
a.LastPaymentAmount = lpa
a.LastPaymentDate = fmt.Sprintf("%v", fields["last_payment_date"])
return
}

View file

@ -1,38 +0,0 @@
package lib
import (
"sort"
"strings"
)
// Application on Vultr
type Application struct {
ID string `json:"APPID"`
Name string `json:"name"`
ShortName string `json:"short_name"`
DeployName string `json:"deploy_name"`
Surcharge float64 `json:"surcharge"`
}
type applications []Application
func (s applications) Len() int { return len(s) }
func (s applications) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s applications) Less(i, j int) bool {
return strings.ToLower(s[i].Name) < strings.ToLower(s[j].Name)
}
// GetApplications returns a list of all available applications on Vultr
func (c *Client) GetApplications() ([]Application, error) {
var appMap map[string]Application
if err := c.get(`app/list`, &appMap); err != nil {
return nil, err
}
var appList []Application
for _, app := range appMap {
appList = append(appList, app)
}
sort.Sort(applications(appList))
return appList, nil
}

View file

@ -1,210 +0,0 @@
package lib
import (
"encoding/json"
"fmt"
"net/url"
"sort"
"strconv"
"strings"
)
// BlockStorage on Vultr account
type BlockStorage struct {
ID string `json:"SUBID,string"`
Name string `json:"label"`
RegionID int `json:"DCID,string"`
SizeGB int `json:"size_gb,string"`
Created string `json:"date_created"`
Cost string `json:"cost_per_month"`
Status string `json:"status"`
AttachedTo string `json:"attached_to_SUBID"`
}
type blockstorages []BlockStorage
func (b blockstorages) Len() int { return len(b) }
func (b blockstorages) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
func (b blockstorages) Less(i, j int) bool {
// sort order: name, size, status
if strings.ToLower(b[i].Name) < strings.ToLower(b[j].Name) {
return true
} else if strings.ToLower(b[i].Name) > strings.ToLower(b[j].Name) {
return false
}
if b[i].SizeGB < b[j].SizeGB {
return true
} else if b[i].SizeGB > b[j].SizeGB {
return false
}
return b[i].Status < b[j].Status
}
// UnmarshalJSON implements json.Unmarshaller on BlockStorage.
// This is needed because the Vultr API is inconsistent in it's JSON responses.
// Some fields can change type, from JSON number to JSON string and vice-versa.
func (b *BlockStorage) UnmarshalJSON(data []byte) (err error) {
if b == nil {
*b = BlockStorage{}
}
var fields map[string]interface{}
if err := json.Unmarshal(data, &fields); err != nil {
return err
}
value := fmt.Sprintf("%v", fields["SUBID"])
if len(value) == 0 || value == "<nil>" || value == "0" {
b.ID = ""
} else {
id, err := strconv.ParseFloat(value, 64)
if err != nil {
return err
}
b.ID = strconv.FormatFloat(id, 'f', -1, 64)
}
value = fmt.Sprintf("%v", fields["DCID"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
region, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
b.RegionID = int(region)
value = fmt.Sprintf("%v", fields["size_gb"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
size, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
b.SizeGB = int(size)
value = fmt.Sprintf("%v", fields["attached_to_SUBID"])
if len(value) == 0 || value == "<nil>" || value == "0" {
b.AttachedTo = ""
} else {
attached, err := strconv.ParseFloat(value, 64)
if err != nil {
return err
}
b.AttachedTo = strconv.FormatFloat(attached, 'f', -1, 64)
}
b.Name = fmt.Sprintf("%v", fields["label"])
b.Created = fmt.Sprintf("%v", fields["date_created"])
b.Status = fmt.Sprintf("%v", fields["status"])
b.Cost = fmt.Sprintf("%v", fields["cost_per_month"])
return
}
// GetBlockStorages returns a list of all active block storages on Vultr account
func (c *Client) GetBlockStorages() (storages []BlockStorage, err error) {
if err := c.get(`block/list`, &storages); err != nil {
return nil, err
}
sort.Sort(blockstorages(storages))
return storages, nil
}
// GetBlockStorage returns block storage with given ID
func (c *Client) GetBlockStorage(id string) (BlockStorage, error) {
storages, err := c.GetBlockStorages()
if err != nil {
return BlockStorage{}, err
}
for _, s := range storages {
if s.ID == id {
return s, nil
}
}
return BlockStorage{}, fmt.Errorf("BlockStorage with ID %v not found", id)
}
// CreateBlockStorage creates a new block storage on Vultr account
func (c *Client) CreateBlockStorage(name string, regionID, size int) (BlockStorage, error) {
values := url.Values{
"label": {name},
"DCID": {fmt.Sprintf("%v", regionID)},
"size_gb": {fmt.Sprintf("%v", size)},
}
var storage BlockStorage
if err := c.post(`block/create`, values, &storage); err != nil {
return BlockStorage{}, err
}
storage.RegionID = regionID
storage.Name = name
storage.SizeGB = size
return storage, nil
}
// ResizeBlockStorage resizes an existing block storage
func (c *Client) ResizeBlockStorage(id string, size int) error {
values := url.Values{
"SUBID": {id},
"size_gb": {fmt.Sprintf("%v", size)},
}
if err := c.post(`block/resize`, values, nil); err != nil {
return err
}
return nil
}
// LabelBlockStorage changes the label on an existing block storage
func (c *Client) LabelBlockStorage(id, name string) error {
values := url.Values{
"SUBID": {id},
"label": {name},
}
if err := c.post(`block/label_set`, values, nil); err != nil {
return err
}
return nil
}
// AttachBlockStorage attaches block storage to an existing virtual machine
func (c *Client) AttachBlockStorage(id, serverID string) error {
values := url.Values{
"SUBID": {id},
"attach_to_SUBID": {serverID},
}
if err := c.post(`block/attach`, values, nil); err != nil {
return err
}
return nil
}
// DetachBlockStorage detaches block storage from virtual machine
func (c *Client) DetachBlockStorage(id string) error {
values := url.Values{
"SUBID": {id},
}
if err := c.post(`block/detach`, values, nil); err != nil {
return err
}
return nil
}
// DeleteBlockStorage deletes an existing block storage
func (c *Client) DeleteBlockStorage(id string) error {
values := url.Values{
"SUBID": {id},
}
if err := c.post(`block/delete`, values, nil); err != nil {
return err
}
return nil
}

View file

@ -1,258 +0,0 @@
package lib
import (
"bytes"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"math/rand"
"net/http"
"net/url"
"strings"
"time"
"github.com/juju/ratelimit"
)
const (
// Version of this libary
Version = "1.15.0"
// APIVersion of Vultr
APIVersion = "v1"
// DefaultEndpoint to be used
DefaultEndpoint = "https://api.vultr.com/"
mediaType = "application/json"
)
// retryableStatusCodes are API response status codes that indicate that
// the failed request can be retried without further actions.
var retryableStatusCodes = map[int]struct{}{
503: {}, // Rate limit hit
500: {}, // Internal server error. Try again at a later time.
}
// Client represents the Vultr API client
type Client struct {
// HTTP client for communication with the Vultr API
client *http.Client
// User agent for HTTP client
UserAgent string
// Endpoint URL for API requests
Endpoint *url.URL
// API key for accessing the Vultr API
APIKey string
// Max. number of request attempts
MaxAttempts int
// Throttling struct
bucket *ratelimit.Bucket
// Optional function called after every successful request made to the API
onRequestCompleted RequestCompletionCallback
}
// RequestCompletionCallback defines the type of the request callback function
type RequestCompletionCallback func(*http.Request, *http.Response)
// Options represents optional settings and flags that can be passed to NewClient
type Options struct {
// HTTP client for communication with the Vultr API
HTTPClient *http.Client
// User agent for HTTP client
UserAgent string
// Endpoint URL for API requests
Endpoint string
// API rate limitation, calls per duration
RateLimitation time.Duration
// Max. number of times to retry API calls
MaxRetries int
}
// NewClient creates new Vultr API client. Options are optional and can be nil.
func NewClient(apiKey string, options *Options) *Client {
userAgent := "vultr-go/" + Version
transport := &http.Transport{
TLSNextProto: make(map[string]func(string, *tls.Conn) http.RoundTripper),
}
client := http.DefaultClient
client.Transport = transport
endpoint, _ := url.Parse(DefaultEndpoint)
rate := 505 * time.Millisecond
attempts := 1
if options != nil {
if options.HTTPClient != nil {
client = options.HTTPClient
}
if options.UserAgent != "" {
userAgent = options.UserAgent
}
if options.Endpoint != "" {
endpoint, _ = url.Parse(options.Endpoint)
}
if options.RateLimitation != 0 {
rate = options.RateLimitation
}
if options.MaxRetries != 0 {
attempts = options.MaxRetries + 1
}
}
return &Client{
UserAgent: userAgent,
client: client,
Endpoint: endpoint,
APIKey: apiKey,
MaxAttempts: attempts,
bucket: ratelimit.NewBucket(rate, 1),
}
}
func apiPath(path string) string {
return fmt.Sprintf("/%s/%s", APIVersion, path)
}
func (c *Client) get(path string, data interface{}) error {
req, err := c.newRequest("GET", apiPath(path), nil)
if err != nil {
return err
}
return c.do(req, data)
}
func (c *Client) post(path string, values url.Values, data interface{}) error {
req, err := c.newRequest("POST", apiPath(path), strings.NewReader(values.Encode()))
if err != nil {
return err
}
return c.do(req, data)
}
// OnRequestCompleted sets the API request completion callback
func (c *Client) OnRequestCompleted(rc RequestCompletionCallback) {
c.onRequestCompleted = rc
}
func (c *Client) newRequest(method string, path string, body io.Reader) (*http.Request, error) {
relPath, err := url.Parse(path)
if err != nil {
return nil, err
}
url := c.Endpoint.ResolveReference(relPath)
req, err := http.NewRequest(method, url.String(), body)
if err != nil {
return nil, err
}
req.Header.Add("API-Key", c.APIKey)
req.Header.Add("User-Agent", c.UserAgent)
req.Header.Add("Accept", mediaType)
if req.Method == "POST" {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
return req, nil
}
func (c *Client) do(req *http.Request, data interface{}) error {
// Throttle http requests to avoid hitting Vultr's API rate-limit
c.bucket.Wait(1)
// Request body gets drained on each read so we
// need to save it's content for retrying requests
var err error
var requestBody []byte
if req.Body != nil {
requestBody, err = ioutil.ReadAll(req.Body)
if err != nil {
return fmt.Errorf("Error reading request body: %v", err)
}
req.Body.Close()
}
var apiError error
for tryCount := 1; tryCount <= c.MaxAttempts; tryCount++ {
// Restore request body to the original state
if requestBody != nil {
req.Body = ioutil.NopCloser(bytes.NewBuffer(requestBody))
}
resp, err := c.client.Do(req)
if err != nil {
return err
}
if c.onRequestCompleted != nil {
c.onRequestCompleted(req, resp)
}
body, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
return err
}
if resp.StatusCode == http.StatusOK {
if data != nil {
// avoid unmarshalling problem because Vultr API returns
// empty array instead of empty map when it shouldn't!
if string(body) == `[]` {
data = nil
} else {
if err := json.Unmarshal(body, data); err != nil {
return err
}
}
}
return nil
}
apiError = errors.New(string(body))
if !isCodeRetryable(resp.StatusCode) {
break
}
delay := backoffDuration(tryCount)
time.Sleep(delay)
}
return apiError
}
// backoffDuration returns the duration to wait before retrying the request.
// Duration is an exponential function of the retry count with a jitter of ~0-30%.
func backoffDuration(retryCount int) time.Duration {
// Upper limit of delay at ~1 minute
if retryCount > 7 {
retryCount = 7
}
rand.Seed(time.Now().UnixNano())
delay := (1 << uint(retryCount)) * (rand.Intn(150) + 500)
return time.Duration(delay) * time.Millisecond
}
// isCodeRetryable returns true if the given status code means that we should retry.
func isCodeRetryable(statusCode int) bool {
if _, ok := retryableStatusCodes[statusCode]; ok {
return true
}
return false
}

View file

@ -1,150 +0,0 @@
package lib
import (
"fmt"
"net/url"
"sort"
"strings"
)
// DNSDomain represents a DNS domain on Vultr
type DNSDomain struct {
Domain string `json:"domain"`
Created string `json:"date_created"`
}
type dnsdomains []DNSDomain
func (d dnsdomains) Len() int { return len(d) }
func (d dnsdomains) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
func (d dnsdomains) Less(i, j int) bool {
return strings.ToLower(d[i].Domain) < strings.ToLower(d[j].Domain)
}
// DNSRecord represents a DNS record on Vultr
type DNSRecord struct {
RecordID int `json:"RECORDID"`
Type string `json:"type"`
Name string `json:"name"`
Data string `json:"data"`
Priority int `json:"priority"`
TTL int `json:"ttl"`
}
type dnsrecords []DNSRecord
func (d dnsrecords) Len() int { return len(d) }
func (d dnsrecords) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
func (d dnsrecords) Less(i, j int) bool {
// sort order: type, data, name
if d[i].Type < d[j].Type {
return true
} else if d[i].Type > d[j].Type {
return false
}
if d[i].Data < d[j].Data {
return true
} else if d[i].Data > d[j].Data {
return false
}
return strings.ToLower(d[i].Name) < strings.ToLower(d[j].Name)
}
// GetDNSDomains returns a list of available domains on Vultr account
func (c *Client) GetDNSDomains() (domains []DNSDomain, err error) {
if err := c.get(`dns/list`, &domains); err != nil {
return nil, err
}
sort.Sort(dnsdomains(domains))
return domains, nil
}
// GetDNSRecords returns a list of all DNS records of a particular domain
func (c *Client) GetDNSRecords(domain string) (records []DNSRecord, err error) {
if err := c.get(`dns/records?domain=`+domain, &records); err != nil {
return nil, err
}
sort.Sort(dnsrecords(records))
return records, nil
}
// CreateDNSDomain creates a new DNS domain name on Vultr
func (c *Client) CreateDNSDomain(domain, serverIP string) error {
values := url.Values{
"domain": {domain},
"serverip": {serverIP},
}
if err := c.post(`dns/create_domain`, values, nil); err != nil {
return err
}
return nil
}
// DeleteDNSDomain deletes an existing DNS domain name
func (c *Client) DeleteDNSDomain(domain string) error {
values := url.Values{
"domain": {domain},
}
if err := c.post(`dns/delete_domain`, values, nil); err != nil {
return err
}
return nil
}
// CreateDNSRecord creates a new DNS record
func (c *Client) CreateDNSRecord(domain, name, rtype, data string, priority, ttl int) error {
values := url.Values{
"domain": {domain},
"name": {name},
"type": {rtype},
"data": {data},
"priority": {fmt.Sprintf("%v", priority)},
"ttl": {fmt.Sprintf("%v", ttl)},
}
if err := c.post(`dns/create_record`, values, nil); err != nil {
return err
}
return nil
}
// UpdateDNSRecord updates an existing DNS record
func (c *Client) UpdateDNSRecord(domain string, dnsrecord DNSRecord) error {
values := url.Values{
"domain": {domain},
"RECORDID": {fmt.Sprintf("%v", dnsrecord.RecordID)},
}
if dnsrecord.Name != "" {
values.Add("name", dnsrecord.Name)
}
if dnsrecord.Data != "" {
values.Add("data", dnsrecord.Data)
}
if dnsrecord.Priority != 0 {
values.Add("priority", fmt.Sprintf("%v", dnsrecord.Priority))
}
if dnsrecord.TTL != 0 {
values.Add("ttl", fmt.Sprintf("%v", dnsrecord.TTL))
}
if err := c.post(`dns/update_record`, values, nil); err != nil {
return err
}
return nil
}
// DeleteDNSRecord deletes an existing DNS record
func (c *Client) DeleteDNSRecord(domain string, recordID int) error {
values := url.Values{
"domain": {domain},
"RECORDID": {fmt.Sprintf("%v", recordID)},
}
if err := c.post(`dns/delete_record`, values, nil); err != nil {
return err
}
return nil
}

View file

@ -1,252 +0,0 @@
package lib
import (
"encoding/json"
"fmt"
"net"
"net/url"
"sort"
"strconv"
"strings"
)
// FirewallGroup represents a firewall group on Vultr
type FirewallGroup struct {
ID string `json:"FIREWALLGROUPID"`
Description string `json:"description"`
Created string `json:"date_created"`
Modified string `json:"date_modified"`
InstanceCount int `json:"instance_count"`
RuleCount int `json:"rule_count"`
MaxRuleCount int `json:"max_rule_count"`
}
// FirewallRule represents a firewall rule on Vultr
type FirewallRule struct {
RuleNumber int `json:"rulenumber"`
Action string `json:"action"`
Protocol string `json:"protocol"`
Port string `json:"port"`
Network *net.IPNet
}
type firewallGroups []FirewallGroup
func (f firewallGroups) Len() int { return len(f) }
func (f firewallGroups) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
func (f firewallGroups) Less(i, j int) bool {
// sort order: description
return strings.ToLower(f[i].Description) < strings.ToLower(f[j].Description)
}
type firewallRules []FirewallRule
func (r firewallRules) Len() int { return len(r) }
func (r firewallRules) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
func (r firewallRules) Less(i, j int) bool {
// sort order: rule number
return r[i].RuleNumber < r[j].RuleNumber
}
// UnmarshalJSON implements json.Unmarshaller on FirewallRule.
// This is needed because the Vultr API is inconsistent in it's JSON responses.
// Some fields can change type, from JSON number to JSON string and vice-versa.
func (r *FirewallRule) UnmarshalJSON(data []byte) (err error) {
if r == nil {
*r = FirewallRule{}
}
var fields map[string]interface{}
if err := json.Unmarshal(data, &fields); err != nil {
return err
}
value := fmt.Sprintf("%v", fields["rulenumber"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
number, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
r.RuleNumber = int(number)
value = fmt.Sprintf("%v", fields["subnet_size"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
subnetSize, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
r.Action = fmt.Sprintf("%v", fields["action"])
r.Protocol = fmt.Sprintf("%v", fields["protocol"])
r.Port = fmt.Sprintf("%v", fields["port"])
subnet := fmt.Sprintf("%v", fields["subnet"])
if subnet == "<nil>" {
subnet = ""
}
if len(subnet) > 0 {
_, r.Network, err = net.ParseCIDR(fmt.Sprintf("%s/%d", subnet, subnetSize))
if err != nil {
return fmt.Errorf("Failed to parse subnet from Vultr API")
}
} else {
// This case is used to create a valid default CIDR when the Vultr API does not return a subnet/subnet size at all, e.g. the response after creating a new rule.
_, r.Network, _ = net.ParseCIDR("0.0.0.0/0")
}
return
}
// GetFirewallGroups returns a list of all available firewall groups on Vultr
func (c *Client) GetFirewallGroups() ([]FirewallGroup, error) {
var groupMap map[string]FirewallGroup
if err := c.get(`firewall/group_list`, &groupMap); err != nil {
return nil, err
}
var groupList []FirewallGroup
for _, g := range groupMap {
groupList = append(groupList, g)
}
sort.Sort(firewallGroups(groupList))
return groupList, nil
}
// GetFirewallGroup returns the firewall group with given ID
func (c *Client) GetFirewallGroup(id string) (FirewallGroup, error) {
groups, err := c.GetFirewallGroups()
if err != nil {
return FirewallGroup{}, err
}
for _, g := range groups {
if g.ID == id {
return g, nil
}
}
return FirewallGroup{}, fmt.Errorf("Firewall group with ID %v not found", id)
}
// CreateFirewallGroup creates a new firewall group in Vultr account
func (c *Client) CreateFirewallGroup(description string) (string, error) {
values := url.Values{}
// Optional description
if len(description) > 0 {
values.Add("description", description)
}
var result FirewallGroup
err := c.post(`firewall/group_create`, values, &result)
if err != nil {
return "", err
}
return result.ID, nil
}
// DeleteFirewallGroup deletes an existing firewall group
func (c *Client) DeleteFirewallGroup(groupID string) error {
values := url.Values{
"FIREWALLGROUPID": {groupID},
}
if err := c.post(`firewall/group_delete`, values, nil); err != nil {
return err
}
return nil
}
// SetFirewallGroupDescription sets the description of an existing firewall group
func (c *Client) SetFirewallGroupDescription(groupID, description string) error {
values := url.Values{
"FIREWALLGROUPID": {groupID},
"description": {description},
}
if err := c.post(`firewall/group_set_description`, values, nil); err != nil {
return err
}
return nil
}
// GetFirewallRules returns a list of rules for the given firewall group
func (c *Client) GetFirewallRules(groupID string) ([]FirewallRule, error) {
var ruleMap map[string]FirewallRule
ipTypes := []string{"v4", "v6"}
for _, ipType := range ipTypes {
args := fmt.Sprintf("direction=in&FIREWALLGROUPID=%s&ip_type=%s",
groupID, ipType)
if err := c.get(`firewall/rule_list?`+args, &ruleMap); err != nil {
return nil, err
}
}
var ruleList []FirewallRule
for _, r := range ruleMap {
ruleList = append(ruleList, r)
}
sort.Sort(firewallRules(ruleList))
return ruleList, nil
}
// CreateFirewallRule creates a new firewall rule in Vultr account.
// groupID is the ID of the firewall group to create the rule in
// protocol must be one of: "icmp", "tcp", "udp", "gre"
// port can be a port number or colon separated port range (TCP/UDP only)
func (c *Client) CreateFirewallRule(groupID, protocol, port string,
network *net.IPNet) (int, error) {
ip := network.IP.String()
maskBits, _ := network.Mask.Size()
if ip == "<nil>" {
return 0, fmt.Errorf("Invalid network")
}
var ipType string
if network.IP.To4() != nil {
ipType = "v4"
} else {
ipType = "v6"
}
values := url.Values{
"FIREWALLGROUPID": {groupID},
// possible values: "in"
"direction": {"in"},
// possible values: "icmp", "tcp", "udp", "gre"
"protocol": {protocol},
// possible values: "v4", "v6"
"ip_type": {ipType},
// IP address representing a subnet
"subnet": {ip},
// IP prefix size in bits
"subnet_size": {fmt.Sprintf("%v", maskBits)},
}
if len(port) > 0 {
values.Add("port", port)
}
var result FirewallRule
err := c.post(`firewall/rule_create`, values, &result)
if err != nil {
return 0, err
}
return result.RuleNumber, nil
}
// DeleteFirewallRule deletes an existing firewall rule
func (c *Client) DeleteFirewallRule(ruleNumber int, groupID string) error {
values := url.Values{
"FIREWALLGROUPID": {groupID},
"rulenumber": {fmt.Sprintf("%v", ruleNumber)},
}
if err := c.post(`firewall/rule_delete`, values, nil); err != nil {
return err
}
return nil
}

View file

@ -1,192 +0,0 @@
package lib
import (
"fmt"
"net/url"
"sort"
)
// IPv4 information of a virtual machine
type IPv4 struct {
IP string `json:"ip"`
Netmask string `json:"netmask"`
Gateway string `json:"gateway"`
Type string `json:"type"`
ReverseDNS string `json:"reverse"`
}
type ipv4s []IPv4
func (s ipv4s) Len() int { return len(s) }
func (s ipv4s) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ipv4s) Less(i, j int) bool {
// sort order: type, ip
if s[i].Type < s[j].Type {
return true
} else if s[i].Type > s[j].Type {
return false
}
return s[i].IP < s[j].IP
}
// IPv6 information of a virtual machine
type IPv6 struct {
IP string `json:"ip"`
Network string `json:"network"`
NetworkSize string `json:"network_size"`
Type string `json:"type"`
}
type ipv6s []IPv6
func (s ipv6s) Len() int { return len(s) }
func (s ipv6s) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ipv6s) Less(i, j int) bool {
// sort order: type, ip
if s[i].Type < s[j].Type {
return true
} else if s[i].Type > s[j].Type {
return false
}
return s[i].IP < s[j].IP
}
// ReverseDNSIPv6 information of a virtual machine
type ReverseDNSIPv6 struct {
IP string `json:"ip"`
ReverseDNS string `json:"reverse"`
}
type reverseDNSIPv6s []ReverseDNSIPv6
func (s reverseDNSIPv6s) Len() int { return len(s) }
func (s reverseDNSIPv6s) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s reverseDNSIPv6s) Less(i, j int) bool { return s[i].IP < s[j].IP }
// ListIPv4 lists the IPv4 information of a virtual machine
func (c *Client) ListIPv4(id string) (list []IPv4, err error) {
var ipMap map[string][]IPv4
if err := c.get(`server/list_ipv4?SUBID=`+id, &ipMap); err != nil {
return nil, err
}
for _, iplist := range ipMap {
for _, ip := range iplist {
list = append(list, ip)
}
}
sort.Sort(ipv4s(list))
return list, nil
}
// CreateIPv4 creates an IPv4 address and attaches it to a virtual machine
func (c *Client) CreateIPv4(id string, reboot bool) error {
values := url.Values{
"SUBID": {id},
"reboot": {fmt.Sprintf("%t", reboot)},
}
if err := c.post(`server/create_ipv4`, values, nil); err != nil {
return err
}
return nil
}
// DeleteIPv4 deletes an IPv4 address and detaches it from a virtual machine
func (c *Client) DeleteIPv4(id, ip string) error {
values := url.Values{
"SUBID": {id},
"ip": {ip},
}
if err := c.post(`server/destroy_ipv4`, values, nil); err != nil {
return err
}
return nil
}
// ListIPv6 lists the IPv4 information of a virtual machine
func (c *Client) ListIPv6(id string) (list []IPv6, err error) {
var ipMap map[string][]IPv6
if err := c.get(`server/list_ipv6?SUBID=`+id, &ipMap); err != nil {
return nil, err
}
for _, iplist := range ipMap {
for _, ip := range iplist {
list = append(list, ip)
}
}
sort.Sort(ipv6s(list))
return list, nil
}
// ListIPv6ReverseDNS lists the IPv6 reverse DNS entries of a virtual machine
func (c *Client) ListIPv6ReverseDNS(id string) (list []ReverseDNSIPv6, err error) {
var ipMap map[string][]ReverseDNSIPv6
if err := c.get(`server/reverse_list_ipv6?SUBID=`+id, &ipMap); err != nil {
return nil, err
}
for _, iplist := range ipMap {
for _, ip := range iplist {
list = append(list, ip)
}
}
sort.Sort(reverseDNSIPv6s(list))
return list, nil
}
// DeleteIPv6ReverseDNS removes a reverse DNS entry for an IPv6 address of a virtual machine
func (c *Client) DeleteIPv6ReverseDNS(id string, ip string) error {
values := url.Values{
"SUBID": {id},
"ip": {ip},
}
if err := c.post(`server/reverse_delete_ipv6`, values, nil); err != nil {
return err
}
return nil
}
// SetIPv6ReverseDNS sets a reverse DNS entry for an IPv6 address of a virtual machine
func (c *Client) SetIPv6ReverseDNS(id, ip, entry string) error {
values := url.Values{
"SUBID": {id},
"ip": {ip},
"entry": {entry},
}
if err := c.post(`server/reverse_set_ipv6`, values, nil); err != nil {
return err
}
return nil
}
// DefaultIPv4ReverseDNS sets a reverse DNS entry for an IPv4 address of a virtual machine to the original setting
func (c *Client) DefaultIPv4ReverseDNS(id, ip string) error {
values := url.Values{
"SUBID": {id},
"ip": {ip},
}
if err := c.post(`server/reverse_default_ipv4`, values, nil); err != nil {
return err
}
return nil
}
// SetIPv4ReverseDNS sets a reverse DNS entry for an IPv4 address of a virtual machine
func (c *Client) SetIPv4ReverseDNS(id, ip, entry string) error {
values := url.Values{
"SUBID": {id},
"ip": {ip},
"entry": {entry},
}
if err := c.post(`server/reverse_set_ipv4`, values, nil); err != nil {
return err
}
return nil
}

View file

@ -1,44 +0,0 @@
package lib
import (
"sort"
"strings"
)
// ISO image on Vultr
type ISO struct {
ID int `json:"ISOID"`
Created string `json:"date_created"`
Filename string `json:"filename"`
Size int `json:"size"`
MD5sum string `json:"md5sum"`
}
type isos []ISO
func (s isos) Len() int { return len(s) }
func (s isos) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s isos) Less(i, j int) bool {
// sort order: filename, created
if strings.ToLower(s[i].Filename) < strings.ToLower(s[j].Filename) {
return true
} else if strings.ToLower(s[i].Filename) > strings.ToLower(s[j].Filename) {
return false
}
return s[i].Created < s[j].Created
}
// GetISO returns a list of all ISO images on Vultr account
func (c *Client) GetISO() ([]ISO, error) {
var isoMap map[string]ISO
if err := c.get(`iso/list`, &isoMap); err != nil {
return nil, err
}
var isoList []ISO
for _, iso := range isoMap {
isoList = append(isoList, iso)
}
sort.Sort(isos(isoList))
return isoList, nil
}

View file

@ -1,37 +0,0 @@
package lib
import (
"sort"
"strings"
)
// OS image on Vultr
type OS struct {
ID int `json:"OSID"`
Name string `json:"name"`
Arch string `json:"arch"`
Family string `json:"family"`
Windows bool `json:"windows"`
Surcharge string `json:"surcharge"`
}
type oses []OS
func (s oses) Len() int { return len(s) }
func (s oses) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s oses) Less(i, j int) bool { return strings.ToLower(s[i].Name) < strings.ToLower(s[j].Name) }
// GetOS returns a list of all available operating systems on Vultr
func (c *Client) GetOS() ([]OS, error) {
var osMap map[string]OS
if err := c.get(`os/list`, &osMap); err != nil {
return nil, err
}
var osList []OS
for _, os := range osMap {
osList = append(osList, os)
}
sort.Sort(oses(osList))
return osList, nil
}

View file

@ -1,78 +0,0 @@
package lib
import (
"fmt"
"sort"
"strconv"
"strings"
)
// Plan on Vultr
type Plan struct {
ID int `json:"VPSPLANID,string"`
Name string `json:"name"`
VCpus int `json:"vcpu_count,string"`
RAM string `json:"ram"`
Disk string `json:"disk"`
Bandwidth string `json:"bandwidth"`
Price string `json:"price_per_month"`
Regions []int `json:"available_locations"`
}
type plans []Plan
func (p plans) Len() int { return len(p) }
func (p plans) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p plans) Less(i, j int) bool {
pa, _ := strconv.ParseFloat(strings.TrimSpace(p[i].Price), 64)
pb, _ := strconv.ParseFloat(strings.TrimSpace(p[j].Price), 64)
ra, _ := strconv.ParseInt(strings.TrimSpace(p[i].RAM), 10, 64)
rb, _ := strconv.ParseInt(strings.TrimSpace(p[j].RAM), 10, 64)
da, _ := strconv.ParseInt(strings.TrimSpace(p[i].Disk), 10, 64)
db, _ := strconv.ParseInt(strings.TrimSpace(p[j].Disk), 10, 64)
// sort order: price, vcpu, ram, disk
if pa < pb {
return true
} else if pa > pb {
return false
}
if p[i].VCpus < p[j].VCpus {
return true
} else if p[i].VCpus > p[j].VCpus {
return false
}
if ra < rb {
return true
} else if ra > rb {
return false
}
return da < db
}
// GetPlans returns a list of all available plans on Vultr account
func (c *Client) GetPlans() ([]Plan, error) {
var planMap map[string]Plan
if err := c.get(`plans/list`, &planMap); err != nil {
return nil, err
}
var p plans
for _, plan := range planMap {
p = append(p, plan)
}
sort.Sort(plans(p))
return p, nil
}
// GetAvailablePlansForRegion returns available plans for specified region
func (c *Client) GetAvailablePlansForRegion(id int) (planIDs []int, err error) {
if err := c.get(fmt.Sprintf(`regions/availability?DCID=%v`, id), &planIDs); err != nil {
return nil, err
}
return
}

View file

@ -1,44 +0,0 @@
package lib
import "sort"
// Region on Vultr
type Region struct {
ID int `json:"DCID,string"`
Name string `json:"name"`
Country string `json:"country"`
Continent string `json:"continent"`
State string `json:"state"`
Ddos bool `json:"ddos_protection"`
BlockStorage bool `json:"block_storage"`
Code string `json:"regioncode"`
}
type regions []Region
func (s regions) Len() int { return len(s) }
func (s regions) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s regions) Less(i, j int) bool {
// sort order: continent, name
if s[i].Continent < s[j].Continent {
return true
} else if s[i].Continent > s[j].Continent {
return false
}
return s[i].Name < s[j].Name
}
// GetRegions returns a list of all available Vultr regions
func (c *Client) GetRegions() ([]Region, error) {
var regionMap map[string]Region
if err := c.get(`regions/list`, &regionMap); err != nil {
return nil, err
}
var regionList []Region
for _, os := range regionMap {
regionList = append(regionList, os)
}
sort.Sort(regions(regionList))
return regionList, nil
}

View file

@ -1,192 +0,0 @@
package lib
import (
"encoding/json"
"fmt"
"net/url"
"sort"
"strconv"
"strings"
)
// IP on Vultr
type IP struct {
ID string `json:"SUBID,string"`
RegionID int `json:"DCID,string"`
IPType string `json:"ip_type"`
Subnet string `json:"subnet"`
SubnetSize int `json:"subnet_size"`
Label string `json:"label"`
AttachedTo string `json:"attached_SUBID,string"`
}
type ips []IP
func (s ips) Len() int { return len(s) }
func (s ips) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ips) Less(i, j int) bool {
// sort order: label, iptype, subnet
if strings.ToLower(s[i].Label) < strings.ToLower(s[j].Label) {
return true
} else if strings.ToLower(s[i].Label) > strings.ToLower(s[j].Label) {
return false
}
if s[i].IPType < s[j].IPType {
return true
} else if s[i].IPType > s[j].IPType {
return false
}
return s[i].Subnet < s[j].Subnet
}
// UnmarshalJSON implements json.Unmarshaller on IP.
// This is needed because the Vultr API is inconsistent in it's JSON responses.
// Some fields can change type, from JSON number to JSON string and vice-versa.
func (i *IP) UnmarshalJSON(data []byte) (err error) {
if i == nil {
*i = IP{}
}
var fields map[string]interface{}
if err := json.Unmarshal(data, &fields); err != nil {
return err
}
value := fmt.Sprintf("%v", fields["SUBID"])
if len(value) == 0 || value == "<nil>" || value == "0" {
i.ID = ""
} else {
id, err := strconv.ParseFloat(value, 64)
if err != nil {
return err
}
i.ID = strconv.FormatFloat(id, 'f', -1, 64)
}
value = fmt.Sprintf("%v", fields["DCID"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
region, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
i.RegionID = int(region)
value = fmt.Sprintf("%v", fields["attached_SUBID"])
if len(value) == 0 || value == "<nil>" || value == "0" || value == "false" {
i.AttachedTo = ""
} else {
attached, err := strconv.ParseFloat(value, 64)
if err != nil {
return err
}
i.AttachedTo = strconv.FormatFloat(attached, 'f', -1, 64)
}
value = fmt.Sprintf("%v", fields["subnet_size"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
size, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
i.SubnetSize = int(size)
i.IPType = fmt.Sprintf("%v", fields["ip_type"])
i.Subnet = fmt.Sprintf("%v", fields["subnet"])
i.Label = fmt.Sprintf("%v", fields["label"])
return
}
// ListReservedIP returns a list of all available reserved IPs on Vultr account
func (c *Client) ListReservedIP() ([]IP, error) {
var ipMap map[string]IP
err := c.get(`reservedip/list`, &ipMap)
if err != nil {
return nil, err
}
ipList := make([]IP, 0)
for _, ip := range ipMap {
ipList = append(ipList, ip)
}
sort.Sort(ips(ipList))
return ipList, nil
}
// GetReservedIP returns reserved IP with given ID
func (c *Client) GetReservedIP(id string) (IP, error) {
var ipMap map[string]IP
err := c.get(`reservedip/list`, &ipMap)
if err != nil {
return IP{}, err
}
if ip, ok := ipMap[id]; ok {
return ip, nil
}
return IP{}, fmt.Errorf("IP with ID %v not found", id)
}
// CreateReservedIP creates a new reserved IP on Vultr account
func (c *Client) CreateReservedIP(regionID int, ipType string, label string) (string, error) {
values := url.Values{
"DCID": {fmt.Sprintf("%v", regionID)},
"ip_type": {ipType},
}
if len(label) > 0 {
values.Add("label", label)
}
result := IP{}
err := c.post(`reservedip/create`, values, &result)
if err != nil {
return "", err
}
return result.ID, nil
}
// DestroyReservedIP deletes an existing reserved IP
func (c *Client) DestroyReservedIP(id string) error {
values := url.Values{
"SUBID": {id},
}
return c.post(`reservedip/destroy`, values, nil)
}
// AttachReservedIP attaches a reserved IP to a virtual machine
func (c *Client) AttachReservedIP(ip string, serverID string) error {
values := url.Values{
"ip_address": {ip},
"attach_SUBID": {serverID},
}
return c.post(`reservedip/attach`, values, nil)
}
// DetachReservedIP detaches a reserved IP from an existing virtual machine
func (c *Client) DetachReservedIP(serverID string, ip string) error {
values := url.Values{
"ip_address": {ip},
"detach_SUBID": {serverID},
}
return c.post(`reservedip/detach`, values, nil)
}
// ConvertReservedIP converts an existing virtual machines IP to a reserved IP
func (c *Client) ConvertReservedIP(serverID string, ip string) (string, error) {
values := url.Values{
"SUBID": {serverID},
"ip_address": {ip},
}
result := IP{}
err := c.post(`reservedip/convert`, values, &result)
if err != nil {
return "", err
}
return result.ID, err
}

View file

@ -1,126 +0,0 @@
package lib
import (
"encoding/json"
"fmt"
"net/url"
"sort"
"strings"
)
// StartupScript on Vultr account
type StartupScript struct {
ID string `json:"SCRIPTID"`
Name string `json:"name"`
Type string `json:"type"`
Content string `json:"script"`
}
type startupscripts []StartupScript
func (s startupscripts) Len() int { return len(s) }
func (s startupscripts) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s startupscripts) Less(i, j int) bool {
return strings.ToLower(s[i].Name) < strings.ToLower(s[j].Name)
}
// UnmarshalJSON implements json.Unmarshaller on StartupScript.
// Necessary because the SCRIPTID field has inconsistent types.
func (s *StartupScript) UnmarshalJSON(data []byte) (err error) {
if s == nil {
*s = StartupScript{}
}
var fields map[string]interface{}
if err := json.Unmarshal(data, &fields); err != nil {
return err
}
s.ID = fmt.Sprintf("%v", fields["SCRIPTID"])
s.Name = fmt.Sprintf("%v", fields["name"])
s.Type = fmt.Sprintf("%v", fields["type"])
s.Content = fmt.Sprintf("%v", fields["script"])
return
}
// GetStartupScripts returns a list of all startup scripts on the current Vultr account
func (c *Client) GetStartupScripts() (scripts []StartupScript, err error) {
var scriptMap map[string]StartupScript
if err := c.get(`startupscript/list`, &scriptMap); err != nil {
return nil, err
}
for _, script := range scriptMap {
if script.Type == "" {
script.Type = "boot" // set default script type
}
scripts = append(scripts, script)
}
sort.Sort(startupscripts(scripts))
return scripts, nil
}
// GetStartupScript returns the startup script with the given ID
func (c *Client) GetStartupScript(id string) (StartupScript, error) {
scripts, err := c.GetStartupScripts()
if err != nil {
return StartupScript{}, err
}
for _, s := range scripts {
if s.ID == id {
return s, nil
}
}
return StartupScript{}, nil
}
// CreateStartupScript creates a new startup script
func (c *Client) CreateStartupScript(name, content, scriptType string) (StartupScript, error) {
values := url.Values{
"name": {name},
"script": {content},
"type": {scriptType},
}
var script StartupScript
if err := c.post(`startupscript/create`, values, &script); err != nil {
return StartupScript{}, err
}
script.Name = name
script.Content = content
script.Type = scriptType
return script, nil
}
// UpdateStartupScript updates an existing startup script
func (c *Client) UpdateStartupScript(script StartupScript) error {
values := url.Values{
"SCRIPTID": {script.ID},
}
if script.Name != "" {
values.Add("name", script.Name)
}
if script.Content != "" {
values.Add("script", script.Content)
}
if err := c.post(`startupscript/update`, values, nil); err != nil {
return err
}
return nil
}
// DeleteStartupScript deletes an existing startup script from Vultr account
func (c *Client) DeleteStartupScript(id string) error {
values := url.Values{
"SCRIPTID": {id},
}
if err := c.post(`startupscript/destroy`, values, nil); err != nil {
return err
}
return nil
}

View file

@ -1,561 +0,0 @@
package lib
import (
"encoding/base64"
"encoding/json"
"fmt"
"net/url"
"sort"
"strconv"
"strings"
)
// Server (virtual machine) on Vultr account
type Server struct {
ID string `json:"SUBID"`
Name string `json:"label"`
OS string `json:"os"`
RAM string `json:"ram"`
Disk string `json:"disk"`
MainIP string `json:"main_ip"`
VCpus int `json:"vcpu_count,string"`
Location string `json:"location"`
RegionID int `json:"DCID,string"`
DefaultPassword string `json:"default_password"`
Created string `json:"date_created"`
PendingCharges float64 `json:"pending_charges"`
Status string `json:"status"`
Cost string `json:"cost_per_month"`
CurrentBandwidth float64 `json:"current_bandwidth_gb"`
AllowedBandwidth float64 `json:"allowed_bandwidth_gb,string"`
NetmaskV4 string `json:"netmask_v4"`
GatewayV4 string `json:"gateway_v4"`
PowerStatus string `json:"power_status"`
ServerState string `json:"server_state"`
PlanID int `json:"VPSPLANID,string"`
V6Networks []V6Network `json:"v6_networks"`
InternalIP string `json:"internal_ip"`
KVMUrl string `json:"kvm_url"`
AutoBackups string `json:"auto_backups"`
Tag string `json:"tag"`
OSID string `json:"OSID"`
AppID string `json:"APPID"`
FirewallGroupID string `json:"FIREWALLGROUPID"`
}
// ServerOptions are optional parameters to be used during server creation
type ServerOptions struct {
IPXEChainURL string
ISO int
Script int
UserData string
Snapshot string
SSHKey string
ReservedIP string
IPV6 bool
PrivateNetworking bool
AutoBackups bool
DontNotifyOnActivate bool
Hostname string
Tag string
AppID string
FirewallGroupID string
}
type servers []Server
func (s servers) Len() int { return len(s) }
func (s servers) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s servers) Less(i, j int) bool {
// sort order: name, ip
if strings.ToLower(s[i].Name) < strings.ToLower(s[j].Name) {
return true
} else if strings.ToLower(s[i].Name) > strings.ToLower(s[j].Name) {
return false
}
return s[i].MainIP < s[j].MainIP
}
// V6Network represents a IPv6 network of a Vultr server
type V6Network struct {
Network string `json:"v6_network"`
MainIP string `json:"v6_main_ip"`
NetworkSize string `json:"v6_network_size"`
}
// ISOStatus represents an ISO image attached to a Vultr server
type ISOStatus struct {
State string `json:"state"`
ISOID string `json:"ISOID"`
}
// UnmarshalJSON implements json.Unmarshaller on Server.
// This is needed because the Vultr API is inconsistent in it's JSON responses for servers.
// Some fields can change type, from JSON number to JSON string and vice-versa.
func (s *Server) UnmarshalJSON(data []byte) (err error) {
if s == nil {
*s = Server{}
}
var fields map[string]interface{}
if err := json.Unmarshal(data, &fields); err != nil {
return err
}
value := fmt.Sprintf("%v", fields["vcpu_count"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
vcpu, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
s.VCpus = int(vcpu)
value = fmt.Sprintf("%v", fields["DCID"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
region, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
s.RegionID = int(region)
value = fmt.Sprintf("%v", fields["VPSPLANID"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
plan, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
s.PlanID = int(plan)
value = fmt.Sprintf("%v", fields["pending_charges"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
pc, err := strconv.ParseFloat(value, 64)
if err != nil {
return err
}
s.PendingCharges = pc
value = fmt.Sprintf("%v", fields["current_bandwidth_gb"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
cb, err := strconv.ParseFloat(value, 64)
if err != nil {
return err
}
s.CurrentBandwidth = cb
value = fmt.Sprintf("%v", fields["allowed_bandwidth_gb"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
ab, err := strconv.ParseFloat(value, 64)
if err != nil {
return err
}
s.AllowedBandwidth = ab
value = fmt.Sprintf("%v", fields["OSID"])
if value == "<nil>" {
value = ""
}
s.OSID = value
value = fmt.Sprintf("%v", fields["APPID"])
if value == "<nil>" || value == "0" {
value = ""
}
s.AppID = value
value = fmt.Sprintf("%v", fields["FIREWALLGROUPID"])
if value == "<nil>" || value == "0" {
value = ""
}
s.FirewallGroupID = value
s.ID = fmt.Sprintf("%v", fields["SUBID"])
s.Name = fmt.Sprintf("%v", fields["label"])
s.OS = fmt.Sprintf("%v", fields["os"])
s.RAM = fmt.Sprintf("%v", fields["ram"])
s.Disk = fmt.Sprintf("%v", fields["disk"])
s.MainIP = fmt.Sprintf("%v", fields["main_ip"])
s.Location = fmt.Sprintf("%v", fields["location"])
s.DefaultPassword = fmt.Sprintf("%v", fields["default_password"])
s.Created = fmt.Sprintf("%v", fields["date_created"])
s.Status = fmt.Sprintf("%v", fields["status"])
s.Cost = fmt.Sprintf("%v", fields["cost_per_month"])
s.NetmaskV4 = fmt.Sprintf("%v", fields["netmask_v4"])
s.GatewayV4 = fmt.Sprintf("%v", fields["gateway_v4"])
s.PowerStatus = fmt.Sprintf("%v", fields["power_status"])
s.ServerState = fmt.Sprintf("%v", fields["server_state"])
v6networks := make([]V6Network, 0)
if networks, ok := fields["v6_networks"].([]interface{}); ok {
for _, network := range networks {
if network, ok := network.(map[string]interface{}); ok {
v6network := V6Network{
Network: fmt.Sprintf("%v", network["v6_network"]),
MainIP: fmt.Sprintf("%v", network["v6_main_ip"]),
NetworkSize: fmt.Sprintf("%v", network["v6_network_size"]),
}
v6networks = append(v6networks, v6network)
}
}
s.V6Networks = v6networks
}
s.InternalIP = fmt.Sprintf("%v", fields["internal_ip"])
s.KVMUrl = fmt.Sprintf("%v", fields["kvm_url"])
s.AutoBackups = fmt.Sprintf("%v", fields["auto_backups"])
s.Tag = fmt.Sprintf("%v", fields["tag"])
return
}
// GetServers returns a list of current virtual machines on Vultr account
func (c *Client) GetServers() (serverList []Server, err error) {
var serverMap map[string]Server
if err := c.get(`server/list`, &serverMap); err != nil {
return nil, err
}
for _, server := range serverMap {
serverList = append(serverList, server)
}
sort.Sort(servers(serverList))
return serverList, nil
}
// GetServersByTag returns a list of all virtual machines matching by tag
func (c *Client) GetServersByTag(tag string) (serverList []Server, err error) {
var serverMap map[string]Server
if err := c.get(`server/list?tag=`+tag, &serverMap); err != nil {
return nil, err
}
for _, server := range serverMap {
serverList = append(serverList, server)
}
sort.Sort(servers(serverList))
return serverList, nil
}
// GetServer returns the virtual machine with the given ID
func (c *Client) GetServer(id string) (server Server, err error) {
if err := c.get(`server/list?SUBID=`+id, &server); err != nil {
return Server{}, err
}
return server, nil
}
// CreateServer creates a new virtual machine on Vultr. ServerOptions are optional settings.
func (c *Client) CreateServer(name string, regionID, planID, osID int, options *ServerOptions) (Server, error) {
values := url.Values{
"label": {name},
"DCID": {fmt.Sprintf("%v", regionID)},
"VPSPLANID": {fmt.Sprintf("%v", planID)},
"OSID": {fmt.Sprintf("%v", osID)},
}
if options != nil {
if options.IPXEChainURL != "" {
values.Add("ipxe_chain_url", options.IPXEChainURL)
}
if options.ISO != 0 {
values.Add("ISOID", fmt.Sprintf("%v", options.ISO))
}
if options.Script != 0 {
values.Add("SCRIPTID", fmt.Sprintf("%v", options.Script))
}
if options.UserData != "" {
values.Add("userdata", base64.StdEncoding.EncodeToString([]byte(options.UserData)))
}
if options.Snapshot != "" {
values.Add("SNAPSHOTID", options.Snapshot)
}
if options.SSHKey != "" {
values.Add("SSHKEYID", options.SSHKey)
}
if options.ReservedIP != "" {
values.Add("reserved_ip_v4", options.ReservedIP)
}
values.Add("enable_ipv6", "no")
if options.IPV6 {
values.Set("enable_ipv6", "yes")
}
values.Add("enable_private_network", "no")
if options.PrivateNetworking {
values.Set("enable_private_network", "yes")
}
values.Add("auto_backups", "no")
if options.AutoBackups {
values.Set("auto_backups", "yes")
}
values.Add("notify_activate", "yes")
if options.DontNotifyOnActivate {
values.Set("notify_activate", "no")
}
if options.Hostname != "" {
values.Add("hostname", options.Hostname)
}
if options.Tag != "" {
values.Add("tag", options.Tag)
}
if options.AppID != "" {
values.Add("APPID", options.AppID)
}
if options.FirewallGroupID != "" {
values.Add("FIREWALLGROUPID", options.FirewallGroupID)
}
}
var server Server
if err := c.post(`server/create`, values, &server); err != nil {
return Server{}, err
}
server.Name = name
server.RegionID = regionID
server.PlanID = planID
return server, nil
}
// RenameServer renames an existing virtual machine
func (c *Client) RenameServer(id, name string) error {
values := url.Values{
"SUBID": {id},
"label": {name},
}
if err := c.post(`server/label_set`, values, nil); err != nil {
return err
}
return nil
}
// TagServer replaces the tag on an existing virtual machine
func (c *Client) TagServer(id, tag string) error {
values := url.Values{
"SUBID": {id},
"tag": {tag},
}
if err := c.post(`server/tag_set`, values, nil); err != nil {
return err
}
return nil
}
// StartServer starts an existing virtual machine
func (c *Client) StartServer(id string) error {
values := url.Values{
"SUBID": {id},
}
if err := c.post(`server/start`, values, nil); err != nil {
return err
}
return nil
}
// HaltServer stops an existing virtual machine
func (c *Client) HaltServer(id string) error {
values := url.Values{
"SUBID": {id},
}
if err := c.post(`server/halt`, values, nil); err != nil {
return err
}
return nil
}
// RebootServer reboots an existing virtual machine
func (c *Client) RebootServer(id string) error {
values := url.Values{
"SUBID": {id},
}
if err := c.post(`server/reboot`, values, nil); err != nil {
return err
}
return nil
}
// ReinstallServer reinstalls the operating system on an existing virtual machine
func (c *Client) ReinstallServer(id string) error {
values := url.Values{
"SUBID": {id},
}
if err := c.post(`server/reinstall`, values, nil); err != nil {
return err
}
return nil
}
// ChangeOSofServer changes the virtual machine to a different operating system
func (c *Client) ChangeOSofServer(id string, osID int) error {
values := url.Values{
"SUBID": {id},
"OSID": {fmt.Sprintf("%v", osID)},
}
if err := c.post(`server/os_change`, values, nil); err != nil {
return err
}
return nil
}
// ListOSforServer lists all available operating systems to which an existing virtual machine can be changed
func (c *Client) ListOSforServer(id string) (os []OS, err error) {
var osMap map[string]OS
if err := c.get(`server/os_change_list?SUBID=`+id, &osMap); err != nil {
return nil, err
}
for _, o := range osMap {
os = append(os, o)
}
sort.Sort(oses(os))
return os, nil
}
// AttachISOtoServer attaches an ISO image to an existing virtual machine and reboots it
func (c *Client) AttachISOtoServer(id string, isoID int) error {
values := url.Values{
"SUBID": {id},
"ISOID": {fmt.Sprintf("%v", isoID)},
}
if err := c.post(`server/iso_attach`, values, nil); err != nil {
return err
}
return nil
}
// DetachISOfromServer detaches the currently mounted ISO image from the virtual machine and reboots it
func (c *Client) DetachISOfromServer(id string) error {
values := url.Values{
"SUBID": {id},
}
if err := c.post(`server/iso_detach`, values, nil); err != nil {
return err
}
return nil
}
// GetISOStatusofServer retrieves the current ISO image state of an existing virtual machine
func (c *Client) GetISOStatusofServer(id string) (isoStatus ISOStatus, err error) {
if err := c.get(`server/iso_status?SUBID=`+id, &isoStatus); err != nil {
return ISOStatus{}, err
}
return isoStatus, nil
}
// DeleteServer deletes an existing virtual machine
func (c *Client) DeleteServer(id string) error {
values := url.Values{
"SUBID": {id},
}
if err := c.post(`server/destroy`, values, nil); err != nil {
return err
}
return nil
}
// SetFirewallGroup adds a virtual machine to a firewall group
func (c *Client) SetFirewallGroup(id, firewallgroup string) error {
values := url.Values{
"SUBID": {id},
"FIREWALLGROUPID": {firewallgroup},
}
if err := c.post(`server/firewall_group_set`, values, nil); err != nil {
return err
}
return nil
}
// UnsetFirewallGroup removes a virtual machine from a firewall group
func (c *Client) UnsetFirewallGroup(id string) error {
return c.SetFirewallGroup(id, "0")
}
// BandwidthOfServer retrieves the bandwidth used by a virtual machine
func (c *Client) BandwidthOfServer(id string) (bandwidth []map[string]string, err error) {
var bandwidthMap map[string][][]string
if err := c.get(`server/bandwidth?SUBID=`+id, &bandwidthMap); err != nil {
return nil, err
}
// parse incoming bytes
for _, b := range bandwidthMap["incoming_bytes"] {
bMap := make(map[string]string)
bMap["date"] = b[0]
bMap["incoming"] = b[1]
bandwidth = append(bandwidth, bMap)
}
// parse outgoing bytes (we'll assume that incoming and outgoing dates are always a match)
for _, b := range bandwidthMap["outgoing_bytes"] {
for i := range bandwidth {
if bandwidth[i]["date"] == b[0] {
bandwidth[i]["outgoing"] = b[1]
break
}
}
}
return bandwidth, nil
}
// ChangeApplicationofServer changes the virtual machine to a different application
func (c *Client) ChangeApplicationofServer(id string, appID string) error {
values := url.Values{
"SUBID": {id},
"APPID": {appID},
}
if err := c.post(`server/app_change`, values, nil); err != nil {
return err
}
return nil
}
// ListApplicationsforServer lists all available operating systems to which an existing virtual machine can be changed
func (c *Client) ListApplicationsforServer(id string) (apps []Application, err error) {
var appMap map[string]Application
if err := c.get(`server/app_change_list?SUBID=`+id, &appMap); err != nil {
return nil, err
}
for _, app := range appMap {
apps = append(apps, app)
}
sort.Sort(applications(apps))
return apps, nil
}

View file

@ -1,72 +0,0 @@
package lib
import (
"net/url"
"sort"
"strings"
)
// Snapshot of a virtual machine on Vultr account
type Snapshot struct {
ID string `json:"SNAPSHOTID"`
Description string `json:"description"`
Size string `json:"size"`
Status string `json:"status"`
Created string `json:"date_created"`
}
type snapshots []Snapshot
func (s snapshots) Len() int { return len(s) }
func (s snapshots) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s snapshots) Less(i, j int) bool {
// sort order: description, created
if strings.ToLower(s[i].Description) < strings.ToLower(s[j].Description) {
return true
} else if strings.ToLower(s[i].Description) > strings.ToLower(s[j].Description) {
return false
}
return s[i].Created < s[j].Created
}
// GetSnapshots retrieves a list of all snapshots on Vultr account
func (c *Client) GetSnapshots() (snapshotList []Snapshot, err error) {
var snapshotMap map[string]Snapshot
if err := c.get(`snapshot/list`, &snapshotMap); err != nil {
return nil, err
}
for _, snapshot := range snapshotMap {
snapshotList = append(snapshotList, snapshot)
}
sort.Sort(snapshots(snapshotList))
return snapshotList, nil
}
// CreateSnapshot creates a new virtual machine snapshot
func (c *Client) CreateSnapshot(id, description string) (Snapshot, error) {
values := url.Values{
"SUBID": {id},
"description": {description},
}
var snapshot Snapshot
if err := c.post(`snapshot/create`, values, &snapshot); err != nil {
return Snapshot{}, err
}
snapshot.Description = description
return snapshot, nil
}
// DeleteSnapshot deletes an existing virtual machine snapshot
func (c *Client) DeleteSnapshot(id string) error {
values := url.Values{
"SNAPSHOTID": {id},
}
if err := c.post(`snapshot/destroy`, values, nil); err != nil {
return err
}
return nil
}

View file

@ -1,82 +0,0 @@
package lib
import (
"net/url"
"sort"
"strings"
)
// SSHKey on Vultr account
type SSHKey struct {
ID string `json:"SSHKEYID"`
Name string `json:"name"`
Key string `json:"ssh_key"`
Created string `json:"date_created"`
}
type sshkeys []SSHKey
func (s sshkeys) Len() int { return len(s) }
func (s sshkeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s sshkeys) Less(i, j int) bool { return strings.ToLower(s[i].Name) < strings.ToLower(s[j].Name) }
// GetSSHKeys returns a list of SSHKeys from Vultr account
func (c *Client) GetSSHKeys() (keys []SSHKey, err error) {
var keyMap map[string]SSHKey
if err := c.get(`sshkey/list`, &keyMap); err != nil {
return nil, err
}
for _, key := range keyMap {
keys = append(keys, key)
}
sort.Sort(sshkeys(keys))
return keys, nil
}
// CreateSSHKey creates new SSHKey on Vultr
func (c *Client) CreateSSHKey(name, key string) (SSHKey, error) {
values := url.Values{
"name": {name},
"ssh_key": {key},
}
var sshKey SSHKey
if err := c.post(`sshkey/create`, values, &sshKey); err != nil {
return SSHKey{}, err
}
sshKey.Name = name
sshKey.Key = key
return sshKey, nil
}
// UpdateSSHKey updates an existing SSHKey entry
func (c *Client) UpdateSSHKey(key SSHKey) error {
values := url.Values{
"SSHKEYID": {key.ID},
}
if key.Name != "" {
values.Add("name", key.Name)
}
if key.Key != "" {
values.Add("ssh_key", key.Key)
}
if err := c.post(`sshkey/update`, values, nil); err != nil {
return err
}
return nil
}
// DeleteSSHKey deletes an existing SSHKey from Vultr account
func (c *Client) DeleteSSHKey(id string) error {
values := url.Values{
"SSHKEYID": {id},
}
if err := c.post(`sshkey/destroy`, values, nil); err != nil {
return err
}
return nil
}

View file

@ -1,191 +0,0 @@
All files in this repository are licensed as follows. If you contribute
to this repository, it is assumed that you license your contribution
under the same license unless you state otherwise.
All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file.
This software is licensed under the LGPLv3, included below.
As a special exception to the GNU Lesser General Public License version 3
("LGPL3"), the copyright holders of this Library give you permission to
convey to a third party a Combined Work that links statically or dynamically
to this Library without providing any Minimal Corresponding Source or
Minimal Application Code as set out in 4d or providing the installation
information set out in section 4e, provided that you comply with the other
provisions of LGPL3 and provided that you meet, for the Application the
terms and conditions of the license(s) which apply to the Application.
Except as stated in this special exception, the provisions of LGPL3 will
continue to comply in full to this Library. If you modify this Library, you
may apply this exception to your version of this Library, but you are not
obliged to do so. If you do not wish to do so, delete this exception
statement from your version. This exception does not (and cannot) modify any
license terms which apply to the Application, with which you must still
comply.
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View file

@ -1,344 +0,0 @@
// Copyright 2014 Canonical Ltd.
// Licensed under the LGPLv3 with static-linking exception.
// See LICENCE file for details.
// Package ratelimit provides an efficient token bucket implementation
// that can be used to limit the rate of arbitrary things.
// See http://en.wikipedia.org/wiki/Token_bucket.
package ratelimit
import (
"math"
"strconv"
"sync"
"time"
)
// The algorithm that this implementation uses does computational work
// only when tokens are removed from the bucket, and that work completes
// in short, bounded-constant time (Bucket.Wait benchmarks at 175ns on
// my laptop).
//
// Time is measured in equal measured ticks, a given interval
// (fillInterval) apart. On each tick a number of tokens (quantum) are
// added to the bucket.
//
// When any of the methods are called the bucket updates the number of
// tokens that are in the bucket, and it records the current tick
// number too. Note that it doesn't record the current time - by
// keeping things in units of whole ticks, it's easy to dish out tokens
// at exactly the right intervals as measured from the start time.
//
// This allows us to calculate the number of tokens that will be
// available at some time in the future with a few simple arithmetic
// operations.
//
// The main reason for being able to transfer multiple tokens on each tick
// is so that we can represent rates greater than 1e9 (the resolution of the Go
// time package) tokens per second, but it's also useful because
// it means we can easily represent situations like "a person gets
// five tokens an hour, replenished on the hour".
// Bucket represents a token bucket that fills at a predetermined rate.
// Methods on Bucket may be called concurrently.
type Bucket struct {
clock Clock
// startTime holds the moment when the bucket was
// first created and ticks began.
startTime time.Time
// capacity holds the overall capacity of the bucket.
capacity int64
// quantum holds how many tokens are added on
// each tick.
quantum int64
// fillInterval holds the interval between each tick.
fillInterval time.Duration
// mu guards the fields below it.
mu sync.Mutex
// availableTokens holds the number of available
// tokens as of the associated latestTick.
// It will be negative when there are consumers
// waiting for tokens.
availableTokens int64
// latestTick holds the latest tick for which
// we know the number of tokens in the bucket.
latestTick int64
}
// NewBucket returns a new token bucket that fills at the
// rate of one token every fillInterval, up to the given
// maximum capacity. Both arguments must be
// positive. The bucket is initially full.
func NewBucket(fillInterval time.Duration, capacity int64) *Bucket {
return NewBucketWithClock(fillInterval, capacity, nil)
}
// NewBucketWithClock is identical to NewBucket but injects a testable clock
// interface.
func NewBucketWithClock(fillInterval time.Duration, capacity int64, clock Clock) *Bucket {
return NewBucketWithQuantumAndClock(fillInterval, capacity, 1, clock)
}
// rateMargin specifes the allowed variance of actual
// rate from specified rate. 1% seems reasonable.
const rateMargin = 0.01
// NewBucketWithRate returns a token bucket that fills the bucket
// at the rate of rate tokens per second up to the given
// maximum capacity. Because of limited clock resolution,
// at high rates, the actual rate may be up to 1% different from the
// specified rate.
func NewBucketWithRate(rate float64, capacity int64) *Bucket {
return NewBucketWithRateAndClock(rate, capacity, nil)
}
// NewBucketWithRateAndClock is identical to NewBucketWithRate but injects a
// testable clock interface.
func NewBucketWithRateAndClock(rate float64, capacity int64, clock Clock) *Bucket {
// Use the same bucket each time through the loop
// to save allocations.
tb := NewBucketWithQuantumAndClock(1, capacity, 1, clock)
for quantum := int64(1); quantum < 1<<50; quantum = nextQuantum(quantum) {
fillInterval := time.Duration(1e9 * float64(quantum) / rate)
if fillInterval <= 0 {
continue
}
tb.fillInterval = fillInterval
tb.quantum = quantum
if diff := math.Abs(tb.Rate() - rate); diff/rate <= rateMargin {
return tb
}
}
panic("cannot find suitable quantum for " + strconv.FormatFloat(rate, 'g', -1, 64))
}
// nextQuantum returns the next quantum to try after q.
// We grow the quantum exponentially, but slowly, so we
// get a good fit in the lower numbers.
func nextQuantum(q int64) int64 {
q1 := q * 11 / 10
if q1 == q {
q1++
}
return q1
}
// NewBucketWithQuantum is similar to NewBucket, but allows
// the specification of the quantum size - quantum tokens
// are added every fillInterval.
func NewBucketWithQuantum(fillInterval time.Duration, capacity, quantum int64) *Bucket {
return NewBucketWithQuantumAndClock(fillInterval, capacity, quantum, nil)
}
// NewBucketWithQuantumAndClock is like NewBucketWithQuantum, but
// also has a clock argument that allows clients to fake the passing
// of time. If clock is nil, the system clock will be used.
func NewBucketWithQuantumAndClock(fillInterval time.Duration, capacity, quantum int64, clock Clock) *Bucket {
if clock == nil {
clock = realClock{}
}
if fillInterval <= 0 {
panic("token bucket fill interval is not > 0")
}
if capacity <= 0 {
panic("token bucket capacity is not > 0")
}
if quantum <= 0 {
panic("token bucket quantum is not > 0")
}
return &Bucket{
clock: clock,
startTime: clock.Now(),
latestTick: 0,
fillInterval: fillInterval,
capacity: capacity,
quantum: quantum,
availableTokens: capacity,
}
}
// Wait takes count tokens from the bucket, waiting until they are
// available.
func (tb *Bucket) Wait(count int64) {
if d := tb.Take(count); d > 0 {
tb.clock.Sleep(d)
}
}
// WaitMaxDuration is like Wait except that it will
// only take tokens from the bucket if it needs to wait
// for no greater than maxWait. It reports whether
// any tokens have been removed from the bucket
// If no tokens have been removed, it returns immediately.
func (tb *Bucket) WaitMaxDuration(count int64, maxWait time.Duration) bool {
d, ok := tb.TakeMaxDuration(count, maxWait)
if d > 0 {
tb.clock.Sleep(d)
}
return ok
}
const infinityDuration time.Duration = 0x7fffffffffffffff
// Take takes count tokens from the bucket without blocking. It returns
// the time that the caller should wait until the tokens are actually
// available.
//
// Note that if the request is irrevocable - there is no way to return
// tokens to the bucket once this method commits us to taking them.
func (tb *Bucket) Take(count int64) time.Duration {
tb.mu.Lock()
defer tb.mu.Unlock()
d, _ := tb.take(tb.clock.Now(), count, infinityDuration)
return d
}
// TakeMaxDuration is like Take, except that
// it will only take tokens from the bucket if the wait
// time for the tokens is no greater than maxWait.
//
// If it would take longer than maxWait for the tokens
// to become available, it does nothing and reports false,
// otherwise it returns the time that the caller should
// wait until the tokens are actually available, and reports
// true.
func (tb *Bucket) TakeMaxDuration(count int64, maxWait time.Duration) (time.Duration, bool) {
tb.mu.Lock()
defer tb.mu.Unlock()
return tb.take(tb.clock.Now(), count, maxWait)
}
// TakeAvailable takes up to count immediately available tokens from the
// bucket. It returns the number of tokens removed, or zero if there are
// no available tokens. It does not block.
func (tb *Bucket) TakeAvailable(count int64) int64 {
tb.mu.Lock()
defer tb.mu.Unlock()
return tb.takeAvailable(tb.clock.Now(), count)
}
// takeAvailable is the internal version of TakeAvailable - it takes the
// current time as an argument to enable easy testing.
func (tb *Bucket) takeAvailable(now time.Time, count int64) int64 {
if count <= 0 {
return 0
}
tb.adjustavailableTokens(tb.currentTick(now))
if tb.availableTokens <= 0 {
return 0
}
if count > tb.availableTokens {
count = tb.availableTokens
}
tb.availableTokens -= count
return count
}
// Available returns the number of available tokens. It will be negative
// when there are consumers waiting for tokens. Note that if this
// returns greater than zero, it does not guarantee that calls that take
// tokens from the buffer will succeed, as the number of available
// tokens could have changed in the meantime. This method is intended
// primarily for metrics reporting and debugging.
func (tb *Bucket) Available() int64 {
return tb.available(tb.clock.Now())
}
// available is the internal version of available - it takes the current time as
// an argument to enable easy testing.
func (tb *Bucket) available(now time.Time) int64 {
tb.mu.Lock()
defer tb.mu.Unlock()
tb.adjustavailableTokens(tb.currentTick(now))
return tb.availableTokens
}
// Capacity returns the capacity that the bucket was created with.
func (tb *Bucket) Capacity() int64 {
return tb.capacity
}
// Rate returns the fill rate of the bucket, in tokens per second.
func (tb *Bucket) Rate() float64 {
return 1e9 * float64(tb.quantum) / float64(tb.fillInterval)
}
// take is the internal version of Take - it takes the current time as
// an argument to enable easy testing.
func (tb *Bucket) take(now time.Time, count int64, maxWait time.Duration) (time.Duration, bool) {
if count <= 0 {
return 0, true
}
tick := tb.currentTick(now)
tb.adjustavailableTokens(tick)
avail := tb.availableTokens - count
if avail >= 0 {
tb.availableTokens = avail
return 0, true
}
// Round up the missing tokens to the nearest multiple
// of quantum - the tokens won't be available until
// that tick.
// endTick holds the tick when all the requested tokens will
// become available.
endTick := tick + (-avail+tb.quantum-1)/tb.quantum
endTime := tb.startTime.Add(time.Duration(endTick) * tb.fillInterval)
waitTime := endTime.Sub(now)
if waitTime > maxWait {
return 0, false
}
tb.availableTokens = avail
return waitTime, true
}
// currentTick returns the current time tick, measured
// from tb.startTime.
func (tb *Bucket) currentTick(now time.Time) int64 {
return int64(now.Sub(tb.startTime) / tb.fillInterval)
}
// adjustavailableTokens adjusts the current number of tokens
// available in the bucket at the given time, which must
// be in the future (positive) with respect to tb.latestTick.
func (tb *Bucket) adjustavailableTokens(tick int64) {
if tb.availableTokens >= tb.capacity {
return
}
tb.availableTokens += (tick - tb.latestTick) * tb.quantum
if tb.availableTokens > tb.capacity {
tb.availableTokens = tb.capacity
}
tb.latestTick = tick
return
}
// Clock represents the passage of time in a way that
// can be faked out for tests.
type Clock interface {
// Now returns the current time.
Now() time.Time
// Sleep sleeps for at least the given duration.
Sleep(d time.Duration)
}
// realClock implements Clock in terms of standard time functions.
type realClock struct{}
// Now implements Clock.Now by calling time.Now.
func (realClock) Now() time.Time {
return time.Now()
}
// Now implements Clock.Sleep by calling time.Sleep.
func (realClock) Sleep(d time.Duration) {
time.Sleep(d)
}

View file

@ -1,51 +0,0 @@
// Copyright 2014 Canonical Ltd.
// Licensed under the LGPLv3 with static-linking exception.
// See LICENCE file for details.
package ratelimit
import "io"
type reader struct {
r io.Reader
bucket *Bucket
}
// Reader returns a reader that is rate limited by
// the given token bucket. Each token in the bucket
// represents one byte.
func Reader(r io.Reader, bucket *Bucket) io.Reader {
return &reader{
r: r,
bucket: bucket,
}
}
func (r *reader) Read(buf []byte) (int, error) {
n, err := r.r.Read(buf)
if n <= 0 {
return n, err
}
r.bucket.Wait(int64(n))
return n, err
}
type writer struct {
w io.Writer
bucket *Bucket
}
// Writer returns a reader that is rate limited by
// the given token bucket. Each token in the bucket
// represents one byte.
func Writer(w io.Writer, bucket *Bucket) io.Writer {
return &writer{
w: w,
bucket: bucket,
}
}
func (w *writer) Write(buf []byte) (int, error) {
w.bucket.Wait(int64(len(buf)))
return w.w.Write(buf)
}

View file

@ -1,6 +1,6 @@
The MIT License (MIT) MIT License
Copyright (c) 2015 Fabio Berchtold Copyright (c) 2019 Vultr
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.

45
vendor/github.com/vultr/govultr/account.go generated vendored Normal file
View file

@ -0,0 +1,45 @@
package govultr
import (
"context"
"net/http"
)
// AccountService is the interface to interact with Accounts endpoint on the Vultr API
// Link: https://www.vultr.com/api/#account
type AccountService interface {
GetInfo(ctx context.Context) (*Account, error)
}
// AccountServiceHandler handles interaction with the account methods for the Vultr API
type AccountServiceHandler struct {
client *Client
}
// Account represents a Vultr account
type Account struct {
Balance string `json:"balance"`
PendingCharges string `json:"pending_charges"`
LastPaymentDate string `json:"last_payment_date"`
LastPaymentAmount string `json:"last_payment_amount"`
}
// GetInfo Vultr account info
func (a *AccountServiceHandler) GetInfo(ctx context.Context) (*Account, error) {
uri := "/v1/account/info"
req, err := a.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
account := new(Account)
err = a.client.DoWithContext(ctx, req, account)
if err != nil {
return nil, err
}
return account, nil
}

44
vendor/github.com/vultr/govultr/api.go generated vendored Normal file
View file

@ -0,0 +1,44 @@
package govultr
import (
"context"
"net/http"
)
// APIService is the interface to interact with the API endpoint on the Vultr API
// Link: https://www.vultr.com/api/#auth
type APIService interface {
GetInfo(ctx context.Context) (*API, error)
}
// APIServiceHandler handles interaction with the API methods for the Vultr API
type APIServiceHandler struct {
client *Client
}
// API represents Vultr API information
type API struct {
ACL []string `json:"acls"`
Email string `json:"email"`
Name string `json:"name"`
}
// GetInfo Vultr API auth information
func (a *APIServiceHandler) GetInfo(ctx context.Context) (*API, error) {
uri := "/v1/auth/info"
req, err := a.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
api := new(API)
err = a.client.DoWithContext(ctx, req, api)
if err != nil {
return nil, err
}
return api, nil
}

51
vendor/github.com/vultr/govultr/application.go generated vendored Normal file
View file

@ -0,0 +1,51 @@
package govultr
import (
"context"
"net/http"
)
// ApplicationService is the interface to interact with the Application endpoint on the Vultr API
// Link: https://www.vultr.com/api/#app
type ApplicationService interface {
List(ctx context.Context) ([]Application, error)
}
// ApplicationServiceHandler handles interaction with the application methods for the Vultr API
type ApplicationServiceHandler struct {
client *Client
}
// Application represents a Vultr application
type Application struct {
AppID string `json:"APPID"`
Name string `json:"name"`
ShortName string `json:"short_name"`
DeployName string `json:"deploy_name"`
Surcharge float64 `json:"surcharge"`
}
// List retrieves a list of available applications that can be launched when creating a Vultr VPS
func (a *ApplicationServiceHandler) List(ctx context.Context) ([]Application, error) {
uri := "/v1/app/list"
req, err := a.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
appsMap := make(map[string]Application)
err = a.client.DoWithContext(ctx, req, &appsMap)
if err != nil {
return nil, err
}
var apps []Application
for _, app := range appsMap {
apps = append(apps, app)
}
return apps, nil
}

105
vendor/github.com/vultr/govultr/backup.go generated vendored Normal file
View file

@ -0,0 +1,105 @@
package govultr
import (
"context"
"net/http"
)
// BackupService is the interface to interact with the backup endpoint on the Vultr API
// Link: https://www.vultr.com/api/#backup
type BackupService interface {
List(ctx context.Context) ([]Backup, error)
Get(ctx context.Context, backupID string) (*Backup, error)
ListBySub(ctx context.Context, subID string) ([]Backup, error)
}
// BackupServiceHandler handles interaction with the backup methods for the Vultr API
type BackupServiceHandler struct {
client *Client
}
// Backup represents a Vultr backup
type Backup struct {
BackupID string `json:"BACKUPID"`
DateCreated string `json:"date_created"`
Description string `json:"description"`
Size string `json:"size"`
Status string `json:"status"`
}
// List retrieves a list of all backups on the current account
func (b *BackupServiceHandler) List(ctx context.Context) ([]Backup, error) {
uri := "/v1/backup/list"
req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
backupsMap := make(map[string]Backup)
err = b.client.DoWithContext(ctx, req, &backupsMap)
if err != nil {
return nil, err
}
var backups []Backup
for _, backup := range backupsMap {
backups = append(backups, backup)
}
return backups, nil
}
// Get retrieves a backup that matches the given backupID
func (b *BackupServiceHandler) Get(ctx context.Context, backupID string) (*Backup, error) {
uri := "/v1/backup/list"
req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("BACKUPID", backupID)
req.URL.RawQuery = q.Encode()
backupsMap := make(map[string]Backup)
err = b.client.DoWithContext(ctx, req, &backupsMap)
if err != nil {
return nil, err
}
backup := new(Backup)
for _, bk := range backupsMap {
backup = &bk
}
return backup, nil
}
// ListBySub retrieves a list of all backups on the current account that match the given subID
func (b *BackupServiceHandler) ListBySub(ctx context.Context, subID string) ([]Backup, error) {
uri := "/v1/backup/list"
req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("SUBID", subID)
req.URL.RawQuery = q.Encode()
backupsMap := make(map[string]Backup)
err = b.client.DoWithContext(ctx, req, &backupsMap)
if err != nil {
return nil, err
}
var backups []Backup
for _, backup := range backupsMap {
backups = append(backups, backup)
}
return backups, nil
}

790
vendor/github.com/vultr/govultr/bare_metal_server.go generated vendored Normal file
View file

@ -0,0 +1,790 @@
package govultr
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
)
// BareMetalServerService is the interface to interact with the bare metal endpoints on the Vultr API
// Link: https://www.vultr.com/api/#baremetal
type BareMetalServerService interface {
AppInfo(ctx context.Context, serverID string) (*AppInfo, error)
Bandwidth(ctx context.Context, serverID string) ([]map[string]string, error)
ChangeApp(ctx context.Context, serverID, appID string) error
ChangeOS(ctx context.Context, serverID, osID string) error
Create(ctx context.Context, regionID, planID, osID string, options *BareMetalServerOptions) (*BareMetalServer, error)
Delete(ctx context.Context, serverID string) error
EnableIPV6(ctx context.Context, serverID string) error
List(ctx context.Context) ([]BareMetalServer, error)
ListByLabel(ctx context.Context, label string) ([]BareMetalServer, error)
ListByMainIP(ctx context.Context, mainIP string) ([]BareMetalServer, error)
ListByTag(ctx context.Context, tag string) ([]BareMetalServer, error)
GetServer(ctx context.Context, serverID string) (*BareMetalServer, error)
GetUserData(ctx context.Context, serverID string) (*UserData, error)
Halt(ctx context.Context, serverID string) error
IPV4Info(ctx context.Context, serverID string) ([]BareMetalServerIPV4, error)
IPV6Info(ctx context.Context, serverID string) ([]BareMetalServerIPV6, error)
ListApps(ctx context.Context, serverID string) ([]Application, error)
ListOS(ctx context.Context, serverID string) ([]OS, error)
Reboot(ctx context.Context, serverID string) error
Reinstall(ctx context.Context, serverID string) error
SetLabel(ctx context.Context, serverID, label string) error
SetTag(ctx context.Context, serverID, tag string) error
SetUserData(ctx context.Context, serverID, userData string) error
}
// BareMetalServerServiceHandler handles interaction with the bare metal methods for the Vultr API
type BareMetalServerServiceHandler struct {
client *Client
}
// BareMetalServer represents a bare metal server on Vultr
type BareMetalServer struct {
BareMetalServerID string `json:"SUBID"`
Os string `json:"os"`
RAM string `json:"ram"`
Disk string `json:"disk"`
MainIP string `json:"main_ip"`
CPUs int `json:"cpu_count"`
Location string `json:"location"`
RegionID int `json:"DCID"`
DefaultPassword string `json:"default_password"`
DateCreated string `json:"date_created"`
Status string `json:"status"`
NetmaskV4 string `json:"netmask_v4"`
GatewayV4 string `json:"gateway_v4"`
BareMetalPlanID int `json:"METALPLANID"`
V6Networks []V6Network `json:"v6_networks"`
Label string `json:"label"`
Tag string `json:"tag"`
OsID string `json:"OSID"`
AppID string `json:"APPID"`
}
// BareMetalServerOptions represents the optional parameters that can be set when creating a bare metal server
type BareMetalServerOptions struct {
StartupScriptID string
SnapshotID string
EnableIPV6 string
Label string
SSHKeyIDs []string
AppID string
UserData string
NotifyActivate string
Hostname string
Tag string
ReservedIPV4 string
}
// BareMetalServerIPV4 represents IPV4 information for a bare metal server
type BareMetalServerIPV4 struct {
IP string `json:"ip"`
Netmask string `json:"netmask"`
Gateway string `json:"gateway"`
Type string `json:"type"`
}
// BareMetalServerIPV6 represents IPV6 information for a bare metal server
type BareMetalServerIPV6 struct {
IP string `json:"ip"`
Network string `json:"network"`
NetworkSize int `json:"network_size"`
Type string `json:"type"`
}
// UnmarshalJSON implements a custom unmarshaler on BareMetalServer
// This is done to help reduce data inconsistency with V1 of the Vultr API
func (b *BareMetalServer) UnmarshalJSON(data []byte) error {
if b == nil {
*b = BareMetalServer{}
}
var v map[string]interface{}
if err := json.Unmarshal(data, &v); err != nil {
return err
}
cpu, err := b.unmarshalInt(fmt.Sprintf("%v", v["cpu_count"]))
if err != nil {
return err
}
b.CPUs = cpu
region, err := b.unmarshalInt(fmt.Sprintf("%v", v["DCID"]))
if err != nil {
return err
}
b.RegionID = region
plan, err := b.unmarshalInt(fmt.Sprintf("%v", v["METALPLANID"]))
if err != nil {
return err
}
b.BareMetalPlanID = plan
b.BareMetalServerID = b.unmarshalStr(fmt.Sprintf("%v", v["SUBID"]))
b.Os = b.unmarshalStr(fmt.Sprintf("%v", v["os"]))
b.RAM = b.unmarshalStr(fmt.Sprintf("%v", v["ram"]))
b.Label = b.unmarshalStr(fmt.Sprintf("%v", v["label"]))
b.Disk = b.unmarshalStr(fmt.Sprintf("%v", v["disk"]))
b.MainIP = b.unmarshalStr(fmt.Sprintf("%v", v["main_ip"]))
b.Location = b.unmarshalStr(fmt.Sprintf("%v", v["location"]))
b.DefaultPassword = b.unmarshalStr(fmt.Sprintf("%v", v["default_password"]))
b.DateCreated = b.unmarshalStr(fmt.Sprintf("%v", v["date_created"]))
b.Status = b.unmarshalStr(fmt.Sprintf("%v", v["status"]))
b.NetmaskV4 = b.unmarshalStr(fmt.Sprintf("%v", v["netmask_v4"]))
b.GatewayV4 = b.unmarshalStr(fmt.Sprintf("%v", v["gateway_v4"]))
b.Tag = b.unmarshalStr(fmt.Sprintf("%v", v["tag"]))
b.OsID = b.unmarshalStr(fmt.Sprintf("%v", v["OSID"]))
b.AppID = b.unmarshalStr(fmt.Sprintf("%v", v["APPID"]))
v6networks := make([]V6Network, 0)
if networks, ok := v["v6_networks"].([]interface{}); ok {
for _, network := range networks {
if network, ok := network.(map[string]interface{}); ok {
v6network := V6Network{
Network: fmt.Sprintf("%v", network["v6_network"]),
MainIP: fmt.Sprintf("%v", network["v6_main_ip"]),
NetworkSize: fmt.Sprintf("%v", network["v6_network_size"]),
}
v6networks = append(v6networks, v6network)
}
}
b.V6Networks = v6networks
}
return nil
}
func (b *BareMetalServer) unmarshalInt(value string) (int, error) {
if len(value) == 0 || value == "<nil>" {
value = "0"
}
v, err := strconv.Atoi(value)
if err != nil {
return 0, err
}
return v, nil
}
func (b *BareMetalServer) unmarshalStr(value string) string {
if value == "<nil>" {
value = ""
}
return value
}
// AppInfo retrieves the application information for a given server ID
func (b *BareMetalServerServiceHandler) AppInfo(ctx context.Context, serverID string) (*AppInfo, error) {
uri := "/v1/baremetal/get_app_info"
req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("SUBID", serverID)
req.URL.RawQuery = q.Encode()
appInfo := new(AppInfo)
err = b.client.DoWithContext(ctx, req, appInfo)
if err != nil {
return nil, err
}
return appInfo, nil
}
// Bandwidth will get the bandwidth used by a bare metal server
func (b *BareMetalServerServiceHandler) Bandwidth(ctx context.Context, serverID string) ([]map[string]string, error) {
uri := "/v1/baremetal/bandwidth"
req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("SUBID", serverID)
req.URL.RawQuery = q.Encode()
var bandwidthMap map[string][][]interface{}
err = b.client.DoWithContext(ctx, req, &bandwidthMap)
if err != nil {
return nil, err
}
var bandwidth []map[string]string
for _, b := range bandwidthMap["incoming_bytes"] {
inMap := make(map[string]string)
inMap["date"] = fmt.Sprintf("%v", b[0])
var bytes int64
switch b[1].(type) {
case float64:
bytes = int64(b[1].(float64))
case int64:
bytes = b[1].(int64)
}
inMap["incoming"] = fmt.Sprintf("%v", bytes)
bandwidth = append(bandwidth, inMap)
}
for _, b := range bandwidthMap["outgoing_bytes"] {
for i := range bandwidth {
if bandwidth[i]["date"] == b[0] {
var bytes int64
switch b[1].(type) {
case float64:
bytes = int64(b[1].(float64))
case int64:
bytes = b[1].(int64)
}
bandwidth[i]["outgoing"] = fmt.Sprintf("%v", bytes)
break
}
}
}
return bandwidth, nil
}
// ChangeApp changes the bare metal server to a different application.
func (b *BareMetalServerServiceHandler) ChangeApp(ctx context.Context, serverID, appID string) error {
uri := "/v1/baremetal/app_change"
values := url.Values{
"SUBID": {serverID},
"APPID": {appID},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = b.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// ChangeOS changes the bare metal server to a different operating system. All data will be permanently lost.
func (b *BareMetalServerServiceHandler) ChangeOS(ctx context.Context, serverID, osID string) error {
uri := "/v1/baremetal/os_change"
values := url.Values{
"SUBID": {serverID},
"OSID": {osID},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = b.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// Create a new bare metal server.
func (b *BareMetalServerServiceHandler) Create(ctx context.Context, regionID, planID, osID string, options *BareMetalServerOptions) (*BareMetalServer, error) {
uri := "/v1/baremetal/create"
values := url.Values{
"DCID": {regionID},
"METALPLANID": {planID},
"OSID": {osID},
}
if options != nil {
if options.StartupScriptID != "" {
values.Add("SCRIPTID", options.StartupScriptID)
}
if options.SnapshotID != "" {
values.Add("SNAPSHOTID", options.SnapshotID)
}
if options.EnableIPV6 != "" {
values.Add("enable_ipv6", options.EnableIPV6)
}
if options.Label != "" {
values.Add("label", options.Label)
}
if options.SSHKeyIDs != nil && len(options.SSHKeyIDs) != 0 {
values.Add("SSHKEYID", strings.Join(options.SSHKeyIDs, ","))
}
if options.AppID != "" {
values.Add("APPID", options.AppID)
}
if options.UserData != "" {
values.Add("userdata", base64.StdEncoding.EncodeToString([]byte(options.UserData)))
}
if options.NotifyActivate != "" {
values.Add("notify_activate", options.NotifyActivate)
}
if options.Hostname != "" {
values.Add("hostname", options.Hostname)
}
if options.Tag != "" {
values.Add("tag", options.Tag)
}
if options.ReservedIPV4 != "" {
values.Add("reserved_ip_v4", options.ReservedIPV4)
}
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return nil, err
}
bm := new(BareMetalServer)
err = b.client.DoWithContext(ctx, req, bm)
if err != nil {
return nil, err
}
return bm, nil
}
// Delete a bare metal server.
// All data will be permanently lost, and the IP address will be released. There is no going back from this call.
func (b *BareMetalServerServiceHandler) Delete(ctx context.Context, serverID string) error {
uri := "/v1/baremetal/destroy"
values := url.Values{
"SUBID": {serverID},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = b.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// EnableIPV6 enables IPv6 networking on a bare metal server by assigning an IPv6 subnet to it.
// The server will not be rebooted when the subnet is assigned.
func (b *BareMetalServerServiceHandler) EnableIPV6(ctx context.Context, serverID string) error {
uri := "/v1/baremetal/ipv6_enable"
values := url.Values{
"SUBID": {serverID},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = b.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// List lists all bare metal servers on the current account. This includes both pending and active servers.
func (b *BareMetalServerServiceHandler) List(ctx context.Context) ([]BareMetalServer, error) {
return b.list(ctx, "", "")
}
// ListByLabel lists all bare metal servers that match the given label on the current account. This includes both pending and active servers.
func (b *BareMetalServerServiceHandler) ListByLabel(ctx context.Context, label string) ([]BareMetalServer, error) {
return b.list(ctx, "label", label)
}
// ListByMainIP lists all bare metal servers that match the given IP address on the current account. This includes both pending and active servers.
func (b *BareMetalServerServiceHandler) ListByMainIP(ctx context.Context, mainIP string) ([]BareMetalServer, error) {
return b.list(ctx, "main_ip", mainIP)
}
// ListByTag lists all bare metal servers that match the given tag on the current account. This includes both pending and active servers.
func (b *BareMetalServerServiceHandler) ListByTag(ctx context.Context, tag string) ([]BareMetalServer, error) {
return b.list(ctx, "tag", tag)
}
func (b *BareMetalServerServiceHandler) list(ctx context.Context, key, value string) ([]BareMetalServer, error) {
uri := "/v1/baremetal/list"
req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
if key != "" {
q := req.URL.Query()
q.Add(key, value)
req.URL.RawQuery = q.Encode()
}
bmsMap := make(map[string]BareMetalServer)
err = b.client.DoWithContext(ctx, req, &bmsMap)
if err != nil {
return nil, err
}
var bms []BareMetalServer
for _, bm := range bmsMap {
bms = append(bms, bm)
}
return bms, nil
}
// GetServer gets the server with the given ID
func (b *BareMetalServerServiceHandler) GetServer(ctx context.Context, serverID string) (*BareMetalServer, error) {
uri := "/v1/baremetal/list"
req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("SUBID", serverID)
req.URL.RawQuery = q.Encode()
bms := new(BareMetalServer)
err = b.client.DoWithContext(ctx, req, bms)
if err != nil {
return nil, err
}
return bms, nil
}
// GetUserData retrieves the (base64 encoded) user-data for this bare metal server
func (b *BareMetalServerServiceHandler) GetUserData(ctx context.Context, serverID string) (*UserData, error) {
uri := "/v1/baremetal/get_user_data"
req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("SUBID", serverID)
req.URL.RawQuery = q.Encode()
userData := new(UserData)
err = b.client.DoWithContext(ctx, req, userData)
if err != nil {
return nil, err
}
return userData, nil
}
// Halt a bare metal server.
// This is a hard power off, meaning that the power to the machine is severed.
// The data on the machine will not be modified, and you will still be billed for the machine.
func (b *BareMetalServerServiceHandler) Halt(ctx context.Context, serverID string) error {
uri := "/v1/baremetal/halt"
values := url.Values{
"SUBID": {serverID},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = b.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// IPV4Info will List the IPv4 information of a bare metal server.
// IP information is only available for bare metal servers in the "active" state.
func (b *BareMetalServerServiceHandler) IPV4Info(ctx context.Context, serverID string) ([]BareMetalServerIPV4, error) {
uri := "/v1/baremetal/list_ipv4"
req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("SUBID", serverID)
req.URL.RawQuery = q.Encode()
var ipMap map[string][]BareMetalServerIPV4
err = b.client.DoWithContext(ctx, req, &ipMap)
if err != nil {
return nil, err
}
var ipv4 []BareMetalServerIPV4
for _, i := range ipMap {
ipv4 = i
}
return ipv4, nil
}
// IPV6Info ists the IPv6 information of a bare metal server.
// IP information is only available for bare metal servers in the "active" state.
// If the bare metal server does not have IPv6 enabled, then an empty array is returned.
func (b *BareMetalServerServiceHandler) IPV6Info(ctx context.Context, serverID string) ([]BareMetalServerIPV6, error) {
uri := "/v1/baremetal/list_ipv6"
req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("SUBID", serverID)
req.URL.RawQuery = q.Encode()
var ipMap map[string][]BareMetalServerIPV6
err = b.client.DoWithContext(ctx, req, &ipMap)
if err != nil {
return nil, err
}
var ipv6 []BareMetalServerIPV6
for _, i := range ipMap {
ipv6 = i
}
return ipv6, nil
}
// ListApps retrieves a list of Vultr one-click applications to which a bare metal server can be changed.
// Always check against this list before trying to switch applications because it is not possible to switch between every application combination.
func (b *BareMetalServerServiceHandler) ListApps(ctx context.Context, serverID string) ([]Application, error) {
uri := "/v1/baremetal/app_change_list"
req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("SUBID", serverID)
req.URL.RawQuery = q.Encode()
var appMap map[string]Application
err = b.client.DoWithContext(ctx, req, &appMap)
if err != nil {
return nil, err
}
var appList []Application
for _, a := range appMap {
appList = append(appList, a)
}
return appList, nil
}
// ListOS retrieves a list of operating systems to which a bare metal server can be changed.
// Always check against this list before trying to switch operating systems because it is not possible to switch between every operating system combination.
func (b *BareMetalServerServiceHandler) ListOS(ctx context.Context, serverID string) ([]OS, error) {
uri := "/v1/baremetal/os_change_list"
req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("SUBID", serverID)
req.URL.RawQuery = q.Encode()
var osMap map[string]OS
err = b.client.DoWithContext(ctx, req, &osMap)
if err != nil {
return nil, err
}
var os []OS
for _, o := range osMap {
os = append(os, o)
}
return os, nil
}
// Reboot a bare metal server. This is a hard reboot, which means that the server is powered off, then back on.
func (b *BareMetalServerServiceHandler) Reboot(ctx context.Context, serverID string) error {
uri := "/v1/baremetal/reboot"
values := url.Values{
"SUBID": {serverID},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = b.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// Reinstall the operating system on a bare metal server.
// All data will be permanently lost, but the IP address will remain the same. There is no going back from this call.
func (b *BareMetalServerServiceHandler) Reinstall(ctx context.Context, serverID string) error {
uri := "/v1/baremetal/reinstall"
values := url.Values{
"SUBID": {serverID},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = b.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// SetLabel sets the label of a bare metal server.
func (b *BareMetalServerServiceHandler) SetLabel(ctx context.Context, serverID, label string) error {
uri := "/v1/baremetal/label_set"
values := url.Values{
"SUBID": {serverID},
"label": {label},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = b.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// SetTag sets the tag of a bare metal server.
func (b *BareMetalServerServiceHandler) SetTag(ctx context.Context, serverID, tag string) error {
uri := "/v1/baremetal/tag_set"
values := url.Values{
"SUBID": {serverID},
"tag": {tag},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = b.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// SetUserData sets the user-data for this server.
// User-data is a generic data store, which some provisioning tools and cloud operating systems use as a configuration file.
// It is generally consumed only once after an instance has been launched, but individual needs may vary.
func (b *BareMetalServerServiceHandler) SetUserData(ctx context.Context, serverID, userData string) error {
uri := "/v1/baremetal/set_user_data"
encodedUserData := base64.StdEncoding.EncodeToString([]byte(userData))
values := url.Values{
"SUBID": {serverID},
"userdata": {encodedUserData},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = b.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}

319
vendor/github.com/vultr/govultr/block_storage.go generated vendored Normal file
View file

@ -0,0 +1,319 @@
package govultr
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
)
// BlockStorageService is the interface to interact with Block-Storage endpoint on the Vultr API
// Link: https://www.vultr.com/api/#block
type BlockStorageService interface {
Attach(ctx context.Context, blockID, InstanceID string) error
Create(ctx context.Context, regionID, size int, label string) (*BlockStorage, error)
Delete(ctx context.Context, blockID string) error
Detach(ctx context.Context, blockID string) error
SetLabel(ctx context.Context, blockID, label string) error
List(ctx context.Context) ([]BlockStorage, error)
Get(ctx context.Context, blockID string) (*BlockStorage, error)
Resize(ctx context.Context, blockID string, size int) error
}
// BlockStorageServiceHandler handles interaction with the block-storage methods for the Vultr API
type BlockStorageServiceHandler struct {
client *Client
}
// BlockStorage represents Vultr Block-Storage
type BlockStorage struct {
BlockStorageID string `json:"SUBID"`
DateCreated string `json:"date_created"`
CostPerMonth string `json:"cost_per_month"`
Status string `json:"status"`
SizeGB int `json:"size_gb"`
RegionID int `json:"DCID"`
InstanceID string `json:"attached_to_SUBID"`
Label string `json:"label"`
}
// UnmarshalJSON implements json.Unmarshaller on BlockStorage to handle the inconsistent types returned from the Vultr v1 API.
func (b *BlockStorage) UnmarshalJSON(data []byte) (err error) {
if b == nil {
*b = BlockStorage{}
}
var v map[string]interface{}
if err := json.Unmarshal(data, &v); err != nil {
return err
}
b.BlockStorageID, err = b.unmarshalStr(fmt.Sprintf("%v", v["SUBID"]))
if err != nil {
return err
}
b.RegionID, err = b.unmarshalInt(fmt.Sprintf("%v", v["DCID"]))
if err != nil {
return err
}
b.SizeGB, err = b.unmarshalInt(fmt.Sprintf("%v", v["size_gb"]))
if err != nil {
return err
}
b.InstanceID, err = b.unmarshalStr(fmt.Sprintf("%v", v["attached_to_SUBID"]))
if err != nil {
return err
}
b.CostPerMonth, err = b.unmarshalStr(fmt.Sprintf("%v", v["cost_per_month"]))
if err != nil {
return err
}
date := fmt.Sprintf("%v", v["date_created"])
if date == "<nil>" {
date = ""
}
b.DateCreated = date
status := fmt.Sprintf("%v", v["status"])
if status == "<nil>" {
status = ""
}
b.Status = status
b.Label = fmt.Sprintf("%v", v["label"])
return nil
}
func (b *BlockStorage) unmarshalInt(value string) (int, error) {
if len(value) == 0 || value == "<nil>" {
value = "0"
}
i, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return 0, err
}
return int(i), nil
}
func (b *BlockStorage) unmarshalStr(value string) (string, error) {
if len(value) == 0 || value == "<nil>" || value == "0" || value == "false" {
return "", nil
}
f, err := strconv.ParseFloat(value, 64)
if err != nil {
return "", err
}
return strconv.FormatFloat(f, 'f', -1, 64), nil
}
// Attach will link a given block storage to a given Vultr vps
func (b *BlockStorageServiceHandler) Attach(ctx context.Context, blockID, InstanceID string) error {
uri := "/v1/block/attach"
values := url.Values{
"SUBID": {blockID},
"attach_to_SUBID": {InstanceID},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = b.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// Create builds out a block storage
func (b *BlockStorageServiceHandler) Create(ctx context.Context, regionID, sizeGB int, label string) (*BlockStorage, error) {
uri := "/v1/block/create"
values := url.Values{
"DCID": {strconv.Itoa(regionID)},
"size_gb": {strconv.Itoa(sizeGB)},
"label": {label},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return nil, err
}
blockStorage := new(BlockStorage)
err = b.client.DoWithContext(ctx, req, blockStorage)
if err != nil {
return nil, err
}
blockStorage.RegionID = regionID
blockStorage.Label = label
blockStorage.SizeGB = sizeGB
return blockStorage, nil
}
// Delete will remove block storage instance from your Vultr account
func (b *BlockStorageServiceHandler) Delete(ctx context.Context, blockID string) error {
uri := "/v1/block/delete"
values := url.Values{
"SUBID": {blockID},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = b.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// Detach will de-link a given block storage to the Vultr vps it is attached to
func (b *BlockStorageServiceHandler) Detach(ctx context.Context, blockID string) error {
uri := "/v1/block/detach"
values := url.Values{
"SUBID": {blockID},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = b.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// SetLabel allows you to set/update the label on your Vultr Block storage
func (b *BlockStorageServiceHandler) SetLabel(ctx context.Context, blockID, label string) error {
uri := "/v1/block/label_set"
values := url.Values{
"SUBID": {blockID},
"label": {label},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = b.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// List returns a list of all block storage instances on your Vultr Account
func (b *BlockStorageServiceHandler) List(ctx context.Context) ([]BlockStorage, error) {
uri := "/v1/block/list"
req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
var blockStorage []BlockStorage
err = b.client.DoWithContext(ctx, req, &blockStorage)
if err != nil {
return nil, err
}
return blockStorage, nil
}
// Get returns a single block storage instance based ony our blockID you provide from your Vultr Account
func (b *BlockStorageServiceHandler) Get(ctx context.Context, blockID string) (*BlockStorage, error) {
uri := "/v1/block/list"
req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("SUBID", blockID)
req.URL.RawQuery = q.Encode()
blockStorage := new(BlockStorage)
err = b.client.DoWithContext(ctx, req, blockStorage)
if err != nil {
return nil, err
}
return blockStorage, nil
}
// Resize allows you to resize your Vultr block storage instance
func (b *BlockStorageServiceHandler) Resize(ctx context.Context, blockID string, sizeGB int) error {
uri := "/v1/block/resize"
values := url.Values{
"SUBID": {blockID},
"size_gb": {strconv.Itoa(sizeGB)},
}
req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = b.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}

209
vendor/github.com/vultr/govultr/dns_domains.go generated vendored Normal file
View file

@ -0,0 +1,209 @@
package govultr
import (
"context"
"net/http"
"net/url"
)
// DNSDomainService is the interface to interact with the DNS endpoints on the Vultr API
// Link: https://www.vultr.com/api/#dns
type DNSDomainService interface {
Create(ctx context.Context, domain, InstanceIP string) error
Delete(ctx context.Context, domain string) error
ToggleDNSSec(ctx context.Context, domain string, enabled bool) error
DNSSecInfo(ctx context.Context, domain string) ([]string, error)
List(ctx context.Context) ([]DNSDomain, error)
GetSoa(ctx context.Context, domain string) (*Soa, error)
UpdateSoa(ctx context.Context, domain, nsPrimary, email string) error
}
// DNSDomainServiceHandler handles interaction with the DNS methods for the Vultr API
type DNSDomainServiceHandler struct {
client *Client
}
// DNSDomain represents a DNS Domain entry on Vultr
type DNSDomain struct {
Domain string `json:"domain"`
DateCreated string `json:"date_created"`
}
// Soa represents record information for a domain on Vultr
type Soa struct {
NsPrimary string `json:"nsprimary"`
Email string `json:"email"`
}
// Create will create a DNS Domain entry on Vultr
func (d *DNSDomainServiceHandler) Create(ctx context.Context, domain, InstanceIP string) error {
uri := "/v1/dns/create_domain"
values := url.Values{
"domain": {domain},
"serverip": {InstanceIP},
}
req, err := d.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = d.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
//Delete will delete a domain name and all associated records
func (d *DNSDomainServiceHandler) Delete(ctx context.Context, domain string) error {
uri := "/v1/dns/delete_domain"
values := url.Values{
"domain": {domain},
}
req, err := d.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = d.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// ToggleDNSSec will enable or disable DNSSEC for a domain on Vultr
func (d *DNSDomainServiceHandler) ToggleDNSSec(ctx context.Context, domain string, enabled bool) error {
uri := "/v1/dns/dnssec_enable"
enable := "no"
if enabled == true {
enable = "yes"
}
values := url.Values{
"domain": {domain},
"enable": {enable},
}
req, err := d.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = d.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// DNSSecInfo gets the DNSSec keys for a domain (if enabled)
func (d *DNSDomainServiceHandler) DNSSecInfo(ctx context.Context, domain string) ([]string, error) {
uri := "/v1/dns/dnssec_info"
req, err := d.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("domain", domain)
req.URL.RawQuery = q.Encode()
var DNSSec []string
err = d.client.DoWithContext(ctx, req, &DNSSec)
if err != nil {
return nil, err
}
return DNSSec, nil
}
// List gets all domains associated with the current Vultr account.
func (d *DNSDomainServiceHandler) List(ctx context.Context) ([]DNSDomain, error) {
uri := "/v1/dns/list"
req, err := d.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
var dnsDomains []DNSDomain
err = d.client.DoWithContext(ctx, req, &dnsDomains)
if err != nil {
return nil, err
}
return dnsDomains, nil
}
// GetSoa gets the SOA record information for a domain
func (d *DNSDomainServiceHandler) GetSoa(ctx context.Context, domain string) (*Soa, error) {
uri := "/v1/dns/soa_info"
req, err := d.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("domain", domain)
req.URL.RawQuery = q.Encode()
soa := new(Soa)
err = d.client.DoWithContext(ctx, req, soa)
if err != nil {
return nil, err
}
return soa, nil
}
// UpdateSoa will update the SOA record information for a domain.
func (d *DNSDomainServiceHandler) UpdateSoa(ctx context.Context, domain, nsPrimary, email string) error {
uri := "/v1/dns/soa_update"
values := url.Values{
"domain": {domain},
"nsprimary": {nsPrimary},
"email": {email},
}
req, err := d.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = d.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}

150
vendor/github.com/vultr/govultr/dns_records.go generated vendored Normal file
View file

@ -0,0 +1,150 @@
package govultr
import (
"context"
"net/http"
"net/url"
"strconv"
)
// DNSRecordService is the interface to interact with the DNS Records endpoints on the Vultr API
// Link: https://www.vultr.com/api/#dns
type DNSRecordService interface {
Create(ctx context.Context, domain, recordType, name, data string, ttl, priority int) error
Delete(ctx context.Context, domain, recordID string) error
List(ctx context.Context, domain string) ([]DNSRecord, error)
Update(ctx context.Context, domain string, dnsRecord *DNSRecord) error
}
// DNSRecordsServiceHandler handles interaction with the DNS Records methods for the Vultr API
type DNSRecordsServiceHandler struct {
client *Client
}
// DNSRecord represents a DNS record on Vultr
type DNSRecord struct {
RecordID int `json:"RECORDID"`
Type string `json:"type"`
Name string `json:"name"`
Data string `json:"data"`
Priority int `json:"priority"`
TTL int `json:"ttl"`
}
// Create will add a DNS record.
func (d *DNSRecordsServiceHandler) Create(ctx context.Context, domain, recordType, name, data string, ttl, priority int) error {
uri := "/v1/dns/create_record"
values := url.Values{
"domain": {domain},
"name": {name},
"type": {recordType},
"data": {data},
"ttl": {strconv.Itoa(ttl)},
"priority": {strconv.Itoa(priority)},
}
req, err := d.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = d.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// Delete will delete a domain name and all associated records.
func (d *DNSRecordsServiceHandler) Delete(ctx context.Context, domain, recordID string) error {
uri := "/v1/dns/delete_record"
values := url.Values{
"domain": {domain},
"RECORDID": {recordID},
}
req, err := d.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = d.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// List will list all the records associated with a particular domain on Vultr
func (d *DNSRecordsServiceHandler) List(ctx context.Context, domain string) ([]DNSRecord, error) {
uri := "/v1/dns/records"
req, err := d.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("domain", domain)
req.URL.RawQuery = q.Encode()
var dnsRecord []DNSRecord
err = d.client.DoWithContext(ctx, req, &dnsRecord)
if err != nil {
return nil, err
}
return dnsRecord, nil
}
// Update will update a DNS record
func (d *DNSRecordsServiceHandler) Update(ctx context.Context, domain string, dnsRecord *DNSRecord) error {
uri := "/v1/dns/update_record"
values := url.Values{
"domain": {domain},
"RECORDID": {strconv.Itoa(dnsRecord.RecordID)},
}
// Optional
if dnsRecord.Name != "" {
values.Add("name", dnsRecord.Name)
}
if dnsRecord.Data != "" {
values.Add("data", dnsRecord.Data)
}
if dnsRecord.TTL != 0 {
values.Add("ttl", strconv.Itoa(dnsRecord.TTL))
}
if dnsRecord.Priority != 0 {
values.Add("priority", strconv.Itoa(dnsRecord.Priority))
}
req, err := d.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = d.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}

163
vendor/github.com/vultr/govultr/firewall_group.go generated vendored Normal file
View file

@ -0,0 +1,163 @@
package govultr
import (
"context"
"net/http"
"net/url"
)
// FirewallGroupService is the interface to interact with the firewall group endpoints on the Vultr API
// Link: https://www.vultr.com/api/#firewall
type FirewallGroupService interface {
Create(ctx context.Context, description string) (*FirewallGroup, error)
Delete(ctx context.Context, groupID string) error
List(ctx context.Context) ([]FirewallGroup, error)
Get(ctx context.Context, groupID string) (*FirewallGroup, error)
ChangeDescription(ctx context.Context, groupID, description string) error
}
// FireWallGroupServiceHandler handles interaction with the firewall group methods for the Vultr API
type FireWallGroupServiceHandler struct {
client *Client
}
// FirewallGroup represents a Vultr firewall group
type FirewallGroup struct {
FirewallGroupID string `json:"FIREWALLGROUPID"`
Description string `json:"description"`
DateCreated string `json:"date_created"`
DateModified string `json:"date_modified"`
InstanceCount int `json:"instance_count"`
RuleCount int `json:"rule_count"`
MaxRuleCount int `json:"max_rule_count"`
}
// Create will create a new firewall group on your Vultr account
func (f *FireWallGroupServiceHandler) Create(ctx context.Context, description string) (*FirewallGroup, error) {
uri := "/v1/firewall/group_create"
values := url.Values{
"description": {description},
}
req, err := f.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return nil, err
}
firewall := new(FirewallGroup)
err = f.client.DoWithContext(ctx, req, firewall)
if err != nil {
return nil, err
}
return firewall, nil
}
// Delete will delete a firewall group from your Vultr account
func (f *FireWallGroupServiceHandler) Delete(ctx context.Context, groupID string) error {
uri := "/v1/firewall/group_delete"
values := url.Values{
"FIREWALLGROUPID": {groupID},
}
req, err := f.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = f.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// List will return a list of all firewall groups on your Vultr account
func (f *FireWallGroupServiceHandler) List(ctx context.Context) ([]FirewallGroup, error) {
uri := "/v1/firewall/group_list"
req, err := f.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
var firewallGroupMap map[string]FirewallGroup
err = f.client.DoWithContext(ctx, req, &firewallGroupMap)
if err != nil {
return nil, err
}
var firewallGroup []FirewallGroup
for _, f := range firewallGroupMap {
firewallGroup = append(firewallGroup, f)
}
return firewallGroup, nil
}
// Get will return a firewall group based on provided groupID from your Vultr account
func (f *FireWallGroupServiceHandler) Get(ctx context.Context, groupID string) (*FirewallGroup, error) {
uri := "/v1/firewall/group_list"
req, err := f.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("FIREWALLGROUPID", groupID)
req.URL.RawQuery = q.Encode()
var firewallGroupMap map[string]FirewallGroup
err = f.client.DoWithContext(ctx, req, &firewallGroupMap)
if err != nil {
return nil, err
}
firewallGroup := new(FirewallGroup)
for _, f := range firewallGroupMap {
firewallGroup = &f
}
return firewallGroup, nil
}
// ChangeDescription will change the description of a firewall group
func (f *FireWallGroupServiceHandler) ChangeDescription(ctx context.Context, groupID, description string) error {
uri := "/v1/firewall/group_set_description"
values := url.Values{
"FIREWALLGROUPID": {groupID},
"description": {description},
}
req, err := f.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = f.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}

265
vendor/github.com/vultr/govultr/firewall_rule.go generated vendored Normal file
View file

@ -0,0 +1,265 @@
package govultr
import (
"context"
"encoding/json"
"errors"
"fmt"
"net"
"net/http"
"net/url"
"strconv"
)
// FireWallRuleService is the interface to interact with the firewall rule endpoints on the Vultr API
// Link: https://www.vultr.com/api/#firewall
type FireWallRuleService interface {
Create(ctx context.Context, groupID, protocol, port, network, notes string) (*FirewallRule, error)
Delete(ctx context.Context, groupID, ruleID string) error
ListByIPType(ctx context.Context, groupID, ipType string) ([]FirewallRule, error)
List(ctx context.Context, groupID string) ([]FirewallRule, error)
}
// FireWallRuleServiceHandler handles interaction with the firewall rule methods for the Vultr API
type FireWallRuleServiceHandler struct {
client *Client
}
// FirewallRule represents a Vultr firewall rule
type FirewallRule struct {
RuleNumber int `json:"rulenumber"`
Action string `json:"action"`
Protocol string `json:"protocol"`
Port string `json:"port"`
Network *net.IPNet `json:"network"`
Notes string `json:"notes"`
}
// UnmarshalJSON implements a custom unmarshaler on FirewallRule
// This is done to help reduce data inconsistency with V1 of the Vultr API
// It also merges the subnet & subnet_mask into a single type of *net.IPNet
func (f *FirewallRule) UnmarshalJSON(data []byte) (err error) {
if f == nil {
*f = FirewallRule{}
}
// Pull out all of the data that was given to us and put it into a map
var fields map[string]interface{}
err = json.Unmarshal(data, &fields)
if err != nil {
return err
}
// Unmarshal RuleNumber
value := fmt.Sprintf("%v", fields["rulenumber"])
number, _ := strconv.Atoi(value)
f.RuleNumber = number
// Unmarshal all other strings
action := fmt.Sprintf("%v", fields["action"])
if action == "<nil>" {
action = ""
}
f.Action = action
protocol := fmt.Sprintf("%v", fields["protocol"])
if protocol == "<nil>" {
protocol = ""
}
f.Protocol = protocol
port := fmt.Sprintf("%v", fields["port"])
if port == "<nil>" {
port = ""
}
f.Port = port
notes := fmt.Sprintf("%v", fields["notes"])
if notes == "<nil>" {
notes = ""
}
f.Notes = notes
// Unmarshal subnet_size & subnet and convert to *net.IP
value = fmt.Sprintf("%v", fields["subnet_size"])
if len(value) == 0 || value == "<nil>" {
value = "0"
}
subnetSize, _ := strconv.Atoi(value)
subnet := fmt.Sprintf("%v", fields["subnet"])
if subnet == "<nil>" {
subnet = ""
}
if len(subnet) > 0 {
_, ipNet, err := net.ParseCIDR(fmt.Sprintf("%s/%d", subnet, subnetSize))
if err != nil {
return errors.New("an issue has occurred while parsing subnet")
}
f.Network = ipNet
}
return
}
// Create will create a rule in a firewall group.
func (f *FireWallRuleServiceHandler) Create(ctx context.Context, groupID, protocol, port, cdirBlock, notes string) (*FirewallRule, error) {
uri := "/v1/firewall/rule_create"
ip, ipNet, err := net.ParseCIDR(cdirBlock)
if err != nil {
return nil, err
}
values := url.Values{
"FIREWALLGROUPID": {groupID},
"direction": {"in"},
"protocol": {protocol},
"subnet": {ip.String()},
}
// mask
mask, _ := ipNet.Mask.Size()
values.Add("subnet_size", strconv.Itoa(mask))
// ip Type
if ipNet.IP.To4() != nil {
values.Add("ip_type", "v4")
} else {
values.Add("ip_type", "v6")
}
// Optional params
if port != "" {
values.Add("port", port)
}
if notes != "" {
values.Add("notes", notes)
}
req, err := f.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return nil, err
}
firewallRule := new(FirewallRule)
err = f.client.DoWithContext(ctx, req, firewallRule)
if err != nil {
return nil, err
}
return firewallRule, nil
}
// Delete will delete a firewall rule on your Vultr account
func (f *FireWallRuleServiceHandler) Delete(ctx context.Context, groupID, ruleID string) error {
uri := "/v1/firewall/rule_delete"
values := url.Values{
"FIREWALLGROUPID": {groupID},
"rulenumber": {ruleID},
}
req, err := f.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = f.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// List will list the current firewall rules in a firewall group.
// ipType values that can be passed in are "v4", "v6"
func (f *FireWallRuleServiceHandler) ListByIPType(ctx context.Context, groupID, ipType string) ([]FirewallRule, error) {
uri := "/v1/firewall/rule_list"
req, err := f.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("FIREWALLGROUPID", groupID)
q.Add("direction", "in")
q.Add("ip_type", ipType)
req.URL.RawQuery = q.Encode()
var firewallRuleMap map[string]FirewallRule
err = f.client.DoWithContext(ctx, req, &firewallRuleMap)
if err != nil {
return nil, err
}
var firewallRule []FirewallRule
for _, f := range firewallRuleMap {
firewallRule = append(firewallRule, f)
}
return firewallRule, nil
}
// List will return both ipv4 an ipv6 firewall rules that are defined within a firewall group
func (f *FireWallRuleServiceHandler) List(ctx context.Context, groupID string) ([]FirewallRule, error) {
uri := "/v1/firewall/rule_list"
req, err := f.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("FIREWALLGROUPID", groupID)
q.Add("direction", "in")
q.Add("ip_type", "v4")
req.URL.RawQuery = q.Encode()
var firewallRuleMap map[string]FirewallRule
// V4 call
err = f.client.DoWithContext(ctx, req, &firewallRuleMap)
if err != nil {
return nil, err
}
// V6 call
q.Del("ip_type")
q.Add("ip_type", "v6")
req.URL.RawQuery = q.Encode()
err = f.client.DoWithContext(ctx, req, &firewallRuleMap)
if err != nil {
return nil, err
}
var firewallRule []FirewallRule
for _, f := range firewallRuleMap {
firewallRule = append(firewallRule, f)
}
return firewallRule, nil
}

222
vendor/github.com/vultr/govultr/govultr.go generated vendored Normal file
View file

@ -0,0 +1,222 @@
package govultr
import (
"context"
"encoding/json"
"errors"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
)
const (
version = "0.1.4"
defaultBase = "https://api.vultr.com"
userAgent = "govultr/" + version
rateLimit = 600 * time.Millisecond
)
// APIKey contains a users API Key for interacting with the API
type APIKey struct {
// API Key
key string
}
// Client manages interaction with the Vultr V1 API
type Client struct {
// Http Client used to interact with the Vultr V1 API
client *http.Client
// BASE URL for APIs
BaseURL *url.URL
// User Agent for the client
UserAgent string
// API Key
APIKey APIKey
// API Rate Limit - Vultr rate limits based on time
RateLimit time.Duration
// Services used to interact with the API
Account AccountService
API APIService
Application ApplicationService
Backup BackupService
BareMetalServer BareMetalServerService
BlockStorage BlockStorageService
DNSDomain DNSDomainService
DNSRecord DNSRecordService
FirewallGroup FirewallGroupService
FirewallRule FireWallRuleService
ISO ISOService
Network NetworkService
OS OSService
Plan PlanService
Region RegionService
ReservedIP ReservedIPService
Server ServerService
Snapshot SnapshotService
SSHKey SSHKeyService
StartupScript StartupScriptService
User UserService
// Optional function called after every successful request made to the Vultr API
onRequestCompleted RequestCompletionCallback
}
// RequestCompletionCallback defines the type of the request callback function
type RequestCompletionCallback func(*http.Request, *http.Response)
// NewClient returns a Vultr API Client
func NewClient(httpClient *http.Client, key string) *Client {
if httpClient == nil {
httpClient = http.DefaultClient
}
baseURL, _ := url.Parse(defaultBase)
client := &Client{
client: httpClient,
BaseURL: baseURL,
UserAgent: userAgent,
RateLimit: rateLimit,
}
client.Account = &AccountServiceHandler{client}
client.API = &APIServiceHandler{client}
client.Application = &ApplicationServiceHandler{client}
client.Backup = &BackupServiceHandler{client}
client.BareMetalServer = &BareMetalServerServiceHandler{client}
client.BlockStorage = &BlockStorageServiceHandler{client}
client.DNSDomain = &DNSDomainServiceHandler{client}
client.DNSRecord = &DNSRecordsServiceHandler{client}
client.FirewallGroup = &FireWallGroupServiceHandler{client}
client.FirewallRule = &FireWallRuleServiceHandler{client}
client.ISO = &ISOServiceHandler{client}
client.Network = &NetworkServiceHandler{client}
client.OS = &OSServiceHandler{client}
client.Plan = &PlanServiceHandler{client}
client.Region = &RegionServiceHandler{client}
client.Server = &ServerServiceHandler{client}
client.ReservedIP = &ReservedIPServiceHandler{client}
client.Snapshot = &SnapshotServiceHandler{client}
client.SSHKey = &SSHKeyServiceHandler{client}
client.StartupScript = &StartupScriptServiceHandler{client}
client.User = &UserServiceHandler{client}
apiKey := APIKey{key: key}
client.APIKey = apiKey
return client
}
// NewRequest creates an API Request
func (c *Client) NewRequest(ctx context.Context, method, uri string, body url.Values) (*http.Request, error) {
path, err := url.Parse(uri)
resolvedURL := c.BaseURL.ResolveReference(path)
if err != nil {
return nil, err
}
var reqBody io.Reader
if body != nil {
reqBody = strings.NewReader(body.Encode())
} else {
reqBody = nil
}
req, err := http.NewRequest(method, resolvedURL.String(), reqBody)
if err != nil {
return nil, err
}
req.Header.Add("API-key", c.APIKey.key)
req.Header.Add("User-Agent", c.UserAgent)
req.Header.Add("Accept", "application/json")
if req.Method == "POST" {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
return req, nil
}
// DoWithContext sends an API Request and returns back the response. The API response is checked to see if it was
// a successful call. A successful call is then checked to see if we need to unmarshal since some resources
// have their own implements of unmarshal.
func (c *Client) DoWithContext(ctx context.Context, r *http.Request, data interface{}) error {
// Sleep this call
time.Sleep(c.RateLimit)
req := r.WithContext(ctx)
res, err := c.client.Do(req)
if c.onRequestCompleted != nil {
c.onRequestCompleted(req, res)
}
if err != nil {
return err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
if res.StatusCode == http.StatusOK {
if data != nil {
if string(body) == "[]" {
data = nil
} else {
if err := json.Unmarshal(body, data); err != nil {
return err
}
}
}
return nil
}
return errors.New(string(body))
}
// SetBaseURL Overrides the default BaseUrl
func (c *Client) SetBaseURL(baseURL string) error {
updatedURL, err := url.Parse(baseURL)
if err != nil {
return err
}
c.BaseURL = updatedURL
return nil
}
// SetRateLimit Overrides the default rateLimit
func (c *Client) SetRateLimit(time time.Duration) {
c.RateLimit = time
}
// SetUserAgent Overrides the default UserAgent
func (c *Client) SetUserAgent(ua string) {
c.UserAgent = ua
}
// OnRequestCompleted sets the API request completion callback
func (c *Client) OnRequestCompleted(rc RequestCompletionCallback) {
c.onRequestCompleted = rc
}

142
vendor/github.com/vultr/govultr/iso.go generated vendored Normal file
View file

@ -0,0 +1,142 @@
package govultr
import (
"context"
"net/http"
"net/url"
"strconv"
)
// ISOService is the interface to interact with the ISO endpoints on the Vultr API
// Link: https://www.vultr.com/api/#ISO
type ISOService interface {
CreateFromURL(ctx context.Context, ISOURL string) (*ISO, error)
Delete(ctx context.Context, ISOID int) error
List(ctx context.Context) ([]ISO, error)
GetPublicList(ctx context.Context) ([]PublicISO, error)
}
// ISOServiceHandler handles interaction with the ISO methods for the Vultr API
type ISOServiceHandler struct {
Client *Client
}
// ISO represents ISOs currently available on this account.
type ISO struct {
ISOID int `json:"ISOID"`
DateCreated string `json:"date_created"`
FileName string `json:"filename"`
Size int `json:"size"`
MD5Sum string `json:"md5sum"`
SHA512Sum string `json:"sha512sum"`
Status string `json:"status"`
}
// PublicISO represents public ISOs offered in the Vultr ISO library.
type PublicISO struct {
ISOID int `json:"ISOID"`
Name string `json:"name"`
Description string `json:"description"`
}
// CreateFromURL will create a new ISO image on your account
func (i *ISOServiceHandler) CreateFromURL(ctx context.Context, ISOURL string) (*ISO, error) {
uri := "/v1/iso/create_from_url"
values := url.Values{
"url": {ISOURL},
}
req, err := i.Client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return nil, err
}
iso := new(ISO)
err = i.Client.DoWithContext(ctx, req, iso)
if err != nil {
return nil, err
}
return iso, nil
}
// Delete will delete an ISO image from your account
func (i *ISOServiceHandler) Delete(ctx context.Context, isoID int) error {
uri := "/v1/iso/destroy"
values := url.Values{
"ISOID": {strconv.Itoa(isoID)},
}
req, err := i.Client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = i.Client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// List will list all ISOs currently available on your account
func (i *ISOServiceHandler) List(ctx context.Context) ([]ISO, error) {
uri := "/v1/iso/list"
req, err := i.Client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
var ISOMap map[string]ISO
err = i.Client.DoWithContext(ctx, req, &ISOMap)
if err != nil {
return nil, err
}
var iso []ISO
for _, i := range ISOMap {
iso = append(iso, i)
}
return iso, nil
}
// GetPublicList will list public ISOs offered in the Vultr ISO library.
func (i *ISOServiceHandler) GetPublicList(ctx context.Context) ([]PublicISO, error) {
uri := "/v1/iso/list_public"
req, err := i.Client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
var ISOMap map[string]PublicISO
err = i.Client.DoWithContext(ctx, req, &ISOMap)
if err != nil {
return nil, err
}
var publicISO []PublicISO
for _, p := range ISOMap {
publicISO = append(publicISO, p)
}
return publicISO, nil
}

120
vendor/github.com/vultr/govultr/network.go generated vendored Normal file
View file

@ -0,0 +1,120 @@
package govultr
import (
"context"
"net"
"net/http"
"net/url"
"strconv"
)
// NetworkService is the interface to interact with the network endpoints on the Vultr API
// Link: https://www.vultr.com/api/#network
type NetworkService interface {
Create(ctx context.Context, regionID, description, cidrBlock string) (*Network, error)
Delete(ctx context.Context, networkID string) error
List(ctx context.Context) ([]Network, error)
}
// NetworkServiceHandler handles interaction with the network methods for the Vultr API
type NetworkServiceHandler struct {
client *Client
}
// Network represents a Vultr private network
type Network struct {
NetworkID string `json:"NETWORKID"`
RegionID string `json:"DCID"`
Description string `json:"description"`
V4Subnet string `json:"v4_subnet"`
V4SubnetMask int `json:"v4_subnet_mask"`
DateCreated string `json:"date_created"`
}
// Create a new private network. A private network can only be used at the location for which it was created.
func (n *NetworkServiceHandler) Create(ctx context.Context, regionID, description, cidrBlock string) (*Network, error) {
uri := "/v1/network/create"
values := url.Values{
"DCID": {regionID},
}
// Optional
if cidrBlock != "" {
_, ipNet, err := net.ParseCIDR(cidrBlock)
if err != nil {
return nil, err
}
if v4Subnet := ipNet.IP.To4(); v4Subnet != nil {
values.Add("v4_subnet", v4Subnet.String())
}
mask, _ := ipNet.Mask.Size()
values.Add("v4_subnet_mask", strconv.Itoa(mask))
}
if description != "" {
values.Add("description", description)
}
req, err := n.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return nil, err
}
network := new(Network)
err = n.client.DoWithContext(ctx, req, network)
if err != nil {
return nil, err
}
return network, nil
}
// Delete a private network. Before deleting, a network must be disabled from all instances. See https://www.vultr.com/api/#server_private_network_disable
func (n *NetworkServiceHandler) Delete(ctx context.Context, networkID string) error {
uri := "/v1/network/destroy"
values := url.Values{
"NETWORKID": {networkID},
}
req, err := n.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = n.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// List lists all private networks on the current account
func (n *NetworkServiceHandler) List(ctx context.Context) ([]Network, error) {
uri := "/v1/network/list"
req, err := n.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
var networkMap map[string]Network
err = n.client.DoWithContext(ctx, req, &networkMap)
if err != nil {
return nil, err
}
var networks []Network
for _, network := range networkMap {
networks = append(networks, network)
}
return networks, nil
}

84
vendor/github.com/vultr/govultr/os.go generated vendored Normal file
View file

@ -0,0 +1,84 @@
package govultr
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strconv"
)
// OSService is the interface to interact with the operating system endpoint on the Vultr API
// Link: https://www.vultr.com/api/#os
type OSService interface {
List(ctx context.Context) ([]OS, error)
}
// OSServiceHandler handles interaction with the operating system methods for the Vultr API
type OSServiceHandler struct {
client *Client
}
// OS represents a Vultr operating system
type OS struct {
OsID int `json:"OSID"`
Name string `json:"name"`
Arch string `json:"arch"`
Family string `json:"family"`
Windows bool `json:"windows"`
}
// UnmarshalJSON implements json.Unmarshaller on OS to handle the inconsistent types returned from the Vultr API.
func (o *OS) UnmarshalJSON(data []byte) (err error) {
if o == nil {
*o = OS{}
}
var v map[string]interface{}
if err := json.Unmarshal(data, &v); err != nil {
return err
}
i, err := strconv.Atoi(fmt.Sprintf("%v", v["OSID"]))
if err != nil {
return err
}
o.OsID = i
value := fmt.Sprintf("%v", v["windows"])
o.Windows = false
if value == "true" {
o.Windows = true
}
o.Name = fmt.Sprintf("%v", v["name"])
o.Arch = fmt.Sprintf("%v", v["arch"])
o.Family = fmt.Sprintf("%v", v["family"])
return nil
}
// List retrieves a list of available operating systems.
// If the Windows flag is true, a Windows license will be included with the instance, which will increase the cost.
func (o *OSServiceHandler) List(ctx context.Context) ([]OS, error) {
uri := "/v1/os/list"
req, err := o.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
osMap := make(map[string]OS)
err = o.client.DoWithContext(ctx, req, &osMap)
if err != nil {
return nil, err
}
var oses []OS
for _, os := range osMap {
oses = append(oses, os)
}
return oses, nil
}

199
vendor/github.com/vultr/govultr/plans.go generated vendored Normal file
View file

@ -0,0 +1,199 @@
package govultr
import (
"context"
"net/http"
)
// PlanService is the interface to interact with the Plans endpoints on the Vultr API
// Link: https://www.vultr.com/api/#plans
type PlanService interface {
List(ctx context.Context, planType string) ([]Plan, error)
GetBareMetalList(ctx context.Context) ([]BareMetalPlan, error)
GetVc2List(ctx context.Context) ([]VCPlan, error)
GetVdc2List(ctx context.Context) ([]VCPlan, error)
GetVc2zList(ctx context.Context) ([]VCPlan, error)
}
// PlanServiceHandler handles interaction with the Plans methods for the Vultr API
type PlanServiceHandler struct {
Client *Client
}
// Plan represents available Plans that Vultr offers
type Plan struct {
PlanID int `json:"VPSPLANID,string"`
Name string `json:"name"`
VCPUs int `json:"vcpu_count,string"`
RAM string `json:"ram"`
Disk string `json:"disk"`
Bandwidth string `json:"bandwidth"`
BandwidthGB string `json:"bandwidth_gb"`
Price string `json:"price_per_month"`
Windows bool `json:"windows"`
PlanType string `json:"plan_type"`
Regions []int `json:"available_locations"`
Deprecated bool `json:"deprecated"`
}
// BareMetalPlan represents bare metal plans
type BareMetalPlan struct {
PlanID string `json:"METALPLANID"`
Name string `json:"name"`
CPUs int `json:"cpu_count"`
CPUModel string `json:"cpu_model"`
RAM int `json:"ram"`
Disk string `json:"disk"`
BandwidthTB int `json:"bandwidth_tb"`
Price int `json:"price_per_month"`
PlanType string `json:"plan_type"`
Deprecated bool `json:"deprecated"`
Regions []int `json:"available_locations"`
}
// VCPlan represents either a vdc2 or a vc2 plan
type VCPlan struct {
PlanID string `json:"VPSPLANID"`
Name string `json:"name"`
VCPUs string `json:"vcpu_count"`
RAM string `json:"ram"`
Disk string `json:"disk"`
Bandwidth string `json:"bandwidth"`
BandwidthGB string `json:"bandwidth_gb"`
Price string `json:"price_per_month"`
PlanType string `json:"plan_type"`
}
// List retrieves a list of all active plans.
// planType is optional - pass an empty string to get all plans
func (p *PlanServiceHandler) List(ctx context.Context, planType string) ([]Plan, error) {
uri := "/v1/plans/list"
req, err := p.Client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
if planType != "" {
q := req.URL.Query()
q.Add("type", planType)
req.URL.RawQuery = q.Encode()
}
var planMap map[string]Plan
err = p.Client.DoWithContext(ctx, req, &planMap)
if err != nil {
return nil, err
}
var plans []Plan
for _, p := range planMap {
plans = append(plans, p)
}
return plans, nil
}
// GetBareMetalList retrieves a list of all active bare metal plans.
func (p *PlanServiceHandler) GetBareMetalList(ctx context.Context) ([]BareMetalPlan, error) {
uri := "/v1/plans/list_baremetal"
req, err := p.Client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
var bareMetalMap map[string]BareMetalPlan
err = p.Client.DoWithContext(ctx, req, &bareMetalMap)
if err != nil {
return nil, err
}
var bareMetalPlan []BareMetalPlan
for _, b := range bareMetalMap {
bareMetalPlan = append(bareMetalPlan, b)
}
return bareMetalPlan, nil
}
// GetVc2List retrieve a list of all active vc2 plans.
func (p *PlanServiceHandler) GetVc2List(ctx context.Context) ([]VCPlan, error) {
uri := "/v1/plans/list_vc2"
req, err := p.Client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
var vc2Plan map[string]VCPlan
err = p.Client.DoWithContext(ctx, req, &vc2Plan)
if err != nil {
return nil, err
}
var vc2 []VCPlan
for _, p := range vc2Plan {
vc2 = append(vc2, p)
}
return vc2, nil
}
// GetVdc2List Retrieve a list of all active vdc2 plans
func (p *PlanServiceHandler) GetVdc2List(ctx context.Context) ([]VCPlan, error) {
uri := "/v1/plans/list_vdc2"
req, err := p.Client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
var vdc2Map map[string]VCPlan
err = p.Client.DoWithContext(ctx, req, &vdc2Map)
if err != nil {
return nil, err
}
var vdc2 []VCPlan
for _, p := range vdc2Map {
vdc2 = append(vdc2, p)
}
return vdc2, nil
}
// GetVc2zList Retrieve a list of all active vc2z plans (high frequency)
func (p *PlanServiceHandler) GetVc2zList(ctx context.Context) ([]VCPlan, error) {
uri := "/v1/plans/list_vc2z"
req, err := p.Client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
var vc2zMap map[string]VCPlan
err = p.Client.DoWithContext(ctx, req, &vc2zMap)
if err != nil {
return nil, err
}
var vc2z []VCPlan
for _, p := range vc2zMap {
vc2z = append(vc2z, p)
}
return vc2z, nil
}

154
vendor/github.com/vultr/govultr/regions.go generated vendored Normal file
View file

@ -0,0 +1,154 @@
package govultr
import (
"context"
"net/http"
"strconv"
)
// RegionService is the interface to interact with Region endpoints on the Vultr API
// Link: https://www.vultr.com/api/#regions
type RegionService interface {
Availability(ctx context.Context, regionID int, planType string) ([]int, error)
BareMetalAvailability(ctx context.Context, regionID int) ([]int, error)
Vc2Availability(ctx context.Context, regionID int) ([]int, error)
Vdc2Availability(ctx context.Context, regionID int) ([]int, error)
List(ctx context.Context) ([]Region, error)
}
// RegionServiceHandler handles interaction with the region methods for the Vultr API
type RegionServiceHandler struct {
Client *Client
}
// Region represents a Vultr region
type Region struct {
RegionID string `json:"DCID"`
Name string `json:"name"`
Country string `json:"country"`
Continent string `json:"continent"`
State string `json:"state"`
Ddos bool `json:"ddos_protection"`
BlockStorage bool `json:"block_storage"`
RegionCode string `json:"regioncode"`
}
// Availability retrieves a list of the VPSPLANIDs currently available for a given location.
func (r *RegionServiceHandler) Availability(ctx context.Context, regionID int, planType string) ([]int, error) {
uri := "/v1/regions/availability"
req, err := r.Client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("DCID", strconv.Itoa(regionID))
// Optional planType filter
if planType != "" {
q.Add("type", planType)
}
req.URL.RawQuery = q.Encode()
var regions []int
err = r.Client.DoWithContext(ctx, req, &regions)
if err != nil {
return nil, err
}
return regions, nil
}
// BareMetalAvailability retrieve a list of the METALPLANIDs currently available for a given location.
func (r *RegionServiceHandler) BareMetalAvailability(ctx context.Context, regionID int) ([]int, error) {
uri := "/v1/regions/availability_baremetal"
regions, err := r.instanceAvailability(ctx, uri, regionID)
if err != nil {
return nil, err
}
return regions, nil
}
// Vc2Availability retrieve a list of the vc2 VPSPLANIDs currently available for a given location.
func (r *RegionServiceHandler) Vc2Availability(ctx context.Context, regionID int) ([]int, error) {
uri := "/v1/regions/availability_vc2"
regions, err := r.instanceAvailability(ctx, uri, regionID)
if err != nil {
return nil, err
}
return regions, nil
}
// Vdc2Availability retrieves a list of the vdc2 VPSPLANIDs currently available for a given location.
func (r *RegionServiceHandler) Vdc2Availability(ctx context.Context, regionID int) ([]int, error) {
uri := "/v1/regions/availability_vdc2"
regions, err := r.instanceAvailability(ctx, uri, regionID)
if err != nil {
return nil, err
}
return regions, nil
}
// List retrieves a list of all active regions
func (r *RegionServiceHandler) List(ctx context.Context) ([]Region, error) {
uri := "/v1/regions/list"
req, err := r.Client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
var regionsMap map[string]Region
err = r.Client.DoWithContext(ctx, req, &regionsMap)
if err != nil {
return nil, err
}
var region []Region
for _, r := range regionsMap {
region = append(region, r)
}
return region, nil
}
// instanceAvailability keeps the similar calls dry
func (r *RegionServiceHandler) instanceAvailability(ctx context.Context, uri string, regionID int) ([]int, error) {
req, err := r.Client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("DCID", strconv.Itoa(regionID))
req.URL.RawQuery = q.Encode()
var regions []int
err = r.Client.DoWithContext(ctx, req, &regions)
if err != nil {
return nil, err
}
return regions, nil
}

273
vendor/github.com/vultr/govultr/reserved_ip.go generated vendored Normal file
View file

@ -0,0 +1,273 @@
package govultr
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
)
// ReservedIPService is the interface to interact with the reserved IP endpoints on the Vultr API
// Link: https://www.vultr.com/api/#reservedip
type ReservedIPService interface {
Attach(ctx context.Context, ip, InstanceID string) error
Convert(ctx context.Context, ip, InstanceID, label string) (*ReservedIP, error)
Create(ctx context.Context, regionID int, ipType, label string) (*ReservedIP, error)
Delete(ctx context.Context, ip string) error
Detach(ctx context.Context, ip, InstanceID string) error
List(ctx context.Context) ([]ReservedIP, error)
}
// ReservedIPServiceHandler handles interaction with the reserved IP methods for the Vultr API
type ReservedIPServiceHandler struct {
client *Client
}
// ReservedIP represents an reserved IP on Vultr
type ReservedIP struct {
ReservedIPID string `json:"SUBID"`
RegionID int `json:"DCID"`
IPType string `json:"ip_type"`
Subnet string `json:"subnet"`
SubnetSize int `json:"subnet_size"`
Label string `json:"label"`
AttachedID string `json:"attached_SUBID"`
}
// UnmarshalJSON implements json.Unmarshaller on ReservedIP to handle the inconsistent types returned from the Vultr API.
func (r *ReservedIP) UnmarshalJSON(data []byte) (err error) {
if r == nil {
*r = ReservedIP{}
}
var v map[string]interface{}
if err := json.Unmarshal(data, &v); err != nil {
return err
}
r.ReservedIPID, err = r.unmarshalStr(fmt.Sprintf("%v", v["SUBID"]))
if err != nil {
return err
}
r.AttachedID, err = r.unmarshalStr(fmt.Sprintf("%v", v["attached_SUBID"]))
if err != nil {
return err
}
r.RegionID, err = r.unmarshalInt(fmt.Sprintf("%v", v["DCID"]))
if err != nil {
return err
}
r.SubnetSize, err = r.unmarshalInt(fmt.Sprintf("%v", v["subnet_size"]))
if err != nil {
return err
}
if r.Subnet = fmt.Sprintf("%v", v["subnet"]); r.Subnet == "<nil>" {
r.Subnet = ""
}
if r.IPType = fmt.Sprintf("%v", v["ip_type"]); r.IPType == "<nil>" {
r.IPType = ""
}
if r.Label = fmt.Sprintf("%v", v["label"]); r.Label == "<nil>" {
r.Label = ""
}
return nil
}
func (r *ReservedIP) unmarshalInt(value string) (int, error) {
if len(value) == 0 || value == "<nil>" {
value = "0"
}
i, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return 0, err
}
return int(i), nil
}
func (r *ReservedIP) unmarshalStr(value string) (string, error) {
if len(value) == 0 || value == "<nil>" || value == "0" || value == "false" {
return "", nil
}
f, err := strconv.ParseFloat(value, 64)
if err != nil {
return "", err
}
return strconv.FormatFloat(f, 'f', -1, 64), nil
}
// Attach a reserved IP to an existing subscription
func (r *ReservedIPServiceHandler) Attach(ctx context.Context, ip, InstanceID string) error {
uri := "/v1/reservedip/attach"
values := url.Values{
"ip_address": {ip},
"attach_SUBID": {InstanceID},
}
req, err := r.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = r.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// Convert an existing IP on a subscription to a reserved IP.
func (r *ReservedIPServiceHandler) Convert(ctx context.Context, ip, InstanceID, label string) (*ReservedIP, error) {
uri := "/v1/reservedip/convert"
values := url.Values{
"SUBID": {InstanceID},
"ip_address": {ip},
}
if label != "" {
values.Add("label", label)
}
req, err := r.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return nil, err
}
rip := new(ReservedIP)
err = r.client.DoWithContext(ctx, req, rip)
if err != nil {
return nil, err
}
rip.Label = label
return rip, nil
}
// Create adds the specified reserved IP to your Vultr account
func (r *ReservedIPServiceHandler) Create(ctx context.Context, regionID int, ipType, label string) (*ReservedIP, error) {
uri := "/v1/reservedip/create"
values := url.Values{
"DCID": {strconv.Itoa(regionID)},
"ip_type": {ipType},
}
if label != "" {
values.Add("label", label)
}
req, err := r.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return nil, err
}
rip := new(ReservedIP)
err = r.client.DoWithContext(ctx, req, rip)
if err != nil {
return nil, err
}
rip.RegionID = regionID
rip.IPType = ipType
rip.Label = label
return rip, nil
}
// Delete removes the specified reserved IP from your Vultr account
func (r *ReservedIPServiceHandler) Delete(ctx context.Context, ip string) error {
uri := "/v1/reservedip/destroy"
values := url.Values{
"ip_address": {ip},
}
req, err := r.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = r.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// Detach a reserved IP from an existing subscription.
func (r *ReservedIPServiceHandler) Detach(ctx context.Context, ip, InstanceID string) error {
uri := "/v1/reservedip/detach"
values := url.Values{
"ip_address": {ip},
"detach_SUBID": {InstanceID},
}
req, err := r.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = r.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// List lists all the reserved IPs associated with your Vultr account
func (r *ReservedIPServiceHandler) List(ctx context.Context) ([]ReservedIP, error) {
uri := "/v1/reservedip/list"
req, err := r.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
ipMap := make(map[string]ReservedIP)
err = r.client.DoWithContext(ctx, req, &ipMap)
if err != nil {
return nil, err
}
var ips []ReservedIP
for _, ip := range ipMap {
ips = append(ips, ip)
}
return ips, nil
}

1469
vendor/github.com/vultr/govultr/server.go generated vendored Normal file

File diff suppressed because it is too large Load diff

168
vendor/github.com/vultr/govultr/snapshot.go generated vendored Normal file
View file

@ -0,0 +1,168 @@
package govultr
import (
"context"
"net/http"
"net/url"
)
// SnapshotService is the interface to interact with Snapshot endpoints on the Vultr API
// Link: https://www.vultr.com/api/#snapshot
type SnapshotService interface {
Create(ctx context.Context, InstanceID, description string) (*Snapshot, error)
CreateFromURL(ctx context.Context, snapshotURL string) (*Snapshot, error)
Delete(ctx context.Context, snapshotID string) error
List(ctx context.Context) ([]Snapshot, error)
Get(ctx context.Context, snapshotID string) (*Snapshot, error)
}
// SnapshotServiceHandler handles interaction with the snapshot methods for the Vultr API
type SnapshotServiceHandler struct {
Client *Client
}
// Snapshot represents a Vultr snapshot
type Snapshot struct {
SnapshotID string `json:"SNAPSHOTID"`
DateCreated string `json:"date_created"`
Description string `json:"description"`
Size string `json:"size"`
Status string `json:"status"`
OsID string `json:"OSID"`
AppID string `json:"APPID"`
}
// Snapshots represent a collection of snapshots
type Snapshots []Snapshot
// Create makes a snapshot of a provided server
func (s *SnapshotServiceHandler) Create(ctx context.Context, InstanceID, description string) (*Snapshot, error) {
uri := "/v1/snapshot/create"
values := url.Values{
"SUBID": {InstanceID},
"description": {description},
}
req, err := s.Client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return nil, err
}
snapshot := new(Snapshot)
err = s.Client.DoWithContext(ctx, req, snapshot)
if err != nil {
return nil, err
}
snapshot.Description = description
return snapshot, nil
}
// CreateFromURL will create a snapshot based on an image iso from a URL you provide
func (s *SnapshotServiceHandler) CreateFromURL(ctx context.Context, snapshotURL string) (*Snapshot, error) {
uri := "/v1/snapshot/create_from_url"
values := url.Values{
"url": {snapshotURL},
}
req, err := s.Client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return nil, err
}
snapshot := new(Snapshot)
err = s.Client.DoWithContext(ctx, req, snapshot)
if err != nil {
return nil, err
}
return snapshot, nil
}
// Delete a snapshot based on snapshotID
func (s *SnapshotServiceHandler) Delete(ctx context.Context, snapshotID string) error {
uri := "/v1/snapshot/destroy"
values := url.Values{
"SNAPSHOTID": {snapshotID},
}
req, err := s.Client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = s.Client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// List of snapshots details
func (s *SnapshotServiceHandler) List(ctx context.Context) ([]Snapshot, error) {
uri := "/v1/snapshot/list"
req, err := s.Client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
snapshotMap := make(map[string]Snapshot)
err = s.Client.DoWithContext(ctx, req, &snapshotMap)
if err != nil {
return nil, err
}
var snapshots []Snapshot
for _, s := range snapshotMap {
snapshots = append(snapshots, s)
}
return snapshots, nil
}
// Get individual details of a snapshot based on snapshotID
func (s *SnapshotServiceHandler) Get(ctx context.Context, snapshotID string) (*Snapshot, error) {
uri := "/v1/snapshot/list"
req, err := s.Client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
if snapshotID != "" {
q := req.URL.Query()
q.Add("SNAPSHOTID", snapshotID)
req.URL.RawQuery = q.Encode()
}
snapshotMap := make(map[string]Snapshot)
err = s.Client.DoWithContext(ctx, req, &snapshotMap)
if err != nil {
return nil, err
}
snapshot := new(Snapshot)
for _, s := range snapshotMap {
snapshot = &s
}
return snapshot, nil
}

140
vendor/github.com/vultr/govultr/ssh_key.go generated vendored Normal file
View file

@ -0,0 +1,140 @@
package govultr
import (
"context"
"net/http"
"net/url"
)
// SSHKeyService is the interface to interact with the SSH Key endpoints on the Vultr API
// Link: https://www.vultr.com/api/#sshkey
type SSHKeyService interface {
Create(ctx context.Context, name, sshKey string) (*SSHKey, error)
Delete(ctx context.Context, sshKeyID string) error
List(ctx context.Context) ([]SSHKey, error)
Update(ctx context.Context, sshKey *SSHKey) error
}
// SSHKeyServiceHandler handles interaction with the SSH Key methods for the Vultr API
type SSHKeyServiceHandler struct {
client *Client
}
// SSHKey represents an SSH Key on Vultr
type SSHKey struct {
SSHKeyID string `json:"SSHKEYID"`
Name string `json:"name"`
Key string `json:"ssh_key"`
DateCreated string `json:"date_created"`
}
// Create will add the specified SSH Key to your Vultr account
func (s *SSHKeyServiceHandler) Create(ctx context.Context, name, sshKey string) (*SSHKey, error) {
uri := "/v1/sshkey/create"
values := url.Values{
"name": {name},
"ssh_key": {sshKey},
}
req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return nil, err
}
key := new(SSHKey)
err = s.client.DoWithContext(ctx, req, key)
if err != nil {
return nil, err
}
key.Name = name
key.Key = sshKey
return key, nil
}
// Delete will delete the specified SHH Key from your Vultr account
func (s *SSHKeyServiceHandler) Delete(ctx context.Context, sshKeyID string) error {
uri := "/v1/sshkey/destroy"
values := url.Values{
"SSHKEYID": {sshKeyID},
}
req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = s.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// List will list all the SSH Keys associated with your Vultr account
func (s *SSHKeyServiceHandler) List(ctx context.Context) ([]SSHKey, error) {
uri := "/v1/sshkey/list"
req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
sshKeysMap := make(map[string]SSHKey)
err = s.client.DoWithContext(ctx, req, &sshKeysMap)
if err != nil {
return nil, err
}
var sshKeys []SSHKey
for _, key := range sshKeysMap {
sshKeys = append(sshKeys, key)
}
return sshKeys, nil
}
// Update will update the given SSH Key. Empty strings will be ignored.
func (s *SSHKeyServiceHandler) Update(ctx context.Context, sshKey *SSHKey) error {
uri := "/v1/sshkey/update"
values := url.Values{
"SSHKEYID": {sshKey.SSHKeyID},
}
// Optional
if sshKey.Name != "" {
values.Add("name", sshKey.Name)
}
if sshKey.Key != "" {
values.Add("ssh_key", sshKey.Key)
}
req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = s.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}

172
vendor/github.com/vultr/govultr/startup_script.go generated vendored Normal file
View file

@ -0,0 +1,172 @@
package govultr
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
)
// StartupScriptService is the interface to interact with the startup script endpoints on the Vultr API
// Link: https://www.vultr.com/api/#startupscript
type StartupScriptService interface {
Create(ctx context.Context, name, script, scriptType string) (*StartupScript, error)
Delete(ctx context.Context, scriptID string) error
List(ctx context.Context) ([]StartupScript, error)
Update(ctx context.Context, script *StartupScript) error
}
// StartupScriptServiceHandler handles interaction with the startup script methods for the Vultr API
type StartupScriptServiceHandler struct {
client *Client
}
// StartupScript represents an startup script on Vultr
type StartupScript struct {
ScriptID string `json:"SCRIPTID"`
DateCreated string `json:"date_created"`
DateModified string `json:"date_modified"`
Name string `json:"name"`
Type string `json:"type"`
Script string `json:"script"`
}
// UnmarshalJSON implements json.Unmarshaller on StartupScript to handle the inconsistent types returned from the Vultr API.
func (s *StartupScript) UnmarshalJSON(data []byte) (err error) {
if s == nil {
*s = StartupScript{}
}
var v map[string]interface{}
if err := json.Unmarshal(data, &v); err != nil {
return err
}
s.ScriptID = fmt.Sprintf("%v", v["SCRIPTID"])
s.DateCreated = fmt.Sprintf("%v", v["date_created"])
s.DateModified = fmt.Sprintf("%v", v["date_modified"])
s.Name = fmt.Sprintf("%v", v["name"])
s.Type = fmt.Sprintf("%v", v["type"])
s.Script = fmt.Sprintf("%v", v["script"])
return nil
}
// Create will add the specified startup script to your Vultr account
func (s *StartupScriptServiceHandler) Create(ctx context.Context, name, script, scriptType string) (*StartupScript, error) {
uri := "/v1/startupscript/create"
values := url.Values{
"name": {name},
"script": {script},
}
if scriptType != "" {
values.Add("type", scriptType)
}
req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return nil, err
}
ss := new(StartupScript)
err = s.client.DoWithContext(ctx, req, ss)
if err != nil {
return nil, err
}
ss.DateCreated = ""
ss.DateModified = ""
ss.Name = name
ss.Type = scriptType
ss.Script = script
return ss, nil
}
// Delete will delete the specified startup script from your Vultr account
func (s *StartupScriptServiceHandler) Delete(ctx context.Context, scriptID string) error {
uri := "/v1/startupscript/destroy"
values := url.Values{
"SCRIPTID": {scriptID},
}
req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = s.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// List will list all the startup scripts associated with your Vultr account
func (s *StartupScriptServiceHandler) List(ctx context.Context) ([]StartupScript, error) {
uri := "/v1/startupscript/list"
req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
scriptsMap := make(map[string]StartupScript)
err = s.client.DoWithContext(ctx, req, &scriptsMap)
if err != nil {
return nil, err
}
var scripts []StartupScript
for _, key := range scriptsMap {
scripts = append(scripts, key)
}
return scripts, nil
}
// Update will update the given startup script. Empty strings will be ignored.
func (s *StartupScriptServiceHandler) Update(ctx context.Context, script *StartupScript) error {
uri := "/v1/startupscript/update"
values := url.Values{
"SCRIPTID": {script.ScriptID},
}
// Optional
if script.Name != "" {
values.Add("name", script.Name)
}
if script.Script != "" {
values.Add("script", script.Script)
}
req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = s.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}

157
vendor/github.com/vultr/govultr/user.go generated vendored Normal file
View file

@ -0,0 +1,157 @@
package govultr
import (
"context"
"net/http"
"net/url"
)
// UserService is the interface to interact with the user management endpoints on the Vultr API
// Link: https://www.vultr.com/api/#user
type UserService interface {
Create(ctx context.Context, email, name, password, apiEnabled string, acls []string) (*User, error)
Delete(ctx context.Context, userID string) error
List(ctx context.Context) ([]User, error)
Update(ctx context.Context, user *User) error
}
// UserServiceHandler handles interaction with the user methods for the Vultr API
type UserServiceHandler struct {
client *Client
}
// User represents an user on Vultr
type User struct {
UserID string `json:"USERID"`
Name string `json:"name"`
Email string `json:"email"`
Password string `json:"password"`
APIEnabled string `json:"api_enabled"`
ACL []string `json:"acls"`
APIKey string `json:"api_key"`
}
// Create will add the specified user to your Vultr account
func (u *UserServiceHandler) Create(ctx context.Context, email, name, password, apiEnabled string, acls []string) (*User, error) {
uri := "/v1/user/create"
values := url.Values{
"email": {email},
"name": {name},
"password": {password},
"acls[]": acls,
}
if apiEnabled != "" {
values.Add("api_enabled", apiEnabled)
}
req, err := u.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return nil, err
}
user := new(User)
err = u.client.DoWithContext(ctx, req, user)
if err != nil {
return nil, err
}
user.Name = name
user.Email = email
user.APIEnabled = apiEnabled
user.ACL = acls
return user, nil
}
// Delete will remove the specified user from your Vultr account
func (u *UserServiceHandler) Delete(ctx context.Context, userID string) error {
uri := "/v1/user/delete"
values := url.Values{
"USERID": {userID},
}
req, err := u.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = u.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}
// List will list all the users associated with your Vultr account
func (u *UserServiceHandler) List(ctx context.Context) ([]User, error) {
uri := "/v1/user/list"
req, err := u.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}
var users []User
err = u.client.DoWithContext(ctx, req, &users)
if err != nil {
return nil, err
}
return users, nil
}
// Update will update the given user. Empty strings will be ignored.
func (u *UserServiceHandler) Update(ctx context.Context, user *User) error {
uri := "/v1/user/update"
values := url.Values{
"USERID": {user.UserID},
}
// Optional
if user.Email != "" {
values.Add("email", user.Email)
}
if user.Name != "" {
values.Add("name", user.Name)
}
if user.Password != "" {
values.Add("password", user.Password)
}
if user.APIEnabled != "" {
values.Add("api_enabled", user.APIEnabled)
}
if len(user.ACL) > 0 {
for _, acl := range user.ACL {
values.Add("acls[]", acl)
}
}
req, err := u.client.NewRequest(ctx, http.MethodPost, uri, values)
if err != nil {
return err
}
err = u.client.DoWithContext(ctx, req, nil)
if err != nil {
return err
}
return nil
}