packer-cn/vendor/github.com/linode/linodego/client.go

392 lines
16 KiB
Go

package linodego
import (
"context"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strconv"
"time"
"github.com/go-resty/resty/v2"
)
const (
// APIHost Linode API hostname
APIHost = "api.linode.com"
// APIHostVar environment var to check for alternate API URL
APIHostVar = "LINODE_URL"
// APIHostCert environment var containing path to CA cert to validate against
APIHostCert = "LINODE_CA"
// APIVersion Linode API version
APIVersion = "v4"
// APIVersionVar environment var to check for alternate API Version
APIVersionVar = "LINODE_API_VERSION"
// APIProto connect to API with http(s)
APIProto = "https"
// Version of linodego
Version = "0.12.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
// Maximum wait time for retries
APIRetryMaxWaitTime = time.Duration(30) * time.Second
// 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
retryConditionals []RetryConditional
millisecondsPerPoll time.Duration
Account *Resource
AccountSettings *Resource
DomainRecords *Resource
Domains *Resource
Events *Resource
Firewalls *Resource
IPAddresses *Resource
IPv6Pools *Resource
IPv6Ranges *Resource
Images *Resource
InstanceConfigs *Resource
InstanceDisks *Resource
InstanceIPs *Resource
InstanceSnapshots *Resource
InstanceStats *Resource
InstanceVolumes *Resource
Instances *Resource
InvoiceItems *Resource
Invoices *Resource
Kernels *Resource
LKEClusters *Resource
LKEClusterPools *Resource
LKEVersions *Resource
Longview *Resource
LongviewClients *Resource
LongviewSubscriptions *Resource
Managed *Resource
NodeBalancerConfigs *Resource
NodeBalancerNodes *Resource
NodeBalancerStats *Resource
NodeBalancers *Resource
Notifications *Resource
OAuthClients *Resource
ObjectStorageBuckets *Resource
ObjectStorageClusters *Resource
ObjectStorageKeys *Resource
Payments *Resource
Profile *Resource
Regions *Resource
SSHKeys *Resource
StackScripts *Resource
Tags *Resource
Tickets *Resource
Token *Resource
Tokens *Resource
Types *Resource
Users *Resource
Volumes *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
}
// SetAPIVersion sets the version of the API to interface with
func (c *Client) SetAPIVersion(apiVersion string) *Client {
c.SetBaseURL(fmt.Sprintf("%s://%s/%s", APIProto, APIHost, apiVersion))
return c
}
// SetRootCertificate adds a root certificate to the underlying TLS client config
func (c *Client) SetRootCertificate(path string) *Client {
c.resty.SetRootCertificate(path)
return c
}
// SetToken sets the API token for all requests from this client
// Only necessary if you haven't already provided an http client to NewClient() configured with the token.
func (c *Client) SetToken(token string) *Client {
c.resty.SetHeader("Authorization", fmt.Sprintf("Bearer %s", token))
return c
}
// SetRetries adds retry conditions for "Linode Busy." errors and 429s.
func (c *Client) SetRetries() *Client {
c.
addRetryConditional(linodeBusyRetryCondition).
addRetryConditional(tooManyRequestsRetryCondition).
SetRetryMaxWaitTime(APIRetryMaxWaitTime)
configureRetries(c)
return c
}
func (c *Client) addRetryConditional(retryConditional RetryConditional) *Client {
c.retryConditionals = append(c.retryConditionals, retryConditional)
return c
}
func (c *Client) SetRetryMaxWaitTime(max time.Duration) *Client {
c.resty.SetRetryMaxWaitTime(max)
return c
}
// SetPollDelay sets the number of milliseconds to wait between events or status polls.
// Affects all WaitFor* functions and retries.
func (c *Client) SetPollDelay(delay time.Duration) *Client {
c.millisecondsPerPoll = delay
c.resty.SetRetryWaitTime(delay * time.Millisecond)
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) {
if hc != nil {
client.resty = resty.NewWithClient(hc)
} else {
client.resty = resty.New()
}
client.SetUserAgent(DefaultUserAgent)
baseURL, baseURLExists := os.LookupEnv(APIHostVar)
if baseURLExists {
client.SetBaseURL(baseURL)
} else {
apiVersion, apiVersionExists := os.LookupEnv(APIVersionVar)
if apiVersionExists {
client.SetAPIVersion(apiVersion)
} else {
client.SetAPIVersion(APIVersion)
}
}
certPath, certPathExists := os.LookupEnv(APIHostCert)
if certPathExists {
cert, err := ioutil.ReadFile(certPath)
if err != nil {
log.Fatalf("[ERROR] Error when reading cert at %s: %s\n", certPath, err.Error())
}
client.SetRootCertificate(certPath)
if envDebug {
log.Printf("[DEBUG] Set API root certificate to %s with contents %s\n", certPath, cert)
}
}
client.
SetPollDelay(1000 * APISecondsPerPoll).
SetRetries().
SetDebug(envDebug)
addResources(&client)
return
}
// nolint
func addResources(client *Client) {
resources := map[string]*Resource{
accountName: NewResource(client, accountName, accountEndpoint, false, Account{}, nil), // really?
accountSettingsName: NewResource(client, accountSettingsName, accountSettingsEndpoint, false, AccountSettings{}, nil), // really?
domainRecordsName: NewResource(client, domainRecordsName, domainRecordsEndpoint, true, DomainRecord{}, DomainRecordsPagedResponse{}),
domainsName: NewResource(client, domainsName, domainsEndpoint, false, Domain{}, DomainsPagedResponse{}),
eventsName: NewResource(client, eventsName, eventsEndpoint, false, Event{}, EventsPagedResponse{}),
firewallsName: NewResource(client, firewallsName, firewallsEndpoint, false, Firewall{}, FirewallsPagedResponse{}),
imagesName: NewResource(client, imagesName, imagesEndpoint, false, Image{}, ImagesPagedResponse{}),
instanceConfigsName: NewResource(client, instanceConfigsName, instanceConfigsEndpoint, true, InstanceConfig{}, InstanceConfigsPagedResponse{}),
instanceDisksName: NewResource(client, instanceDisksName, instanceDisksEndpoint, true, InstanceDisk{}, InstanceDisksPagedResponse{}),
instanceIPsName: NewResource(client, instanceIPsName, instanceIPsEndpoint, true, InstanceIP{}, nil), // really?
instanceSnapshotsName: NewResource(client, instanceSnapshotsName, instanceSnapshotsEndpoint, true, InstanceSnapshot{}, nil),
instanceStatsName: NewResource(client, instanceStatsName, instanceStatsEndpoint, true, InstanceStats{}, nil),
instanceVolumesName: NewResource(client, instanceVolumesName, instanceVolumesEndpoint, true, nil, InstanceVolumesPagedResponse{}), // really?
instancesName: NewResource(client, instancesName, instancesEndpoint, false, Instance{}, InstancesPagedResponse{}),
invoiceItemsName: NewResource(client, invoiceItemsName, invoiceItemsEndpoint, true, InvoiceItem{}, InvoiceItemsPagedResponse{}),
invoicesName: NewResource(client, invoicesName, invoicesEndpoint, false, Invoice{}, InvoicesPagedResponse{}),
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{}),
kernelsName: NewResource(client, kernelsName, kernelsEndpoint, false, LinodeKernel{}, LinodeKernelsPagedResponse{}),
lkeClustersName: NewResource(client, lkeClustersName, lkeClustersEndpoint, false, LKECluster{}, LKEClustersPagedResponse{}),
lkeClusterPoolsName: NewResource(client, lkeClusterPoolsName, lkeClusterPoolsEndpoint, true, LKEClusterPool{}, LKEClusterPoolsPagedResponse{}),
lkeVersionsName: NewResource(client, lkeVersionsName, lkeVersionsEndpoint, false, LKEVersion{}, LKEVersionsPagedResponse{}),
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{}),
managedName: NewResource(client, managedName, managedEndpoint, false, nil, nil), // really?
nodebalancerconfigsName: NewResource(client, nodebalancerconfigsName, nodebalancerconfigsEndpoint, true, NodeBalancerConfig{}, NodeBalancerConfigsPagedResponse{}),
nodebalancernodesName: NewResource(client, nodebalancernodesName, nodebalancernodesEndpoint, true, NodeBalancerNode{}, NodeBalancerNodesPagedResponse{}),
nodebalancerStatsName: NewResource(client, nodebalancerStatsName, nodebalancerStatsEndpoint, true, NodeBalancerStats{}, nil),
nodebalancersName: NewResource(client, nodebalancersName, nodebalancersEndpoint, false, NodeBalancer{}, NodeBalancerConfigsPagedResponse{}),
notificationsName: NewResource(client, notificationsName, notificationsEndpoint, false, Notification{}, NotificationsPagedResponse{}),
oauthClientsName: NewResource(client, oauthClientsName, oauthClientsEndpoint, false, OAuthClient{}, OAuthClientsPagedResponse{}),
objectStorageBucketsName: NewResource(client, objectStorageBucketsName, objectStorageBucketsEndpoint, false, ObjectStorageBucket{}, ObjectStorageBucketsPagedResponse{}),
objectStorageClustersName: NewResource(client, objectStorageClustersName, objectStorageClustersEndpoint, false, ObjectStorageCluster{}, ObjectStorageClustersPagedResponse{}),
objectStorageKeysName: NewResource(client, objectStorageKeysName, objectStorageKeysEndpoint, false, ObjectStorageKey{}, ObjectStorageKeysPagedResponse{}),
paymentsName: NewResource(client, paymentsName, paymentsEndpoint, false, Payment{}, PaymentsPagedResponse{}),
profileName: NewResource(client, profileName, profileEndpoint, false, nil, nil), // really?
regionsName: NewResource(client, regionsName, regionsEndpoint, false, Region{}, RegionsPagedResponse{}),
sshkeysName: NewResource(client, sshkeysName, sshkeysEndpoint, false, SSHKey{}, SSHKeysPagedResponse{}),
stackscriptsName: NewResource(client, stackscriptsName, stackscriptsEndpoint, false, Stackscript{}, StackscriptsPagedResponse{}),
tagsName: NewResource(client, tagsName, tagsEndpoint, false, Tag{}, TagsPagedResponse{}),
ticketsName: NewResource(client, ticketsName, ticketsEndpoint, false, Ticket{}, TicketsPagedResponse{}),
tokensName: NewResource(client, tokensName, tokensEndpoint, false, Token{}, TokensPagedResponse{}),
typesName: NewResource(client, typesName, typesEndpoint, false, LinodeType{}, LinodeTypesPagedResponse{}),
usersName: NewResource(client, usersName, usersEndpoint, false, User{}, UsersPagedResponse{}),
volumesName: NewResource(client, volumesName, volumesEndpoint, false, Volume{}, VolumesPagedResponse{}),
}
client.resources = resources
client.Account = resources[accountName]
client.DomainRecords = resources[domainRecordsName]
client.Domains = resources[domainsName]
client.Events = resources[eventsName]
client.Firewalls = resources[firewallsName]
client.IPAddresses = resources[ipaddressesName]
client.IPv6Pools = resources[ipv6poolsName]
client.IPv6Ranges = resources[ipv6rangesName]
client.Images = resources[imagesName]
client.InstanceConfigs = resources[instanceConfigsName]
client.InstanceDisks = resources[instanceDisksName]
client.InstanceIPs = resources[instanceIPsName]
client.InstanceSnapshots = resources[instanceSnapshotsName]
client.InstanceStats = resources[instanceStatsName]
client.InstanceVolumes = resources[instanceVolumesName]
client.Instances = resources[instancesName]
client.Invoices = resources[invoicesName]
client.Kernels = resources[kernelsName]
client.LKEClusters = resources[lkeClustersName]
client.LKEClusterPools = resources[lkeClusterPoolsName]
client.LKEVersions = resources[lkeVersionsName]
client.Longview = resources[longviewName]
client.LongviewSubscriptions = resources[longviewsubscriptionsName]
client.Managed = resources[managedName]
client.NodeBalancerConfigs = resources[nodebalancerconfigsName]
client.NodeBalancerNodes = resources[nodebalancernodesName]
client.NodeBalancerStats = resources[nodebalancerStatsName]
client.NodeBalancers = resources[nodebalancersName]
client.Notifications = resources[notificationsName]
client.OAuthClients = resources[oauthClientsName]
client.ObjectStorageBuckets = resources[objectStorageBucketsName]
client.ObjectStorageClusters = resources[objectStorageClustersName]
client.ObjectStorageKeys = resources[objectStorageKeysName]
client.Payments = resources[paymentsName]
client.Profile = resources[profileName]
client.Regions = resources[regionsName]
client.SSHKeys = resources[sshkeysName]
client.StackScripts = resources[stackscriptsName]
client.Tags = resources[tagsName]
client.Tickets = resources[ticketsName]
client.Tokens = resources[tokensName]
client.Types = resources[typesName]
client.Users = resources[usersName]
client.Volumes = resources[volumesName]
}
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
}