open-nomad/vendor/github.com/linode/linodego/resources.go
Seth Hoenig 435c0d9fc8 deps: Switch to Go modules for dependency management
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.
2020-06-02 14:30:36 -05:00

163 lines
5.8 KiB
Go

package linodego
import (
"bytes"
"context"
"fmt"
"text/template"
"gopkg.in/resty.v1"
)
const (
stackscriptsName = "stackscripts"
imagesName = "images"
instancesName = "instances"
instanceDisksName = "disks"
instanceConfigsName = "configs"
instanceIPsName = "ips"
instanceSnapshotsName = "snapshots"
instanceVolumesName = "instancevolumes"
ipaddressesName = "ipaddresses"
ipv6poolsName = "ipv6pools"
ipv6rangesName = "ipv6ranges"
regionsName = "regions"
volumesName = "volumes"
kernelsName = "kernels"
typesName = "types"
domainsName = "domains"
domainRecordsName = "records"
longviewName = "longview"
longviewclientsName = "longviewclients"
longviewsubscriptionsName = "longviewsubscriptions"
nodebalancersName = "nodebalancers"
nodebalancerconfigsName = "nodebalancerconfigs"
nodebalancernodesName = "nodebalancernodes"
notificationsName = "notifications"
sshkeysName = "sshkeys"
ticketsName = "tickets"
tokensName = "tokens"
accountName = "account"
eventsName = "events"
invoicesName = "invoices"
invoiceItemsName = "invoiceitems"
profileName = "profile"
managedName = "managed"
tagsName = "tags"
usersName = "users"
// notificationsName = "notifications"
stackscriptsEndpoint = "linode/stackscripts"
imagesEndpoint = "images"
instancesEndpoint = "linode/instances"
instanceConfigsEndpoint = "linode/instances/{{ .ID }}/configs"
instanceDisksEndpoint = "linode/instances/{{ .ID }}/disks"
instanceSnapshotsEndpoint = "linode/instances/{{ .ID }}/backups"
instanceIPsEndpoint = "linode/instances/{{ .ID }}/ips"
instanceVolumesEndpoint = "linode/instances/{{ .ID }}/volumes"
ipaddressesEndpoint = "networking/ips"
ipv6poolsEndpoint = "networking/ipv6/pools"
ipv6rangesEndpoint = "networking/ipv6/ranges"
regionsEndpoint = "regions"
volumesEndpoint = "volumes"
kernelsEndpoint = "linode/kernels"
typesEndpoint = "linode/types"
domainsEndpoint = "domains"
domainRecordsEndpoint = "domains/{{ .ID }}/records"
longviewEndpoint = "longview"
longviewclientsEndpoint = "longview/clients"
longviewsubscriptionsEndpoint = "longview/subscriptions"
nodebalancersEndpoint = "nodebalancers"
// @TODO we can't use these nodebalancer endpoints unless we include these templated fields
// The API seems inconsistent about including parent IDs in objects, (compare instance configs to nb configs)
// Parent IDs would be immutable for updates and are ignored in create requests ..
// Should we include these fields in CreateOpts and UpdateOpts?
nodebalancerconfigsEndpoint = "nodebalancers/{{ .ID }}/configs"
nodebalancernodesEndpoint = "nodebalancers/{{ .ID }}/configs/{{ .SecondID }}/nodes"
sshkeysEndpoint = "profile/sshkeys"
ticketsEndpoint = "support/tickets"
tokensEndpoint = "profile/tokens"
accountEndpoint = "account"
eventsEndpoint = "account/events"
invoicesEndpoint = "account/invoices"
invoiceItemsEndpoint = "account/invoices/{{ .ID }}/items"
profileEndpoint = "profile"
managedEndpoint = "managed"
tagsEndpoint = "tags"
usersEndpoint = "account/users"
notificationsEndpoint = "account/notifications"
)
// Resource represents a linode API resource
type Resource struct {
name string
endpoint string
isTemplate bool
endpointTemplate *template.Template
R func(ctx context.Context) *resty.Request
PR func(ctx context.Context) *resty.Request
}
// NewResource is the factory to create a new Resource struct. If it has a template string the useTemplate bool must be set.
func NewResource(client *Client, name string, endpoint string, useTemplate bool, singleType interface{}, pagedType interface{}) *Resource {
var tmpl *template.Template
if useTemplate {
tmpl = template.Must(template.New(name).Parse(endpoint))
}
r := func(ctx context.Context) *resty.Request {
return client.R(ctx).SetResult(singleType)
}
pr := func(ctx context.Context) *resty.Request {
return client.R(ctx).SetResult(pagedType)
}
return &Resource{name, endpoint, useTemplate, tmpl, r, pr}
}
func (r Resource) render(data ...interface{}) (string, error) {
if data == nil {
return "", NewError("Cannot template endpoint with <nil> data")
}
out := ""
buf := bytes.NewBufferString(out)
var substitutions interface{}
if len(data) == 1 {
substitutions = struct{ ID interface{} }{data[0]}
} else if len(data) == 2 {
substitutions = struct {
ID interface{}
SecondID interface{}
}{data[0], data[1]}
} else {
return "", NewError("Too many arguments to render template (expected 1 or 2)")
}
if err := r.endpointTemplate.Execute(buf, substitutions); err != nil {
return "", NewError(err)
}
return buf.String(), nil
}
// endpointWithID will return the rendered endpoint string for the resource with provided id
func (r Resource) endpointWithID(id ...int) (string, error) {
if !r.isTemplate {
return r.endpoint, nil
}
data := make([]interface{}, len(id))
for i, v := range id {
data[i] = v
}
return r.render(data...)
}
// Endpoint will return the non-templated endpoint string for resource
func (r Resource) Endpoint() (string, error) {
if r.isTemplate {
return "", NewError(fmt.Sprintf("Tried to get endpoint for %s without providing data for template", r.name))
}
return r.endpoint, nil
}