435c0d9fc8
This PR switches the Nomad repository from using govendor to Go modules for managing dependencies. Aspects of the Nomad workflow remain pretty much the same. The usual Makefile targets should continue to work as they always did. The API submodule simply defers to the parent Nomad version on the repository, keeping the semantics of API versioning that currently exists.
258 lines
10 KiB
Go
258 lines
10 KiB
Go
package linodego
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
"gopkg.in/resty.v1"
|
|
)
|
|
|
|
const (
|
|
// APIHost Linode API hostname
|
|
APIHost = "api.linode.com"
|
|
// APIVersion Linode API version
|
|
APIVersion = "v4"
|
|
// APIProto connect to API with http(s)
|
|
APIProto = "https"
|
|
// Version of linodego
|
|
Version = "0.7.0"
|
|
// APIEnvVar environment var to check for API token
|
|
APIEnvVar = "LINODE_TOKEN"
|
|
// APISecondsPerPoll how frequently to poll for new Events or Status in WaitFor functions
|
|
APISecondsPerPoll = 3
|
|
// DefaultUserAgent is the default User-Agent sent in HTTP request headers
|
|
DefaultUserAgent = "linodego " + Version + " https://github.com/linode/linodego"
|
|
)
|
|
|
|
var (
|
|
envDebug = false
|
|
)
|
|
|
|
// Client is a wrapper around the Resty client
|
|
type Client struct {
|
|
resty *resty.Client
|
|
userAgent string
|
|
resources map[string]*Resource
|
|
debug bool
|
|
|
|
millisecondsPerPoll time.Duration
|
|
|
|
Images *Resource
|
|
InstanceDisks *Resource
|
|
InstanceConfigs *Resource
|
|
InstanceSnapshots *Resource
|
|
InstanceIPs *Resource
|
|
InstanceVolumes *Resource
|
|
Instances *Resource
|
|
IPAddresses *Resource
|
|
IPv6Pools *Resource
|
|
IPv6Ranges *Resource
|
|
Regions *Resource
|
|
StackScripts *Resource
|
|
Volumes *Resource
|
|
Kernels *Resource
|
|
Types *Resource
|
|
Domains *Resource
|
|
DomainRecords *Resource
|
|
Longview *Resource
|
|
LongviewClients *Resource
|
|
LongviewSubscriptions *Resource
|
|
NodeBalancers *Resource
|
|
NodeBalancerConfigs *Resource
|
|
NodeBalancerNodes *Resource
|
|
SSHKeys *Resource
|
|
Tickets *Resource
|
|
Tokens *Resource
|
|
Token *Resource
|
|
Account *Resource
|
|
Invoices *Resource
|
|
InvoiceItems *Resource
|
|
Events *Resource
|
|
Notifications *Resource
|
|
Profile *Resource
|
|
Managed *Resource
|
|
Tags *Resource
|
|
Users *Resource
|
|
}
|
|
|
|
func init() {
|
|
// Wether or not we will enable Resty debugging output
|
|
if apiDebug, ok := os.LookupEnv("LINODE_DEBUG"); ok {
|
|
if parsed, err := strconv.ParseBool(apiDebug); err == nil {
|
|
envDebug = parsed
|
|
log.Println("[INFO] LINODE_DEBUG being set to", envDebug)
|
|
} else {
|
|
log.Println("[WARN] LINODE_DEBUG should be an integer, 0 or 1")
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// SetUserAgent sets a custom user-agent for HTTP requests
|
|
func (c *Client) SetUserAgent(ua string) *Client {
|
|
c.userAgent = ua
|
|
c.resty.SetHeader("User-Agent", c.userAgent)
|
|
|
|
return c
|
|
}
|
|
|
|
// R wraps resty's R method
|
|
func (c *Client) R(ctx context.Context) *resty.Request {
|
|
return c.resty.R().
|
|
ExpectContentType("application/json").
|
|
SetHeader("Content-Type", "application/json").
|
|
SetContext(ctx).
|
|
SetError(APIError{})
|
|
}
|
|
|
|
// SetDebug sets the debug on resty's client
|
|
func (c *Client) SetDebug(debug bool) *Client {
|
|
c.debug = debug
|
|
c.resty.SetDebug(debug)
|
|
return c
|
|
}
|
|
|
|
// SetBaseURL sets the base URL of the Linode v4 API (https://api.linode.com/v4)
|
|
func (c *Client) SetBaseURL(url string) *Client {
|
|
c.resty.SetHostURL(url)
|
|
return c
|
|
}
|
|
|
|
// SetPollDelay sets the number of milliseconds to wait between events or status polls.
|
|
// Affects all WaitFor* functions.
|
|
func (c *Client) SetPollDelay(delay time.Duration) *Client {
|
|
c.millisecondsPerPoll = delay
|
|
return c
|
|
}
|
|
|
|
// Resource looks up a resource by name
|
|
func (c Client) Resource(resourceName string) *Resource {
|
|
selectedResource, ok := c.resources[resourceName]
|
|
if !ok {
|
|
log.Fatalf("Could not find resource named '%s', exiting.", resourceName)
|
|
}
|
|
return selectedResource
|
|
}
|
|
|
|
// NewClient factory to create new Client struct
|
|
func NewClient(hc *http.Client) (client Client) {
|
|
restyClient := resty.NewWithClient(hc)
|
|
client.resty = restyClient
|
|
client.SetUserAgent(DefaultUserAgent)
|
|
client.SetBaseURL(fmt.Sprintf("%s://%s/%s", APIProto, APIHost, APIVersion))
|
|
client.SetPollDelay(1000 * APISecondsPerPoll)
|
|
|
|
resources := map[string]*Resource{
|
|
stackscriptsName: NewResource(&client, stackscriptsName, stackscriptsEndpoint, false, Stackscript{}, StackscriptsPagedResponse{}),
|
|
imagesName: NewResource(&client, imagesName, imagesEndpoint, false, Image{}, ImagesPagedResponse{}),
|
|
instancesName: NewResource(&client, instancesName, instancesEndpoint, false, Instance{}, InstancesPagedResponse{}),
|
|
instanceDisksName: NewResource(&client, instanceDisksName, instanceDisksEndpoint, true, InstanceDisk{}, InstanceDisksPagedResponse{}),
|
|
instanceConfigsName: NewResource(&client, instanceConfigsName, instanceConfigsEndpoint, true, InstanceConfig{}, InstanceConfigsPagedResponse{}),
|
|
instanceSnapshotsName: NewResource(&client, instanceSnapshotsName, instanceSnapshotsEndpoint, true, InstanceSnapshot{}, nil),
|
|
instanceIPsName: NewResource(&client, instanceIPsName, instanceIPsEndpoint, true, InstanceIP{}, nil), // really?
|
|
instanceVolumesName: NewResource(&client, instanceVolumesName, instanceVolumesEndpoint, true, nil, InstanceVolumesPagedResponse{}), // really?
|
|
ipaddressesName: NewResource(&client, ipaddressesName, ipaddressesEndpoint, false, nil, IPAddressesPagedResponse{}), // really?
|
|
ipv6poolsName: NewResource(&client, ipv6poolsName, ipv6poolsEndpoint, false, nil, IPv6PoolsPagedResponse{}), // really?
|
|
ipv6rangesName: NewResource(&client, ipv6rangesName, ipv6rangesEndpoint, false, IPv6Range{}, IPv6RangesPagedResponse{}),
|
|
regionsName: NewResource(&client, regionsName, regionsEndpoint, false, Region{}, RegionsPagedResponse{}),
|
|
volumesName: NewResource(&client, volumesName, volumesEndpoint, false, Volume{}, VolumesPagedResponse{}),
|
|
kernelsName: NewResource(&client, kernelsName, kernelsEndpoint, false, LinodeKernel{}, LinodeKernelsPagedResponse{}),
|
|
typesName: NewResource(&client, typesName, typesEndpoint, false, LinodeType{}, LinodeTypesPagedResponse{}),
|
|
domainsName: NewResource(&client, domainsName, domainsEndpoint, false, Domain{}, DomainsPagedResponse{}),
|
|
domainRecordsName: NewResource(&client, domainRecordsName, domainRecordsEndpoint, true, DomainRecord{}, DomainRecordsPagedResponse{}),
|
|
longviewName: NewResource(&client, longviewName, longviewEndpoint, false, nil, nil), // really?
|
|
longviewclientsName: NewResource(&client, longviewclientsName, longviewclientsEndpoint, false, LongviewClient{}, LongviewClientsPagedResponse{}),
|
|
longviewsubscriptionsName: NewResource(&client, longviewsubscriptionsName, longviewsubscriptionsEndpoint, false, LongviewSubscription{}, LongviewSubscriptionsPagedResponse{}),
|
|
nodebalancersName: NewResource(&client, nodebalancersName, nodebalancersEndpoint, false, NodeBalancer{}, NodeBalancerConfigsPagedResponse{}),
|
|
nodebalancerconfigsName: NewResource(&client, nodebalancerconfigsName, nodebalancerconfigsEndpoint, true, NodeBalancerConfig{}, NodeBalancerConfigsPagedResponse{}),
|
|
nodebalancernodesName: NewResource(&client, nodebalancernodesName, nodebalancernodesEndpoint, true, NodeBalancerNode{}, NodeBalancerNodesPagedResponse{}),
|
|
notificationsName: NewResource(&client, notificationsName, notificationsEndpoint, false, Notification{}, NotificationsPagedResponse{}),
|
|
sshkeysName: NewResource(&client, sshkeysName, sshkeysEndpoint, false, SSHKey{}, SSHKeysPagedResponse{}),
|
|
ticketsName: NewResource(&client, ticketsName, ticketsEndpoint, false, Ticket{}, TicketsPagedResponse{}),
|
|
tokensName: NewResource(&client, tokensName, tokensEndpoint, false, Token{}, TokensPagedResponse{}),
|
|
accountName: NewResource(&client, accountName, accountEndpoint, false, Account{}, nil), // really?
|
|
eventsName: NewResource(&client, eventsName, eventsEndpoint, false, Event{}, EventsPagedResponse{}),
|
|
invoicesName: NewResource(&client, invoicesName, invoicesEndpoint, false, Invoice{}, InvoicesPagedResponse{}),
|
|
invoiceItemsName: NewResource(&client, invoiceItemsName, invoiceItemsEndpoint, true, InvoiceItem{}, InvoiceItemsPagedResponse{}),
|
|
profileName: NewResource(&client, profileName, profileEndpoint, false, nil, nil), // really?
|
|
managedName: NewResource(&client, managedName, managedEndpoint, false, nil, nil), // really?
|
|
tagsName: NewResource(&client, tagsName, tagsEndpoint, false, Tag{}, TagsPagedResponse{}),
|
|
usersName: NewResource(&client, usersName, usersEndpoint, false, User{}, UsersPagedResponse{}),
|
|
}
|
|
|
|
client.resources = resources
|
|
|
|
client.SetDebug(envDebug)
|
|
client.Images = resources[imagesName]
|
|
client.StackScripts = resources[stackscriptsName]
|
|
client.Instances = resources[instancesName]
|
|
client.Regions = resources[regionsName]
|
|
client.InstanceDisks = resources[instanceDisksName]
|
|
client.InstanceConfigs = resources[instanceConfigsName]
|
|
client.InstanceSnapshots = resources[instanceSnapshotsName]
|
|
client.InstanceIPs = resources[instanceIPsName]
|
|
client.InstanceVolumes = resources[instanceVolumesName]
|
|
client.IPAddresses = resources[ipaddressesName]
|
|
client.IPv6Pools = resources[ipv6poolsName]
|
|
client.IPv6Ranges = resources[ipv6rangesName]
|
|
client.Volumes = resources[volumesName]
|
|
client.Kernels = resources[kernelsName]
|
|
client.Types = resources[typesName]
|
|
client.Domains = resources[domainsName]
|
|
client.DomainRecords = resources[domainRecordsName]
|
|
client.Longview = resources[longviewName]
|
|
client.LongviewSubscriptions = resources[longviewsubscriptionsName]
|
|
client.NodeBalancers = resources[nodebalancersName]
|
|
client.NodeBalancerConfigs = resources[nodebalancerconfigsName]
|
|
client.NodeBalancerNodes = resources[nodebalancernodesName]
|
|
client.Notifications = resources[notificationsName]
|
|
client.SSHKeys = resources[sshkeysName]
|
|
client.Tickets = resources[ticketsName]
|
|
client.Tokens = resources[tokensName]
|
|
client.Account = resources[accountName]
|
|
client.Events = resources[eventsName]
|
|
client.Invoices = resources[invoicesName]
|
|
client.Profile = resources[profileName]
|
|
client.Managed = resources[managedName]
|
|
client.Tags = resources[tagsName]
|
|
client.Users = resources[usersName]
|
|
return
|
|
}
|
|
|
|
func copyBool(bPtr *bool) *bool {
|
|
if bPtr == nil {
|
|
return nil
|
|
}
|
|
var t = *bPtr
|
|
return &t
|
|
}
|
|
|
|
func copyInt(iPtr *int) *int {
|
|
if iPtr == nil {
|
|
return nil
|
|
}
|
|
var t = *iPtr
|
|
return &t
|
|
}
|
|
|
|
func copyString(sPtr *string) *string {
|
|
if sPtr == nil {
|
|
return nil
|
|
}
|
|
var t = *sPtr
|
|
return &t
|
|
}
|
|
|
|
func copyTime(tPtr *time.Time) *time.Time {
|
|
if tPtr == nil {
|
|
return nil
|
|
}
|
|
var t = *tPtr
|
|
return &t
|
|
}
|