mirror of https://github.com/hashicorp/packer
Merge pull request #5531 from stack72/bump-triton-dependencies
Bump Joyent/triton-go to modern version of the SDKpull/5534/head
commit
a495948dc5
@ -1,95 +0,0 @@
|
||||
package triton
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
)
|
||||
|
||||
type AccountsClient struct {
|
||||
*Client
|
||||
}
|
||||
|
||||
// Accounts returns a c used for accessing functions pertaining
|
||||
// to Account functionality in the Triton API.
|
||||
func (c *Client) Accounts() *AccountsClient {
|
||||
return &AccountsClient{c}
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
ID string `json:"id"`
|
||||
Login string `json:"login"`
|
||||
Email string `json:"email"`
|
||||
CompanyName string `json:"companyName"`
|
||||
FirstName string `json:"firstName"`
|
||||
LastName string `json:"lastName"`
|
||||
Address string `json:"address"`
|
||||
PostalCode string `json:"postalCode"`
|
||||
City string `json:"city"`
|
||||
State string `json:"state"`
|
||||
Country string `json:"country"`
|
||||
Phone string `json:"phone"`
|
||||
Created time.Time `json:"created"`
|
||||
Updated time.Time `json:"updated"`
|
||||
TritonCNSEnabled bool `json:"triton_cns_enabled"`
|
||||
}
|
||||
|
||||
type GetAccountInput struct{}
|
||||
|
||||
func (client *AccountsClient) GetAccount(ctx context.Context, input *GetAccountInput) (*Account, error) {
|
||||
path := fmt.Sprintf("/%s", client.accountName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing GetAccount request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *Account
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding GetAccount response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type UpdateAccountInput struct {
|
||||
Email string `json:"email,omitempty"`
|
||||
CompanyName string `json:"companyName,omitempty"`
|
||||
FirstName string `json:"firstName,omitempty"`
|
||||
LastName string `json:"lastName,omitempty"`
|
||||
Address string `json:"address,omitempty"`
|
||||
PostalCode string `json:"postalCode,omitempty"`
|
||||
City string `json:"city,omitempty"`
|
||||
State string `json:"state,omitempty"`
|
||||
Country string `json:"country,omitempty"`
|
||||
Phone string `json:"phone,omitempty"`
|
||||
TritonCNSEnabled bool `json:"triton_cns_enabled,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateAccount updates your account details with the given parameters.
|
||||
// TODO(jen20) Work out a safe way to test this
|
||||
func (client *AccountsClient) UpdateAccount(ctx context.Context, input *UpdateAccountInput) (*Account, error) {
|
||||
path := fmt.Sprintf("/%s", client.accountName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPost, path, input)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing UpdateAccount request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *Account
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding UpdateAccount response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@ -1,195 +0,0 @@
|
||||
package triton
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/joyent/triton-go/authentication"
|
||||
)
|
||||
|
||||
const nilContext = "nil context"
|
||||
|
||||
// Client represents a connection to the Triton API.
|
||||
type Client struct {
|
||||
client *http.Client
|
||||
authorizer []authentication.Signer
|
||||
apiURL url.URL
|
||||
accountName string
|
||||
}
|
||||
|
||||
// NewClient is used to construct a Client in order to make API
|
||||
// requests to the Triton API.
|
||||
//
|
||||
// At least one signer must be provided - example signers include
|
||||
// authentication.PrivateKeySigner and authentication.SSHAgentSigner.
|
||||
func NewClient(endpoint string, accountName string, signers ...authentication.Signer) (*Client, error) {
|
||||
apiURL, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("invalid endpoint: {{err}}", err)
|
||||
}
|
||||
|
||||
if accountName == "" {
|
||||
return nil, errors.New("account name can not be empty")
|
||||
}
|
||||
|
||||
httpClient := &http.Client{
|
||||
Transport: httpTransport(false),
|
||||
CheckRedirect: doNotFollowRedirects,
|
||||
}
|
||||
|
||||
return &Client{
|
||||
client: httpClient,
|
||||
authorizer: signers,
|
||||
apiURL: *apiURL,
|
||||
accountName: accountName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// InsecureSkipTLSVerify turns off TLS verification for the client connection. This
|
||||
// allows connection to an endpoint with a certificate which was signed by a non-
|
||||
// trusted CA, such as self-signed certificates. This can be useful when connecting
|
||||
// to temporary Triton installations such as Triton Cloud-On-A-Laptop.
|
||||
func (c *Client) InsecureSkipTLSVerify() {
|
||||
if c.client == nil {
|
||||
return
|
||||
}
|
||||
|
||||
c.client.Transport = httpTransport(true)
|
||||
}
|
||||
|
||||
func httpTransport(insecureSkipTLSVerify bool) *http.Transport {
|
||||
return &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
DisableKeepAlives: true,
|
||||
MaxIdleConnsPerHost: -1,
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: insecureSkipTLSVerify,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func doNotFollowRedirects(*http.Request, []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
}
|
||||
|
||||
func (c *Client) executeRequestURIParams(ctx context.Context, method, path string, body interface{}, query *url.Values) (io.ReadCloser, error) {
|
||||
var requestBody io.ReadSeeker
|
||||
if body != nil {
|
||||
marshaled, err := json.MarshalIndent(body, "", " ")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
requestBody = bytes.NewReader(marshaled)
|
||||
}
|
||||
|
||||
endpoint := c.apiURL
|
||||
endpoint.Path = path
|
||||
if query != nil {
|
||||
endpoint.RawQuery = query.Encode()
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, endpoint.String(), requestBody)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error constructing HTTP request: {{err}}", err)
|
||||
}
|
||||
|
||||
dateHeader := time.Now().UTC().Format(time.RFC1123)
|
||||
req.Header.Set("date", dateHeader)
|
||||
|
||||
authHeader, err := c.authorizer[0].Sign(dateHeader)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error signing HTTP request: {{err}}", err)
|
||||
}
|
||||
req.Header.Set("Authorization", authHeader)
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("Accept-Version", "8")
|
||||
req.Header.Set("User-Agent", "triton-go Client API")
|
||||
|
||||
if body != nil {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
resp, err := c.client.Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing HTTP request: {{err}}", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices {
|
||||
return resp.Body, nil
|
||||
}
|
||||
|
||||
return nil, c.decodeError(resp.StatusCode, resp.Body)
|
||||
}
|
||||
|
||||
func (c *Client) decodeError(statusCode int, body io.Reader) error {
|
||||
err := &TritonError{
|
||||
StatusCode: statusCode,
|
||||
}
|
||||
|
||||
errorDecoder := json.NewDecoder(body)
|
||||
if err := errorDecoder.Decode(err); err != nil {
|
||||
return errwrap.Wrapf("Error decoding error response: {{err}}", err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) executeRequest(ctx context.Context, method, path string, body interface{}) (io.ReadCloser, error) {
|
||||
return c.executeRequestURIParams(ctx, method, path, body, nil)
|
||||
}
|
||||
|
||||
func (c *Client) executeRequestRaw(ctx context.Context, method, path string, body interface{}) (*http.Response, error) {
|
||||
var requestBody io.ReadSeeker
|
||||
if body != nil {
|
||||
marshaled, err := json.MarshalIndent(body, "", " ")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
requestBody = bytes.NewReader(marshaled)
|
||||
}
|
||||
|
||||
endpoint := c.apiURL
|
||||
endpoint.Path = path
|
||||
|
||||
req, err := http.NewRequest(method, endpoint.String(), requestBody)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error constructing HTTP request: {{err}}", err)
|
||||
}
|
||||
|
||||
dateHeader := time.Now().UTC().Format(time.RFC1123)
|
||||
req.Header.Set("date", dateHeader)
|
||||
|
||||
authHeader, err := c.authorizer[0].Sign(dateHeader)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error signing HTTP request: {{err}}", err)
|
||||
}
|
||||
req.Header.Set("Authorization", authHeader)
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("Accept-Version", "8")
|
||||
req.Header.Set("User-Agent", "triton-go c API")
|
||||
|
||||
if body != nil {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
resp, err := c.client.Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing HTTP request: {{err}}", err)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@ -0,0 +1,397 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/joyent/triton-go/authentication"
|
||||
)
|
||||
|
||||
const nilContext = "nil context"
|
||||
|
||||
var MissingKeyIdError = errors.New("Default SSH agent authentication requires SDC_KEY_ID")
|
||||
|
||||
// Client represents a connection to the Triton Compute or Object Storage APIs.
|
||||
type Client struct {
|
||||
HTTPClient *http.Client
|
||||
Authorizers []authentication.Signer
|
||||
TritonURL url.URL
|
||||
MantaURL url.URL
|
||||
AccountName string
|
||||
Endpoint string
|
||||
}
|
||||
|
||||
// New is used to construct a Client in order to make API
|
||||
// requests to the Triton API.
|
||||
//
|
||||
// At least one signer must be provided - example signers include
|
||||
// authentication.PrivateKeySigner and authentication.SSHAgentSigner.
|
||||
func New(tritonURL string, mantaURL string, accountName string, signers ...authentication.Signer) (*Client, error) {
|
||||
cloudURL, err := url.Parse(tritonURL)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("invalid endpoint URL: {{err}}", err)
|
||||
}
|
||||
|
||||
storageURL, err := url.Parse(mantaURL)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("invalid manta URL: {{err}}", err)
|
||||
}
|
||||
|
||||
if accountName == "" {
|
||||
return nil, errors.New("account name can not be empty")
|
||||
}
|
||||
|
||||
httpClient := &http.Client{
|
||||
Transport: httpTransport(false),
|
||||
CheckRedirect: doNotFollowRedirects,
|
||||
}
|
||||
|
||||
newClient := &Client{
|
||||
HTTPClient: httpClient,
|
||||
Authorizers: signers,
|
||||
TritonURL: *cloudURL,
|
||||
MantaURL: *storageURL,
|
||||
AccountName: accountName,
|
||||
// TODO(justinwr): Deprecated?
|
||||
// Endpoint: tritonURL,
|
||||
}
|
||||
|
||||
var authorizers []authentication.Signer
|
||||
for _, key := range signers {
|
||||
if key != nil {
|
||||
authorizers = append(authorizers, key)
|
||||
}
|
||||
}
|
||||
|
||||
// Default to constructing an SSHAgentSigner if there are no other signers
|
||||
// passed into NewClient and there's an SDC_KEY_ID value available in the
|
||||
// user environ.
|
||||
if len(authorizers) == 0 {
|
||||
keyID := os.Getenv("SDC_KEY_ID")
|
||||
if len(keyID) != 0 {
|
||||
keySigner, err := authentication.NewSSHAgentSigner(keyID, accountName)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Problem initializing NewSSHAgentSigner: {{err}}", err)
|
||||
}
|
||||
newClient.Authorizers = append(authorizers, keySigner)
|
||||
} else {
|
||||
return nil, MissingKeyIdError
|
||||
}
|
||||
}
|
||||
|
||||
return newClient, nil
|
||||
}
|
||||
|
||||
// InsecureSkipTLSVerify turns off TLS verification for the client connection. This
|
||||
// allows connection to an endpoint with a certificate which was signed by a non-
|
||||
// trusted CA, such as self-signed certificates. This can be useful when connecting
|
||||
// to temporary Triton installations such as Triton Cloud-On-A-Laptop.
|
||||
func (c *Client) InsecureSkipTLSVerify() {
|
||||
if c.HTTPClient == nil {
|
||||
return
|
||||
}
|
||||
|
||||
c.HTTPClient.Transport = httpTransport(true)
|
||||
}
|
||||
|
||||
func httpTransport(insecureSkipTLSVerify bool) *http.Transport {
|
||||
return &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
DisableKeepAlives: true,
|
||||
MaxIdleConnsPerHost: -1,
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: insecureSkipTLSVerify,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func doNotFollowRedirects(*http.Request, []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
}
|
||||
|
||||
// TODO(justinwr): Deprecated?
|
||||
// func (c *Client) FormatURL(path string) string {
|
||||
// return fmt.Sprintf("%s%s", c.Endpoint, path)
|
||||
// }
|
||||
|
||||
func (c *Client) DecodeError(statusCode int, body io.Reader) error {
|
||||
err := &TritonError{
|
||||
StatusCode: statusCode,
|
||||
}
|
||||
|
||||
errorDecoder := json.NewDecoder(body)
|
||||
if err := errorDecoder.Decode(err); err != nil {
|
||||
return errwrap.Wrapf("Error decoding error response: {{err}}", err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type RequestInput struct {
|
||||
Method string
|
||||
Path string
|
||||
Query *url.Values
|
||||
Headers *http.Header
|
||||
Body interface{}
|
||||
}
|
||||
|
||||
func (c *Client) ExecuteRequestURIParams(ctx context.Context, inputs RequestInput) (io.ReadCloser, error) {
|
||||
method := inputs.Method
|
||||
path := inputs.Path
|
||||
body := inputs.Body
|
||||
query := inputs.Query
|
||||
|
||||
var requestBody io.ReadSeeker
|
||||
if body != nil {
|
||||
marshaled, err := json.MarshalIndent(body, "", " ")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
requestBody = bytes.NewReader(marshaled)
|
||||
}
|
||||
|
||||
endpoint := c.TritonURL
|
||||
endpoint.Path = path
|
||||
if query != nil {
|
||||
endpoint.RawQuery = query.Encode()
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, endpoint.String(), requestBody)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error constructing HTTP request: {{err}}", err)
|
||||
}
|
||||
|
||||
dateHeader := time.Now().UTC().Format(time.RFC1123)
|
||||
req.Header.Set("date", dateHeader)
|
||||
|
||||
// NewClient ensures there's always an authorizer (unless this is called
|
||||
// outside that constructor).
|
||||
authHeader, err := c.Authorizers[0].Sign(dateHeader)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error signing HTTP request: {{err}}", err)
|
||||
}
|
||||
req.Header.Set("Authorization", authHeader)
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("Accept-Version", "8")
|
||||
req.Header.Set("User-Agent", "triton-go Client API")
|
||||
|
||||
if body != nil {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
resp, err := c.HTTPClient.Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing HTTP request: {{err}}", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices {
|
||||
return resp.Body, nil
|
||||
}
|
||||
|
||||
return nil, c.DecodeError(resp.StatusCode, resp.Body)
|
||||
}
|
||||
|
||||
func (c *Client) ExecuteRequest(ctx context.Context, inputs RequestInput) (io.ReadCloser, error) {
|
||||
return c.ExecuteRequestURIParams(ctx, inputs)
|
||||
}
|
||||
|
||||
func (c *Client) ExecuteRequestRaw(ctx context.Context, inputs RequestInput) (*http.Response, error) {
|
||||
method := inputs.Method
|
||||
path := inputs.Path
|
||||
body := inputs.Body
|
||||
|
||||
var requestBody io.ReadSeeker
|
||||
if body != nil {
|
||||
marshaled, err := json.MarshalIndent(body, "", " ")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
requestBody = bytes.NewReader(marshaled)
|
||||
}
|
||||
|
||||
endpoint := c.TritonURL
|
||||
endpoint.Path = path
|
||||
|
||||
req, err := http.NewRequest(method, endpoint.String(), requestBody)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error constructing HTTP request: {{err}}", err)
|
||||
}
|
||||
|
||||
dateHeader := time.Now().UTC().Format(time.RFC1123)
|
||||
req.Header.Set("date", dateHeader)
|
||||
|
||||
// NewClient ensures there's always an authorizer (unless this is called
|
||||
// outside that constructor).
|
||||
authHeader, err := c.Authorizers[0].Sign(dateHeader)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error signing HTTP request: {{err}}", err)
|
||||
}
|
||||
req.Header.Set("Authorization", authHeader)
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("Accept-Version", "8")
|
||||
req.Header.Set("User-Agent", "triton-go c API")
|
||||
|
||||
if body != nil {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
resp, err := c.HTTPClient.Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing HTTP request: {{err}}", err)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *Client) ExecuteRequestStorage(ctx context.Context, inputs RequestInput) (io.ReadCloser, http.Header, error) {
|
||||
method := inputs.Method
|
||||
path := inputs.Path
|
||||
query := inputs.Query
|
||||
headers := inputs.Headers
|
||||
body := inputs.Body
|
||||
|
||||
endpoint := c.MantaURL
|
||||
endpoint.Path = path
|
||||
|
||||
var requestBody io.ReadSeeker
|
||||
if body != nil {
|
||||
marshaled, err := json.MarshalIndent(body, "", " ")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
requestBody = bytes.NewReader(marshaled)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, endpoint.String(), requestBody)
|
||||
if err != nil {
|
||||
return nil, nil, errwrap.Wrapf("Error constructing HTTP request: {{err}}", err)
|
||||
}
|
||||
|
||||
if body != nil && (headers == nil || headers.Get("Content-Type") == "") {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
if headers != nil {
|
||||
for key, values := range *headers {
|
||||
for _, value := range values {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dateHeader := time.Now().UTC().Format(time.RFC1123)
|
||||
req.Header.Set("date", dateHeader)
|
||||
|
||||
authHeader, err := c.Authorizers[0].Sign(dateHeader)
|
||||
if err != nil {
|
||||
return nil, nil, errwrap.Wrapf("Error signing HTTP request: {{err}}", err)
|
||||
}
|
||||
req.Header.Set("Authorization", authHeader)
|
||||
req.Header.Set("Accept", "*/*")
|
||||
req.Header.Set("User-Agent", "manta-go client API")
|
||||
|
||||
if query != nil {
|
||||
req.URL.RawQuery = query.Encode()
|
||||
}
|
||||
|
||||
resp, err := c.HTTPClient.Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, nil, errwrap.Wrapf("Error executing HTTP request: {{err}}", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices {
|
||||
return resp.Body, resp.Header, nil
|
||||
}
|
||||
|
||||
mantaError := &MantaError{
|
||||
StatusCode: resp.StatusCode,
|
||||
}
|
||||
|
||||
errorDecoder := json.NewDecoder(resp.Body)
|
||||
if err := errorDecoder.Decode(mantaError); err != nil {
|
||||
return nil, nil, errwrap.Wrapf("Error decoding error response: {{err}}", err)
|
||||
}
|
||||
return nil, nil, mantaError
|
||||
}
|
||||
|
||||
type RequestNoEncodeInput struct {
|
||||
Method string
|
||||
Path string
|
||||
Query *url.Values
|
||||
Headers *http.Header
|
||||
Body io.ReadSeeker
|
||||
}
|
||||
|
||||
func (c *Client) ExecuteRequestNoEncode(ctx context.Context, inputs RequestNoEncodeInput) (io.ReadCloser, http.Header, error) {
|
||||
method := inputs.Method
|
||||
path := inputs.Path
|
||||
query := inputs.Query
|
||||
headers := inputs.Headers
|
||||
body := inputs.Body
|
||||
|
||||
endpoint := c.MantaURL
|
||||
endpoint.Path = path
|
||||
|
||||
req, err := http.NewRequest(method, endpoint.String(), body)
|
||||
if err != nil {
|
||||
return nil, nil, errwrap.Wrapf("Error constructing HTTP request: {{err}}", err)
|
||||
}
|
||||
|
||||
if headers != nil {
|
||||
for key, values := range *headers {
|
||||
for _, value := range values {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dateHeader := time.Now().UTC().Format(time.RFC1123)
|
||||
req.Header.Set("date", dateHeader)
|
||||
|
||||
authHeader, err := c.Authorizers[0].Sign(dateHeader)
|
||||
if err != nil {
|
||||
return nil, nil, errwrap.Wrapf("Error signing HTTP request: {{err}}", err)
|
||||
}
|
||||
req.Header.Set("Authorization", authHeader)
|
||||
req.Header.Set("Accept", "*/*")
|
||||
req.Header.Set("User-Agent", "manta-go client API")
|
||||
|
||||
if query != nil {
|
||||
req.URL.RawQuery = query.Encode()
|
||||
}
|
||||
|
||||
resp, err := c.HTTPClient.Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
return nil, nil, errwrap.Wrapf("Error executing HTTP request: {{err}}", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices {
|
||||
return resp.Body, resp.Header, nil
|
||||
}
|
||||
|
||||
mantaError := &MantaError{
|
||||
StatusCode: resp.StatusCode,
|
||||
}
|
||||
|
||||
errorDecoder := json.NewDecoder(resp.Body)
|
||||
if err := errorDecoder.Decode(mantaError); err != nil {
|
||||
return nil, nil, errwrap.Wrapf("Error decoding error response: {{err}}", err)
|
||||
}
|
||||
return nil, nil, mantaError
|
||||
}
|
||||
@ -0,0 +1,190 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
)
|
||||
|
||||
// ClientError represents an error code and message along with the status code
|
||||
// of the HTTP request which resulted in the error message.
|
||||
type ClientError struct {
|
||||
StatusCode int
|
||||
Code string
|
||||
Message string
|
||||
}
|
||||
|
||||
// Error implements interface Error on the TritonError type.
|
||||
func (e ClientError) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.Code, e.Message)
|
||||
}
|
||||
|
||||
// MantaError represents an error code and message along with
|
||||
// the status code of the HTTP request which resulted in the error
|
||||
// message. Error codes used by the Manta API are listed at
|
||||
// https://apidocs.joyent.com/manta/api.html#errors
|
||||
type MantaError struct {
|
||||
StatusCode int
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Error implements interface Error on the MantaError type.
|
||||
func (e MantaError) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.Code, e.Message)
|
||||
}
|
||||
|
||||
// TritonError represents an error code and message along with
|
||||
// the status code of the HTTP request which resulted in the error
|
||||
// message. Error codes used by the Triton API are listed at
|
||||
// https://apidocs.joyent.com/cloudapi/#cloudapi-http-responses
|
||||
type TritonError struct {
|
||||
StatusCode int
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Error implements interface Error on the TritonError type.
|
||||
func (e TritonError) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.Code, e.Message)
|
||||
}
|
||||
|
||||
func IsAuthSchemeError(err error) bool {
|
||||
return isSpecificError(err, "AuthScheme")
|
||||
}
|
||||
func IsAuthorizationError(err error) bool {
|
||||
return isSpecificError(err, "Authorization")
|
||||
}
|
||||
func IsBadRequestError(err error) bool {
|
||||
return isSpecificError(err, "BadRequest")
|
||||
}
|
||||
func IsChecksumError(err error) bool {
|
||||
return isSpecificError(err, "Checksum")
|
||||
}
|
||||
func IsConcurrentRequestError(err error) bool {
|
||||
return isSpecificError(err, "ConcurrentRequest")
|
||||
}
|
||||
func IsContentLengthError(err error) bool {
|
||||
return isSpecificError(err, "ContentLength")
|
||||
}
|
||||
func IsContentMD5MismatchError(err error) bool {
|
||||
return isSpecificError(err, "ContentMD5Mismatch")
|
||||
}
|
||||
func IsEntityExistsError(err error) bool {
|
||||
return isSpecificError(err, "EntityExists")
|
||||
}
|
||||
func IsInvalidArgumentError(err error) bool {
|
||||
return isSpecificError(err, "InvalidArgument")
|
||||
}
|
||||
func IsInvalidAuthTokenError(err error) bool {
|
||||
return isSpecificError(err, "InvalidAuthToken")
|
||||
}
|
||||
func IsInvalidCredentialsError(err error) bool {
|
||||
return isSpecificError(err, "InvalidCredentials")
|
||||
}
|
||||
func IsInvalidDurabilityLevelError(err error) bool {
|
||||
return isSpecificError(err, "InvalidDurabilityLevel")
|
||||
}
|
||||
func IsInvalidKeyIdError(err error) bool {
|
||||
return isSpecificError(err, "InvalidKeyId")
|
||||
}
|
||||
func IsInvalidJobError(err error) bool {
|
||||
return isSpecificError(err, "InvalidJob")
|
||||
}
|
||||
func IsInvalidLinkError(err error) bool {
|
||||
return isSpecificError(err, "InvalidLink")
|
||||
}
|
||||
func IsInvalidLimitError(err error) bool {
|
||||
return isSpecificError(err, "InvalidLimit")
|
||||
}
|
||||
func IsInvalidSignatureError(err error) bool {
|
||||
return isSpecificError(err, "InvalidSignature")
|
||||
}
|
||||
func IsInvalidUpdateError(err error) bool {
|
||||
return isSpecificError(err, "InvalidUpdate")
|
||||
}
|
||||
func IsDirectoryDoesNotExistError(err error) bool {
|
||||
return isSpecificError(err, "DirectoryDoesNotExist")
|
||||
}
|
||||
func IsDirectoryExistsError(err error) bool {
|
||||
return isSpecificError(err, "DirectoryExists")
|
||||
}
|
||||
func IsDirectoryNotEmptyError(err error) bool {
|
||||
return isSpecificError(err, "DirectoryNotEmpty")
|
||||
}
|
||||
func IsDirectoryOperationError(err error) bool {
|
||||
return isSpecificError(err, "DirectoryOperation")
|
||||
}
|
||||
func IsInternalError(err error) bool {
|
||||
return isSpecificError(err, "Internal")
|
||||
}
|
||||
func IsJobNotFoundError(err error) bool {
|
||||
return isSpecificError(err, "JobNotFound")
|
||||
}
|
||||
func IsJobStateError(err error) bool {
|
||||
return isSpecificError(err, "JobState")
|
||||
}
|
||||
func IsKeyDoesNotExistError(err error) bool {
|
||||
return isSpecificError(err, "KeyDoesNotExist")
|
||||
}
|
||||
func IsNotAcceptableError(err error) bool {
|
||||
return isSpecificError(err, "NotAcceptable")
|
||||
}
|
||||
func IsNotEnoughSpaceError(err error) bool {
|
||||
return isSpecificError(err, "NotEnoughSpace")
|
||||
}
|
||||
func IsLinkNotFoundError(err error) bool {
|
||||
return isSpecificError(err, "LinkNotFound")
|
||||
}
|
||||
func IsLinkNotObjectError(err error) bool {
|
||||
return isSpecificError(err, "LinkNotObject")
|
||||
}
|
||||
func IsLinkRequiredError(err error) bool {
|
||||
return isSpecificError(err, "LinkRequired")
|
||||
}
|
||||
func IsParentNotDirectoryError(err error) bool {
|
||||
return isSpecificError(err, "ParentNotDirectory")
|
||||
}
|
||||
func IsPreconditionFailedError(err error) bool {
|
||||
return isSpecificError(err, "PreconditionFailed")
|
||||
}
|
||||
func IsPreSignedRequestError(err error) bool {
|
||||
return isSpecificError(err, "PreSignedRequest")
|
||||
}
|
||||
func IsRequestEntityTooLargeError(err error) bool {
|
||||
return isSpecificError(err, "RequestEntityTooLarge")
|
||||
}
|
||||
func IsResourceNotFoundError(err error) bool {
|
||||
return isSpecificError(err, "ResourceNotFound")
|
||||
}
|
||||
func IsRootDirectoryError(err error) bool {
|
||||
return isSpecificError(err, "RootDirectory")
|
||||
}
|
||||
func IsServiceUnavailableError(err error) bool {
|
||||
return isSpecificError(err, "ServiceUnavailable")
|
||||
}
|
||||
func IsSSLRequiredError(err error) bool {
|
||||
return isSpecificError(err, "SSLRequired")
|
||||
}
|
||||
func IsUploadTimeoutError(err error) bool {
|
||||
return isSpecificError(err, "UploadTimeout")
|
||||
}
|
||||
func IsUserDoesNotExistError(err error) bool {
|
||||
return isSpecificError(err, "UserDoesNotExist")
|
||||
}
|
||||
|
||||
// isSpecificError checks whether the error represented by err wraps
|
||||
// an underlying MantaError with code errorCode.
|
||||
func isSpecificError(err error, errorCode string) bool {
|
||||
tritonErrorInterface := errwrap.GetType(err.(error), &MantaError{})
|
||||
if tritonErrorInterface == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
tritonErr := tritonErrorInterface.(*MantaError)
|
||||
if tritonErr.Code == errorCode {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
package compute
|
||||
|
||||
import (
|
||||
triton "github.com/joyent/triton-go"
|
||||
"github.com/joyent/triton-go/client"
|
||||
)
|
||||
|
||||
type ComputeClient struct {
|
||||
Client *client.Client
|
||||
}
|
||||
|
||||
func newComputeClient(client *client.Client) *ComputeClient {
|
||||
return &ComputeClient{
|
||||
Client: client,
|
||||
}
|
||||
}
|
||||
|
||||
// NewClient returns a new client for working with Compute endpoints and
|
||||
// resources within CloudAPI
|
||||
func NewClient(config *triton.ClientConfig) (*ComputeClient, error) {
|
||||
// TODO: Utilize config interface within the function itself
|
||||
client, err := client.New(config.TritonURL, config.MantaURL, config.AccountName, config.Signers...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newComputeClient(client), nil
|
||||
}
|
||||
|
||||
// Datacenters returns a Compute client used for accessing functions pertaining
|
||||
// to DataCenter functionality in the Triton API.
|
||||
func (c *ComputeClient) Datacenters() *DataCentersClient {
|
||||
return &DataCentersClient{c.Client}
|
||||
}
|
||||
|
||||
// Images returns a Compute client used for accessing functions pertaining to
|
||||
// Images functionality in the Triton API.
|
||||
func (c *ComputeClient) Images() *ImagesClient {
|
||||
return &ImagesClient{c.Client}
|
||||
}
|
||||
|
||||
// Machines returns a Compute client used for accessing functions pertaining to
|
||||
// machine functionality in the Triton API.
|
||||
func (c *ComputeClient) Instances() *InstancesClient {
|
||||
return &InstancesClient{c.Client}
|
||||
}
|
||||
|
||||
// Packages returns a Compute client used for accessing functions pertaining to
|
||||
// Packages functionality in the Triton API.
|
||||
func (c *ComputeClient) Packages() *PackagesClient {
|
||||
return &PackagesClient{c.Client}
|
||||
}
|
||||
|
||||
// Services returns a Compute client used for accessing functions pertaining to
|
||||
// Services functionality in the Triton API.
|
||||
func (c *ComputeClient) Services() *ServicesClient {
|
||||
return &ServicesClient{c.Client}
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
package compute
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/joyent/triton-go/client"
|
||||
)
|
||||
|
||||
type DataCentersClient struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
type DataCenter struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
type ListDataCentersInput struct{}
|
||||
|
||||
func (c *DataCentersClient) List(ctx context.Context, _ *ListDataCentersInput) ([]*DataCenter, error) {
|
||||
path := fmt.Sprintf("/%s/datacenters", c.client.AccountName)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodGet,
|
||||
Path: path,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing List request: {{err}}", err)
|
||||
}
|
||||
|
||||
var intermediate map[string]string
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&intermediate); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding List response: {{err}}", err)
|
||||
}
|
||||
|
||||
keys := make([]string, len(intermediate))
|
||||
i := 0
|
||||
for k := range intermediate {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
result := make([]*DataCenter, len(intermediate))
|
||||
i = 0
|
||||
for _, key := range keys {
|
||||
result[i] = &DataCenter{
|
||||
Name: key,
|
||||
URL: intermediate[key],
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type GetDataCenterInput struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (c *DataCentersClient) Get(ctx context.Context, input *GetDataCenterInput) (*DataCenter, error) {
|
||||
path := fmt.Sprintf("/%s/datacenters/%s", c.client.AccountName, input.Name)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodGet,
|
||||
Path: path,
|
||||
}
|
||||
resp, err := c.client.ExecuteRequestRaw(ctx, reqInputs)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing Get request: {{err}}", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusFound {
|
||||
return nil, fmt.Errorf("Error executing Get request: expected status code 302, got %s",
|
||||
resp.StatusCode)
|
||||
}
|
||||
|
||||
location := resp.Header.Get("Location")
|
||||
if location == "" {
|
||||
return nil, errors.New("Error decoding Get response: no Location header")
|
||||
}
|
||||
|
||||
return &DataCenter{
|
||||
Name: input.Name,
|
||||
URL: location,
|
||||
}, nil
|
||||
}
|
||||
@ -1,123 +1,112 @@
|
||||
package triton
|
||||
package compute
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/joyent/triton-go/client"
|
||||
)
|
||||
|
||||
// TritonError represents an error code and message along with
|
||||
// the status code of the HTTP request which resulted in the error
|
||||
// message. Error codes used by the Triton API are listed at
|
||||
// https://apidocs.joyent.com/cloudapi/#cloudapi-http-responses
|
||||
type TritonError struct {
|
||||
StatusCode int
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Error implements interface Error on the TritonError type.
|
||||
func (e TritonError) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.Code, e.Message)
|
||||
}
|
||||
|
||||
// IsBadRequest tests whether err wraps a TritonError with
|
||||
// IsBadRequest tests whether err wraps a client.TritonError with
|
||||
// code BadRequest
|
||||
func IsBadRequest(err error) bool {
|
||||
return isSpecificError(err, "BadRequest")
|
||||
}
|
||||
|
||||
// IsInternalError tests whether err wraps a TritonError with
|
||||
// IsInternalError tests whether err wraps a client.TritonError with
|
||||
// code InternalError
|
||||
func IsInternalError(err error) bool {
|
||||
return isSpecificError(err, "InternalError")
|
||||
}
|
||||
|
||||
// IsInUseError tests whether err wraps a TritonError with
|
||||
// IsInUseError tests whether err wraps a client.TritonError with
|
||||
// code InUseError
|
||||
func IsInUseError(err error) bool {
|
||||
return isSpecificError(err, "InUseError")
|
||||
}
|
||||
|
||||
// IsInvalidArgument tests whether err wraps a TritonError with
|
||||
// IsInvalidArgument tests whether err wraps a client.TritonError with
|
||||
// code InvalidArgument
|
||||
func IsInvalidArgument(err error) bool {
|
||||
return isSpecificError(err, "InvalidArgument")
|
||||
}
|
||||
|
||||
// IsInvalidCredentials tests whether err wraps a TritonError with
|
||||
// IsInvalidCredentials tests whether err wraps a client.TritonError with
|
||||
// code InvalidCredentials
|
||||
func IsInvalidCredentials(err error) bool {
|
||||
return isSpecificError(err, "InvalidCredentials")
|
||||
}
|
||||
|
||||
// IsInvalidHeader tests whether err wraps a TritonError with
|
||||
// IsInvalidHeader tests whether err wraps a client.TritonError with
|
||||
// code InvalidHeader
|
||||
func IsInvalidHeader(err error) bool {
|
||||
return isSpecificError(err, "InvalidHeader")
|
||||
}
|
||||
|
||||
// IsInvalidVersion tests whether err wraps a TritonError with
|
||||
// IsInvalidVersion tests whether err wraps a client.TritonError with
|
||||
// code InvalidVersion
|
||||
func IsInvalidVersion(err error) bool {
|
||||
return isSpecificError(err, "InvalidVersion")
|
||||
}
|
||||
|
||||
// IsMissingParameter tests whether err wraps a TritonError with
|
||||
// IsMissingParameter tests whether err wraps a client.TritonError with
|
||||
// code MissingParameter
|
||||
func IsMissingParameter(err error) bool {
|
||||
return isSpecificError(err, "MissingParameter")
|
||||
}
|
||||
|
||||
// IsNotAuthorized tests whether err wraps a TritonError with
|
||||
// IsNotAuthorized tests whether err wraps a client.TritonError with
|
||||
// code NotAuthorized
|
||||
func IsNotAuthorized(err error) bool {
|
||||
return isSpecificError(err, "NotAuthorized")
|
||||
}
|
||||
|
||||
// IsRequestThrottled tests whether err wraps a TritonError with
|
||||
// IsRequestThrottled tests whether err wraps a client.TritonError with
|
||||
// code RequestThrottled
|
||||
func IsRequestThrottled(err error) bool {
|
||||
return isSpecificError(err, "RequestThrottled")
|
||||
}
|
||||
|
||||
// IsRequestTooLarge tests whether err wraps a TritonError with
|
||||
// IsRequestTooLarge tests whether err wraps a client.TritonError with
|
||||
// code RequestTooLarge
|
||||
func IsRequestTooLarge(err error) bool {
|
||||
return isSpecificError(err, "RequestTooLarge")
|
||||
}
|
||||
|
||||
// IsRequestMoved tests whether err wraps a TritonError with
|
||||
// IsRequestMoved tests whether err wraps a client.TritonError with
|
||||
// code RequestMoved
|
||||
func IsRequestMoved(err error) bool {
|
||||
return isSpecificError(err, "RequestMoved")
|
||||
}
|
||||
|
||||
// IsResourceNotFound tests whether err wraps a TritonError with
|
||||
// IsResourceFound tests whether err wraps a client.TritonError with code ResourceFound
|
||||
func IsResourceFound(err error) bool {
|
||||
return isSpecificError(err, "ResourceFound")
|
||||
}
|
||||
|
||||
// IsResourceNotFound tests whether err wraps a client.TritonError with
|
||||
// code ResourceNotFound
|
||||
func IsResourceNotFound(err error) bool {
|
||||
return isSpecificError(err, "ResourceNotFound")
|
||||
}
|
||||
|
||||
// IsUnknownError tests whether err wraps a TritonError with
|
||||
// IsUnknownError tests whether err wraps a client.TritonError with
|
||||
// code UnknownError
|
||||
func IsUnknownError(err error) bool {
|
||||
return isSpecificError(err, "UnknownError")
|
||||
}
|
||||
|
||||
// isSpecificError checks whether the error represented by err wraps
|
||||
// an underlying TritonError with code errorCode.
|
||||
// an underlying client.TritonError with code errorCode.
|
||||
func isSpecificError(err error, errorCode string) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
tritonErrorInterface := errwrap.GetType(err.(error), &TritonError{})
|
||||
tritonErrorInterface := errwrap.GetType(err.(error), &client.TritonError{})
|
||||
if tritonErrorInterface == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
tritonErr := tritonErrorInterface.(*TritonError)
|
||||
tritonErr := tritonErrorInterface.(*client.TritonError)
|
||||
if tritonErr.Code == errorCode {
|
||||
return true
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,73 +0,0 @@
|
||||
package triton
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
)
|
||||
|
||||
type ConfigClient struct {
|
||||
*Client
|
||||
}
|
||||
|
||||
// Config returns a c used for accessing functions pertaining
|
||||
// to Config functionality in the Triton API.
|
||||
func (c *Client) Config() *ConfigClient {
|
||||
return &ConfigClient{c}
|
||||
}
|
||||
|
||||
// Config represents configuration for your account.
|
||||
type Config struct {
|
||||
// DefaultNetwork is the network that docker containers are provisioned on.
|
||||
DefaultNetwork string `json:"default_network"`
|
||||
}
|
||||
|
||||
type GetConfigInput struct{}
|
||||
|
||||
// GetConfig outputs configuration for your account.
|
||||
func (client *ConfigClient) GetConfig(ctx context.Context, input *GetConfigInput) (*Config, error) {
|
||||
path := fmt.Sprintf("/%s/config", client.accountName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing GetConfig request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *Config
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding GetConfig response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type UpdateConfigInput struct {
|
||||
// DefaultNetwork is the network that docker containers are provisioned on.
|
||||
DefaultNetwork string `json:"default_network"`
|
||||
}
|
||||
|
||||
// UpdateConfig updates configuration values for your account.
|
||||
func (client *ConfigClient) UpdateConfig(ctx context.Context, input *UpdateConfigInput) (*Config, error) {
|
||||
path := fmt.Sprintf("/%s/config", client.accountName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPut, path, input)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing UpdateConfig request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *Config
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding UpdateConfig response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@ -1,93 +0,0 @@
|
||||
package triton
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
|
||||
"context"
|
||||
"github.com/hashicorp/errwrap"
|
||||
)
|
||||
|
||||
type DataCentersClient struct {
|
||||
*Client
|
||||
}
|
||||
|
||||
// DataCenters returns a c used for accessing functions pertaining
|
||||
// to Datacenter functionality in the Triton API.
|
||||
func (c *Client) Datacenters() *DataCentersClient {
|
||||
return &DataCentersClient{c}
|
||||
}
|
||||
|
||||
type DataCenter struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
type ListDataCentersInput struct{}
|
||||
|
||||
func (client *DataCentersClient) ListDataCenters(ctx context.Context, _ *ListDataCentersInput) ([]*DataCenter, error) {
|
||||
path := fmt.Sprintf("/%s/datacenters", client.accountName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing ListDatacenters request: {{err}}", err)
|
||||
}
|
||||
|
||||
var intermediate map[string]string
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&intermediate); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding ListDatacenters response: {{err}}", err)
|
||||
}
|
||||
|
||||
keys := make([]string, len(intermediate))
|
||||
i := 0
|
||||
for k := range intermediate {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
result := make([]*DataCenter, len(intermediate))
|
||||
i = 0
|
||||
for _, key := range keys {
|
||||
result[i] = &DataCenter{
|
||||
Name: key,
|
||||
URL: intermediate[key],
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type GetDataCenterInput struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (client *DataCentersClient) GetDataCenter(ctx context.Context, input *GetDataCenterInput) (*DataCenter, error) {
|
||||
path := fmt.Sprintf("/%s/datacenters/%s", client.accountName, input.Name)
|
||||
resp, err := client.executeRequestRaw(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing GetDatacenter request: {{err}}", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusFound {
|
||||
return nil, fmt.Errorf("Error executing GetDatacenter request: expected status code 302, got %s",
|
||||
resp.StatusCode)
|
||||
}
|
||||
|
||||
location := resp.Header.Get("Location")
|
||||
if location == "" {
|
||||
return nil, errors.New("Error decoding GetDatacenter response: no Location header")
|
||||
}
|
||||
|
||||
return &DataCenter{
|
||||
Name: input.Name,
|
||||
URL: location,
|
||||
}, nil
|
||||
}
|
||||
@ -1,234 +0,0 @@
|
||||
package triton
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"context"
|
||||
"github.com/hashicorp/errwrap"
|
||||
)
|
||||
|
||||
type FabricsClient struct {
|
||||
*Client
|
||||
}
|
||||
|
||||
// Fabrics returns a client used for accessing functions pertaining to
|
||||
// Fabric functionality in the Triton API.
|
||||
func (c *Client) Fabrics() *FabricsClient {
|
||||
return &FabricsClient{c}
|
||||
}
|
||||
|
||||
type FabricVLAN struct {
|
||||
Name string `json:"name"`
|
||||
ID int `json:"vlan_id"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type ListFabricVLANsInput struct{}
|
||||
|
||||
func (client *FabricsClient) ListFabricVLANs(ctx context.Context, _ *ListFabricVLANsInput) ([]*FabricVLAN, error) {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans", client.accountName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing ListFabricVLANs request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result []*FabricVLAN
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding ListFabricVLANs response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type CreateFabricVLANInput struct {
|
||||
Name string `json:"name"`
|
||||
ID int `json:"vlan_id"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func (client *FabricsClient) CreateFabricVLAN(ctx context.Context, input *CreateFabricVLANInput) (*FabricVLAN, error) {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans", client.accountName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPost, path, input)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing CreateFabricVLAN request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FabricVLAN
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding CreateFabricVLAN response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type UpdateFabricVLANInput struct {
|
||||
ID int `json:"-"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func (client *FabricsClient) UpdateFabricVLAN(ctx context.Context, input *UpdateFabricVLANInput) (*FabricVLAN, error) {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d", client.accountName, input.ID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPut, path, input)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing UpdateFabricVLAN request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FabricVLAN
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding UpdateFabricVLAN response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type GetFabricVLANInput struct {
|
||||
ID int `json:"-"`
|
||||
}
|
||||
|
||||
func (client *FabricsClient) GetFabricVLAN(ctx context.Context, input *GetFabricVLANInput) (*FabricVLAN, error) {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d", client.accountName, input.ID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing GetFabricVLAN request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FabricVLAN
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding GetFabricVLAN response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type DeleteFabricVLANInput struct {
|
||||
ID int `json:"-"`
|
||||
}
|
||||
|
||||
func (client *FabricsClient) DeleteFabricVLAN(ctx context.Context, input *DeleteFabricVLANInput) error {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d", client.accountName, input.ID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodDelete, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing DeleteFabricVLAN request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListFabricNetworksInput struct {
|
||||
FabricVLANID int `json:"-"`
|
||||
}
|
||||
|
||||
func (client *FabricsClient) ListFabricNetworks(ctx context.Context, input *ListFabricNetworksInput) ([]*Network, error) {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d/networks", client.accountName, input.FabricVLANID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing ListFabricNetworks request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result []*Network
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding ListFabricNetworks response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type CreateFabricNetworkInput struct {
|
||||
FabricVLANID int `json:"-"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Subnet string `json:"subnet"`
|
||||
ProvisionStartIP string `json:"provision_start_ip"`
|
||||
ProvisionEndIP string `json:"provision_end_ip"`
|
||||
Gateway string `json:"gateway"`
|
||||
Resolvers []string `json:"resolvers"`
|
||||
Routes map[string]string `json:"routes"`
|
||||
InternetNAT bool `json:"internet_nat"`
|
||||
}
|
||||
|
||||
func (client *FabricsClient) CreateFabricNetwork(ctx context.Context, input *CreateFabricNetworkInput) (*Network, error) {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d/networks", client.accountName, input.FabricVLANID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPost, path, input)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing CreateFabricNetwork request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *Network
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding CreateFabricNetwork response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type GetFabricNetworkInput struct {
|
||||
FabricVLANID int `json:"-"`
|
||||
NetworkID string `json:"-"`
|
||||
}
|
||||
|
||||
func (client *FabricsClient) GetFabricNetwork(ctx context.Context, input *GetFabricNetworkInput) (*Network, error) {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d/networks/%s", client.accountName, input.FabricVLANID, input.NetworkID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing GetFabricNetwork request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *Network
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding GetFabricNetwork response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type DeleteFabricNetworkInput struct {
|
||||
FabricVLANID int `json:"-"`
|
||||
NetworkID string `json:"-"`
|
||||
}
|
||||
|
||||
func (client *FabricsClient) DeleteFabricNetwork(ctx context.Context, input *DeleteFabricNetworkInput) error {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d/networks/%s", client.accountName, input.FabricVLANID, input.NetworkID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodDelete, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing DeleteFabricNetwork request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -1,219 +0,0 @@
|
||||
package triton
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
)
|
||||
|
||||
type FirewallClient struct {
|
||||
*Client
|
||||
}
|
||||
|
||||
// Firewall returns a client used for accessing functions pertaining to
|
||||
// firewall functionality in the Triton API.
|
||||
func (c *Client) Firewall() *FirewallClient {
|
||||
return &FirewallClient{c}
|
||||
}
|
||||
|
||||
// FirewallRule represents a firewall rule
|
||||
type FirewallRule struct {
|
||||
// ID is a unique identifier for this rule
|
||||
ID string `json:"id"`
|
||||
|
||||
// Enabled indicates if the rule is enabled
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// Rule is the firewall rule text
|
||||
Rule string `json:"rule"`
|
||||
|
||||
// Global indicates if the rule is global. Optional.
|
||||
Global bool `json:"global"`
|
||||
|
||||
// Description is a human-readable description for the rule. Optional
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type ListFirewallRulesInput struct{}
|
||||
|
||||
func (client *FirewallClient) ListFirewallRules(ctx context.Context, _ *ListFirewallRulesInput) ([]*FirewallRule, error) {
|
||||
path := fmt.Sprintf("/%s/fwrules", client.accountName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing ListFirewallRules request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result []*FirewallRule
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding ListFirewallRules response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type GetFirewallRuleInput struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func (client *FirewallClient) GetFirewallRule(ctx context.Context, input *GetFirewallRuleInput) (*FirewallRule, error) {
|
||||
path := fmt.Sprintf("/%s/fwrules/%s", client.accountName, input.ID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing GetFirewallRule request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FirewallRule
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding GetFirewallRule response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type CreateFirewallRuleInput struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Rule string `json:"rule"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func (client *FirewallClient) CreateFirewallRule(ctx context.Context, input *CreateFirewallRuleInput) (*FirewallRule, error) {
|
||||
path := fmt.Sprintf("/%s/fwrules", client.accountName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPost, path, input)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing CreateFirewallRule request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FirewallRule
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding CreateFirewallRule response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type UpdateFirewallRuleInput struct {
|
||||
ID string `json:"-"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Rule string `json:"rule"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func (client *FirewallClient) UpdateFirewallRule(ctx context.Context, input *UpdateFirewallRuleInput) (*FirewallRule, error) {
|
||||
path := fmt.Sprintf("/%s/fwrules/%s", client.accountName, input.ID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPost, path, input)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing UpdateFirewallRule request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FirewallRule
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding UpdateFirewallRule response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type EnableFirewallRuleInput struct {
|
||||
ID string `json:"-"`
|
||||
}
|
||||
|
||||
func (client *FirewallClient) EnableFirewallRule(ctx context.Context, input *EnableFirewallRuleInput) (*FirewallRule, error) {
|
||||
path := fmt.Sprintf("/%s/fwrules/%s/enable", client.accountName, input.ID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPost, path, input)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing EnableFirewallRule request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FirewallRule
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding EnableFirewallRule response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type DisableFirewallRuleInput struct {
|
||||
ID string `json:"-"`
|
||||
}
|
||||
|
||||
func (client *FirewallClient) DisableFirewallRule(ctx context.Context, input *DisableFirewallRuleInput) (*FirewallRule, error) {
|
||||
path := fmt.Sprintf("/%s/fwrules/%s/disable", client.accountName, input.ID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPost, path, input)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing DisableFirewallRule request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FirewallRule
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding DisableFirewallRule response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type DeleteFirewallRuleInput struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func (client *FirewallClient) DeleteFirewallRule(ctx context.Context, input *DeleteFirewallRuleInput) error {
|
||||
path := fmt.Sprintf("/%s/fwrules/%s", client.accountName, input.ID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodDelete, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing DeleteFirewallRule request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListMachineFirewallRulesInput struct {
|
||||
MachineID string
|
||||
}
|
||||
|
||||
func (client *FirewallClient) ListMachineFirewallRules(ctx context.Context, input *ListMachineFirewallRulesInput) ([]*FirewallRule, error) {
|
||||
path := fmt.Sprintf("/%s/machines/%s/firewallrules", client.accountName, input.MachineID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing ListMachineFirewallRules request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result []*FirewallRule
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding ListFirewallRules response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@ -1,125 +0,0 @@
|
||||
package triton
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
)
|
||||
|
||||
type KeysClient struct {
|
||||
*Client
|
||||
}
|
||||
|
||||
// Keys returns a c used for accessing functions pertaining to
|
||||
// SSH key functionality in the Triton API.
|
||||
func (c *Client) Keys() *KeysClient {
|
||||
return &KeysClient{c}
|
||||
}
|
||||
|
||||
// Key represents a public key
|
||||
type Key struct {
|
||||
// Name of the key
|
||||
Name string `json:"name"`
|
||||
|
||||
// Key fingerprint
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
|
||||
// OpenSSH-formatted public key
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
type ListKeysInput struct{}
|
||||
|
||||
// ListKeys lists all public keys we have on record for the specified
|
||||
// account.
|
||||
func (client *KeysClient) ListKeys(ctx context.Context, _ *ListKeysInput) ([]*Key, error) {
|
||||
path := fmt.Sprintf("/%s/keys", client.accountName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing ListKeys request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result []*Key
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding ListKeys response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type GetKeyInput struct {
|
||||
KeyName string
|
||||
}
|
||||
|
||||
func (client *KeysClient) GetKey(ctx context.Context, input *GetKeyInput) (*Key, error) {
|
||||
path := fmt.Sprintf("/%s/keys/%s", client.accountName, input.KeyName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing GetKey request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *Key
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding GetKey response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type DeleteKeyInput struct {
|
||||
KeyName string
|
||||
}
|
||||
|
||||
func (client *KeysClient) DeleteKey(ctx context.Context, input *DeleteKeyInput) error {
|
||||
path := fmt.Sprintf("/%s/keys/%s", client.accountName, input.KeyName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodDelete, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing DeleteKey request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateKeyInput represents the option that can be specified
|
||||
// when creating a new key.
|
||||
type CreateKeyInput struct {
|
||||
// Name of the key. Optional.
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// OpenSSH-formatted public key.
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// CreateKey uploads a new OpenSSH key to Triton for use in HTTP signing and SSH.
|
||||
func (client *KeysClient) CreateKey(ctx context.Context, input *CreateKeyInput) (*Key, error) {
|
||||
path := fmt.Sprintf("/%s/keys", client.accountName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPost, path, input)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing CreateKey request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *Key
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding CreateKey response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@ -1,667 +0,0 @@
|
||||
package triton
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
)
|
||||
|
||||
type MachinesClient struct {
|
||||
*Client
|
||||
}
|
||||
|
||||
// Machines returns a client used for accessing functions pertaining to
|
||||
// machine functionality in the Triton API.
|
||||
func (c *Client) Machines() *MachinesClient {
|
||||
return &MachinesClient{c}
|
||||
}
|
||||
|
||||
const (
|
||||
machineCNSTagDisable = "triton.cns.disable"
|
||||
machineCNSTagReversePTR = "triton.cns.reverse_ptr"
|
||||
machineCNSTagServices = "triton.cns.services"
|
||||
)
|
||||
|
||||
// MachineCNS is a container for the CNS-specific attributes. In the API these
|
||||
// values are embedded within a Machine's Tags attribute, however they are
|
||||
// exposed to the caller as their native types.
|
||||
type MachineCNS struct {
|
||||
Disable *bool
|
||||
ReversePTR *string
|
||||
Services []string
|
||||
}
|
||||
|
||||
type Machine struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Brand string `json:"brand"`
|
||||
State string `json:"state"`
|
||||
Image string `json:"image"`
|
||||
Memory int `json:"memory"`
|
||||
Disk int `json:"disk"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
Created time.Time `json:"created"`
|
||||
Updated time.Time `json:"updated"`
|
||||
Docker bool `json:"docker"`
|
||||
IPs []string `json:"ips"`
|
||||
Networks []string `json:"networks"`
|
||||
PrimaryIP string `json:"primaryIp"`
|
||||
FirewallEnabled bool `json:"firewall_enabled"`
|
||||
ComputeNode string `json:"compute_node"`
|
||||
Package string `json:"package"`
|
||||
DomainNames []string `json:"dns_names"`
|
||||
CNS MachineCNS
|
||||
}
|
||||
|
||||
// _Machine is a private facade over Machine that handles the necessary API
|
||||
// overrides from VMAPI's machine endpoint(s).
|
||||
type _Machine struct {
|
||||
Machine
|
||||
Tags map[string]interface{} `json:"tags"`
|
||||
}
|
||||
|
||||
type NIC struct {
|
||||
IP string `json:"ip"`
|
||||
MAC string `json:"mac"`
|
||||
Primary bool `json:"primary"`
|
||||
Netmask string `json:"netmask"`
|
||||
Gateway string `json:"gateway"`
|
||||
State string `json:"state"`
|
||||
Network string `json:"network"`
|
||||
}
|
||||
|
||||
type GetMachineInput struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func (gmi *GetMachineInput) Validate() error {
|
||||
if gmi.ID == "" {
|
||||
return fmt.Errorf("machine ID can not be empty")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (client *MachinesClient) GetMachine(ctx context.Context, input *GetMachineInput) (*Machine, error) {
|
||||
if err := input.Validate(); err != nil {
|
||||
return nil, errwrap.Wrapf("unable to get machine: {{err}}", err)
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("/%s/machines/%s", client.accountName, input.ID)
|
||||
response, err := client.executeRequestRaw(ctx, http.MethodGet, path, nil)
|
||||
if response != nil {
|
||||
defer response.Body.Close()
|
||||
}
|
||||
if response.StatusCode == http.StatusNotFound || response.StatusCode == http.StatusGone {
|
||||
return nil, &TritonError{
|
||||
StatusCode: response.StatusCode,
|
||||
Code: "ResourceNotFound",
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing GetMachine request: {{err}}",
|
||||
client.decodeError(response.StatusCode, response.Body))
|
||||
}
|
||||
|
||||
var result *_Machine
|
||||
decoder := json.NewDecoder(response.Body)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding GetMachine response: {{err}}", err)
|
||||
}
|
||||
|
||||
native, err := result.toNative()
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("unable to convert API response for machines to native type: {{err}}", err)
|
||||
}
|
||||
|
||||
return native, nil
|
||||
}
|
||||
|
||||
type ListMachinesInput struct{}
|
||||
|
||||
func (client *MachinesClient) ListMachines(ctx context.Context, _ *ListMachinesInput) ([]*Machine, error) {
|
||||
path := fmt.Sprintf("/%s/machines", client.accountName)
|
||||
response, err := client.executeRequestRaw(ctx, http.MethodGet, path, nil)
|
||||
if response != nil {
|
||||
defer response.Body.Close()
|
||||
}
|
||||
if response.StatusCode == http.StatusNotFound {
|
||||
return nil, &TritonError{
|
||||
StatusCode: response.StatusCode,
|
||||
Code: "ResourceNotFound",
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing ListMachines request: {{err}}",
|
||||
client.decodeError(response.StatusCode, response.Body))
|
||||
}
|
||||
|
||||
var results []*_Machine
|
||||
decoder := json.NewDecoder(response.Body)
|
||||
if err = decoder.Decode(&results); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding ListMachines response: {{err}}", err)
|
||||
}
|
||||
|
||||
machines := make([]*Machine, 0, len(results))
|
||||
for _, machineAPI := range results {
|
||||
native, err := machineAPI.toNative()
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("unable to convert API response for machines to native type: {{err}}", err)
|
||||
}
|
||||
machines = append(machines, native)
|
||||
}
|
||||
return machines, nil
|
||||
}
|
||||
|
||||
type CreateMachineInput struct {
|
||||
Name string
|
||||
Package string
|
||||
Image string
|
||||
Networks []string
|
||||
LocalityStrict bool
|
||||
LocalityNear []string
|
||||
LocalityFar []string
|
||||
Metadata map[string]string
|
||||
Tags map[string]string
|
||||
FirewallEnabled bool
|
||||
CNS MachineCNS
|
||||
}
|
||||
|
||||
func (input *CreateMachineInput) toAPI() map[string]interface{} {
|
||||
const numExtraParams = 8
|
||||
result := make(map[string]interface{}, numExtraParams+len(input.Metadata)+len(input.Tags))
|
||||
|
||||
result["firewall_enabled"] = input.FirewallEnabled
|
||||
|
||||
if input.Name != "" {
|
||||
result["name"] = input.Name
|
||||
}
|
||||
|
||||
if input.Package != "" {
|
||||
result["package"] = input.Package
|
||||
}
|
||||
|
||||
if input.Image != "" {
|
||||
result["image"] = input.Image
|
||||
}
|
||||
|
||||
if len(input.Networks) > 0 {
|
||||
result["networks"] = input.Networks
|
||||
}
|
||||
|
||||
locality := struct {
|
||||
Strict bool `json:"strict"`
|
||||
Near []string `json:"near,omitempty"`
|
||||
Far []string `json:"far,omitempty"`
|
||||
}{
|
||||
Strict: input.LocalityStrict,
|
||||
Near: input.LocalityNear,
|
||||
Far: input.LocalityFar,
|
||||
}
|
||||
result["locality"] = locality
|
||||
for key, value := range input.Tags {
|
||||
result[fmt.Sprintf("tag.%s", key)] = value
|
||||
}
|
||||
|
||||
// Deliberately clobber any user-specified Tags with the attributes from the
|
||||
// CNS struct.
|
||||
input.CNS.toTags(result)
|
||||
|
||||
for key, value := range input.Metadata {
|
||||
result[fmt.Sprintf("metadata.%s", key)] = value
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (client *MachinesClient) CreateMachine(ctx context.Context, input *CreateMachineInput) (*Machine, error) {
|
||||
path := fmt.Sprintf("/%s/machines", client.accountName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPost, path, input.toAPI())
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing CreateMachine request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *Machine
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding CreateMachine response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type DeleteMachineInput struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) DeleteMachine(ctx context.Context, input *DeleteMachineInput) error {
|
||||
path := fmt.Sprintf("/%s/machines/%s", client.accountName, input.ID)
|
||||
response, err := client.executeRequestRaw(ctx, http.MethodDelete, path, nil)
|
||||
if response.Body != nil {
|
||||
defer response.Body.Close()
|
||||
}
|
||||
if response.StatusCode == http.StatusNotFound || response.StatusCode == http.StatusGone {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing DeleteMachine request: {{err}}",
|
||||
client.decodeError(response.StatusCode, response.Body))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type DeleteMachineTagsInput struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) DeleteMachineTags(ctx context.Context, input *DeleteMachineTagsInput) error {
|
||||
path := fmt.Sprintf("/%s/machines/%s/tags", client.accountName, input.ID)
|
||||
response, err := client.executeRequestRaw(ctx, http.MethodDelete, path, nil)
|
||||
if response.Body != nil {
|
||||
defer response.Body.Close()
|
||||
}
|
||||
if response.StatusCode == http.StatusNotFound {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing DeleteMachineTags request: {{err}}",
|
||||
client.decodeError(response.StatusCode, response.Body))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type DeleteMachineTagInput struct {
|
||||
ID string
|
||||
Key string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) DeleteMachineTag(ctx context.Context, input *DeleteMachineTagInput) error {
|
||||
path := fmt.Sprintf("/%s/machines/%s/tags/%s", client.accountName, input.ID, input.Key)
|
||||
response, err := client.executeRequestRaw(ctx, http.MethodDelete, path, nil)
|
||||
if response.Body != nil {
|
||||
defer response.Body.Close()
|
||||
}
|
||||
if response.StatusCode == http.StatusNotFound {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing DeleteMachineTag request: {{err}}",
|
||||
client.decodeError(response.StatusCode, response.Body))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type RenameMachineInput struct {
|
||||
ID string
|
||||
Name string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) RenameMachine(ctx context.Context, input *RenameMachineInput) error {
|
||||
path := fmt.Sprintf("/%s/machines/%s", client.accountName, input.ID)
|
||||
|
||||
params := &url.Values{}
|
||||
params.Set("action", "rename")
|
||||
params.Set("name", input.Name)
|
||||
|
||||
respReader, err := client.executeRequestURIParams(ctx, http.MethodPost, path, nil, params)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing RenameMachine request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ReplaceMachineTagsInput struct {
|
||||
ID string
|
||||
Tags map[string]string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) ReplaceMachineTags(ctx context.Context, input *ReplaceMachineTagsInput) error {
|
||||
path := fmt.Sprintf("/%s/machines/%s/tags", client.accountName, input.ID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPut, path, input.Tags)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing ReplaceMachineTags request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type AddMachineTagsInput struct {
|
||||
ID string
|
||||
Tags map[string]string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) AddMachineTags(ctx context.Context, input *AddMachineTagsInput) error {
|
||||
path := fmt.Sprintf("/%s/machines/%s/tags", client.accountName, input.ID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPost, path, input.Tags)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing AddMachineTags request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type GetMachineTagInput struct {
|
||||
ID string
|
||||
Key string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) GetMachineTag(ctx context.Context, input *GetMachineTagInput) (string, error) {
|
||||
path := fmt.Sprintf("/%s/machines/%s/tags/%s", client.accountName, input.ID, input.Key)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return "", errwrap.Wrapf("Error executing GetMachineTag request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result string
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return "", errwrap.Wrapf("Error decoding GetMachineTag response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type ListMachineTagsInput struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) ListMachineTags(ctx context.Context, input *ListMachineTagsInput) (map[string]string, error) {
|
||||
path := fmt.Sprintf("/%s/machines/%s/tags", client.accountName, input.ID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing ListMachineTags request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding ListMachineTags response: {{err}}", err)
|
||||
}
|
||||
|
||||
_, tags := machineTagsExtractMeta(result)
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
type UpdateMachineMetadataInput struct {
|
||||
ID string
|
||||
Metadata map[string]string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) UpdateMachineMetadata(ctx context.Context, input *UpdateMachineMetadataInput) (map[string]string, error) {
|
||||
path := fmt.Sprintf("/%s/machines/%s/tags", client.accountName, input.ID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPost, path, input.Metadata)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing UpdateMachineMetadata request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result map[string]string
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding UpdateMachineMetadata response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type ResizeMachineInput struct {
|
||||
ID string
|
||||
Package string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) ResizeMachine(ctx context.Context, input *ResizeMachineInput) error {
|
||||
path := fmt.Sprintf("/%s/machines/%s", client.accountName, input.ID)
|
||||
|
||||
params := &url.Values{}
|
||||
params.Set("action", "resize")
|
||||
params.Set("package", input.Package)
|
||||
|
||||
respReader, err := client.executeRequestURIParams(ctx, http.MethodPost, path, nil, params)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing ResizeMachine request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type EnableMachineFirewallInput struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) EnableMachineFirewall(ctx context.Context, input *EnableMachineFirewallInput) error {
|
||||
path := fmt.Sprintf("/%s/machines/%s", client.accountName, input.ID)
|
||||
|
||||
params := &url.Values{}
|
||||
params.Set("action", "enable_firewall")
|
||||
|
||||
respReader, err := client.executeRequestURIParams(ctx, http.MethodPost, path, nil, params)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing EnableMachineFirewall request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type DisableMachineFirewallInput struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) DisableMachineFirewall(ctx context.Context, input *DisableMachineFirewallInput) error {
|
||||
path := fmt.Sprintf("/%s/machines/%s", client.accountName, input.ID)
|
||||
|
||||
params := &url.Values{}
|
||||
params.Set("action", "disable_firewall")
|
||||
|
||||
respReader, err := client.executeRequestURIParams(ctx, http.MethodPost, path, nil, params)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing DisableMachineFirewall request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListNICsInput struct {
|
||||
MachineID string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) ListNICs(ctx context.Context, input *ListNICsInput) ([]*NIC, error) {
|
||||
path := fmt.Sprintf("/%s/machines/%s/nics", client.accountName, input.MachineID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing ListNICs request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result []*NIC
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding ListNICs response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type AddNICInput struct {
|
||||
MachineID string `json:"-"`
|
||||
Network string `json:"network"`
|
||||
}
|
||||
|
||||
func (client *MachinesClient) AddNIC(ctx context.Context, input *AddNICInput) (*NIC, error) {
|
||||
path := fmt.Sprintf("/%s/machines/%s/nics", client.accountName, input.MachineID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPost, path, input)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing AddNIC request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *NIC
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding AddNIC response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type RemoveNICInput struct {
|
||||
MachineID string
|
||||
MAC string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) RemoveNIC(ctx context.Context, input *RemoveNICInput) error {
|
||||
path := fmt.Sprintf("/%s/machines/%s/nics/%s", client.accountName, input.MachineID, input.MAC)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodDelete, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing RemoveNIC request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type StopMachineInput struct {
|
||||
MachineID string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) StopMachine(ctx context.Context, input *StopMachineInput) error {
|
||||
path := fmt.Sprintf("/%s/machines/%s", client.accountName, input.MachineID)
|
||||
|
||||
params := &url.Values{}
|
||||
params.Set("action", "stop")
|
||||
|
||||
respReader, err := client.executeRequestURIParams(ctx, http.MethodPost, path, nil, params)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing StopMachine request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type StartMachineInput struct {
|
||||
MachineID string
|
||||
}
|
||||
|
||||
func (client *MachinesClient) StartMachine(ctx context.Context, input *StartMachineInput) error {
|
||||
path := fmt.Sprintf("/%s/machines/%s", client.accountName, input.MachineID)
|
||||
|
||||
params := &url.Values{}
|
||||
params.Set("action", "start")
|
||||
|
||||
respReader, err := client.executeRequestURIParams(ctx, http.MethodPost, path, nil, params)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing StartMachine request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var reservedMachineCNSTags = map[string]struct{}{
|
||||
machineCNSTagDisable: {},
|
||||
machineCNSTagReversePTR: {},
|
||||
machineCNSTagServices: {},
|
||||
}
|
||||
|
||||
// machineTagsExtractMeta() extracts all of the misc parameters from Tags and
|
||||
// returns a clean CNS and Tags struct.
|
||||
func machineTagsExtractMeta(tags map[string]interface{}) (MachineCNS, map[string]string) {
|
||||
nativeCNS := MachineCNS{}
|
||||
nativeTags := make(map[string]string, len(tags))
|
||||
for k, raw := range tags {
|
||||
if _, found := reservedMachineCNSTags[k]; found {
|
||||
switch k {
|
||||
case machineCNSTagDisable:
|
||||
b := raw.(bool)
|
||||
nativeCNS.Disable = &b
|
||||
case machineCNSTagReversePTR:
|
||||
s := raw.(string)
|
||||
nativeCNS.ReversePTR = &s
|
||||
case machineCNSTagServices:
|
||||
nativeCNS.Services = strings.Split(raw.(string), ",")
|
||||
default:
|
||||
// TODO(seanc@): should assert, logic fail
|
||||
}
|
||||
} else {
|
||||
nativeTags[k] = raw.(string)
|
||||
}
|
||||
}
|
||||
|
||||
return nativeCNS, nativeTags
|
||||
}
|
||||
|
||||
// toNative() exports a given _Machine (API representation) to its native object
|
||||
// format.
|
||||
func (api *_Machine) toNative() (*Machine, error) {
|
||||
m := Machine(api.Machine)
|
||||
m.CNS, m.Tags = machineTagsExtractMeta(api.Tags)
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
// toTags() injects its state information into a Tags map suitable for use to
|
||||
// submit an API call to the vmapi machine endpoint
|
||||
func (mcns *MachineCNS) toTags(m map[string]interface{}) {
|
||||
if mcns.Disable != nil {
|
||||
s := fmt.Sprintf("%t", mcns.Disable)
|
||||
m[machineCNSTagDisable] = &s
|
||||
}
|
||||
|
||||
if mcns.ReversePTR != nil {
|
||||
m[machineCNSTagReversePTR] = &mcns.ReversePTR
|
||||
}
|
||||
|
||||
if len(mcns.Services) > 0 {
|
||||
m[machineCNSTagServices] = strings.Join(mcns.Services, ",")
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
triton "github.com/joyent/triton-go"
|
||||
"github.com/joyent/triton-go/client"
|
||||
)
|
||||
|
||||
type NetworkClient struct {
|
||||
Client *client.Client
|
||||
}
|
||||
|
||||
func newNetworkClient(client *client.Client) *NetworkClient {
|
||||
return &NetworkClient{
|
||||
Client: client,
|
||||
}
|
||||
}
|
||||
|
||||
// NewClient returns a new client for working with Network endpoints and
|
||||
// resources within CloudAPI
|
||||
func NewClient(config *triton.ClientConfig) (*NetworkClient, error) {
|
||||
// TODO: Utilize config interface within the function itself
|
||||
client, err := client.New(config.TritonURL, config.MantaURL, config.AccountName, config.Signers...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newNetworkClient(client), nil
|
||||
}
|
||||
|
||||
// Fabrics returns a FabricsClient used for accessing functions pertaining to
|
||||
// Fabric functionality in the Triton API.
|
||||
func (c *NetworkClient) Fabrics() *FabricsClient {
|
||||
return &FabricsClient{c.Client}
|
||||
}
|
||||
|
||||
// Firewall returns a FirewallClient client used for accessing functions
|
||||
// pertaining to firewall functionality in the Triton API.
|
||||
func (c *NetworkClient) Firewall() *FirewallClient {
|
||||
return &FirewallClient{c.Client}
|
||||
}
|
||||
@ -0,0 +1,269 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/joyent/triton-go/client"
|
||||
)
|
||||
|
||||
type FabricsClient struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
type FabricVLAN struct {
|
||||
Name string `json:"name"`
|
||||
ID int `json:"vlan_id"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type ListVLANsInput struct{}
|
||||
|
||||
func (c *FabricsClient) ListVLANs(ctx context.Context, _ *ListVLANsInput) ([]*FabricVLAN, error) {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans", c.client.AccountName)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodGet,
|
||||
Path: path,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing ListVLANs request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result []*FabricVLAN
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding ListVLANs response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type CreateVLANInput struct {
|
||||
Name string `json:"name"`
|
||||
ID int `json:"vlan_id"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
func (c *FabricsClient) CreateVLAN(ctx context.Context, input *CreateVLANInput) (*FabricVLAN, error) {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans", c.client.AccountName)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodPost,
|
||||
Path: path,
|
||||
Body: input,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing CreateVLAN request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FabricVLAN
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding CreateVLAN response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type UpdateVLANInput struct {
|
||||
ID int `json:"-"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func (c *FabricsClient) UpdateVLAN(ctx context.Context, input *UpdateVLANInput) (*FabricVLAN, error) {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d", c.client.AccountName, input.ID)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodPut,
|
||||
Path: path,
|
||||
Body: input,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing UpdateVLAN request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FabricVLAN
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding UpdateVLAN response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type GetVLANInput struct {
|
||||
ID int `json:"-"`
|
||||
}
|
||||
|
||||
func (c *FabricsClient) GetVLAN(ctx context.Context, input *GetVLANInput) (*FabricVLAN, error) {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d", c.client.AccountName, input.ID)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodGet,
|
||||
Path: path,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing GetVLAN request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FabricVLAN
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding GetVLAN response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type DeleteVLANInput struct {
|
||||
ID int `json:"-"`
|
||||
}
|
||||
|
||||
func (c *FabricsClient) DeleteVLAN(ctx context.Context, input *DeleteVLANInput) error {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d", c.client.AccountName, input.ID)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodDelete,
|
||||
Path: path,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing DeleteVLAN request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListFabricsInput struct {
|
||||
FabricVLANID int `json:"-"`
|
||||
}
|
||||
|
||||
func (c *FabricsClient) List(ctx context.Context, input *ListFabricsInput) ([]*Network, error) {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d/networks", c.client.AccountName, input.FabricVLANID)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodGet,
|
||||
Path: path,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing ListFabrics request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result []*Network
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding ListFabrics response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type CreateFabricInput struct {
|
||||
FabricVLANID int `json:"-"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Subnet string `json:"subnet"`
|
||||
ProvisionStartIP string `json:"provision_start_ip"`
|
||||
ProvisionEndIP string `json:"provision_end_ip"`
|
||||
Gateway string `json:"gateway,omitempty"`
|
||||
Resolvers []string `json:"resolvers,omitempty"`
|
||||
Routes map[string]string `json:"routes,omitempty"`
|
||||
InternetNAT bool `json:"internet_nat"`
|
||||
}
|
||||
|
||||
func (c *FabricsClient) Create(ctx context.Context, input *CreateFabricInput) (*Network, error) {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d/networks", c.client.AccountName, input.FabricVLANID)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodPost,
|
||||
Path: path,
|
||||
Body: input,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing CreateFabric request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *Network
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding CreateFabric response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type GetFabricInput struct {
|
||||
FabricVLANID int `json:"-"`
|
||||
NetworkID string `json:"-"`
|
||||
}
|
||||
|
||||
func (c *FabricsClient) Get(ctx context.Context, input *GetFabricInput) (*Network, error) {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d/networks/%s", c.client.AccountName, input.FabricVLANID, input.NetworkID)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodGet,
|
||||
Path: path,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing GetFabric request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *Network
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding GetFabric response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type DeleteFabricInput struct {
|
||||
FabricVLANID int `json:"-"`
|
||||
NetworkID string `json:"-"`
|
||||
}
|
||||
|
||||
func (c *FabricsClient) Delete(ctx context.Context, input *DeleteFabricInput) error {
|
||||
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d/networks/%s", c.client.AccountName, input.FabricVLANID, input.NetworkID)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodDelete,
|
||||
Path: path,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing DeleteFabric request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -0,0 +1,250 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/joyent/triton-go/client"
|
||||
)
|
||||
|
||||
type FirewallClient struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// FirewallRule represents a firewall rule
|
||||
type FirewallRule struct {
|
||||
// ID is a unique identifier for this rule
|
||||
ID string `json:"id"`
|
||||
|
||||
// Enabled indicates if the rule is enabled
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// Rule is the firewall rule text
|
||||
Rule string `json:"rule"`
|
||||
|
||||
// Global indicates if the rule is global. Optional.
|
||||
Global bool `json:"global"`
|
||||
|
||||
// Description is a human-readable description for the rule. Optional
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type ListRulesInput struct{}
|
||||
|
||||
func (c *FirewallClient) ListRules(ctx context.Context, _ *ListRulesInput) ([]*FirewallRule, error) {
|
||||
path := fmt.Sprintf("/%s/fwrules", c.client.AccountName)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodGet,
|
||||
Path: path,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing ListRules request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result []*FirewallRule
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding ListRules response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type GetRuleInput struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func (c *FirewallClient) GetRule(ctx context.Context, input *GetRuleInput) (*FirewallRule, error) {
|
||||
path := fmt.Sprintf("/%s/fwrules/%s", c.client.AccountName, input.ID)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodGet,
|
||||
Path: path,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing GetRule request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FirewallRule
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding GetRule response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type CreateRuleInput struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Rule string `json:"rule"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
func (c *FirewallClient) CreateRule(ctx context.Context, input *CreateRuleInput) (*FirewallRule, error) {
|
||||
path := fmt.Sprintf("/%s/fwrules", c.client.AccountName)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodPost,
|
||||
Path: path,
|
||||
Body: input,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing CreateRule request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FirewallRule
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding CreateRule response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type UpdateRuleInput struct {
|
||||
ID string `json:"-"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Rule string `json:"rule"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
func (c *FirewallClient) UpdateRule(ctx context.Context, input *UpdateRuleInput) (*FirewallRule, error) {
|
||||
path := fmt.Sprintf("/%s/fwrules/%s", c.client.AccountName, input.ID)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodPost,
|
||||
Path: path,
|
||||
Body: input,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing UpdateRule request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FirewallRule
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding UpdateRule response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type EnableRuleInput struct {
|
||||
ID string `json:"-"`
|
||||
}
|
||||
|
||||
func (c *FirewallClient) EnableRule(ctx context.Context, input *EnableRuleInput) (*FirewallRule, error) {
|
||||
path := fmt.Sprintf("/%s/fwrules/%s/enable", c.client.AccountName, input.ID)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodPost,
|
||||
Path: path,
|
||||
Body: input,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing EnableRule request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FirewallRule
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding EnableRule response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type DisableRuleInput struct {
|
||||
ID string `json:"-"`
|
||||
}
|
||||
|
||||
func (c *FirewallClient) DisableRule(ctx context.Context, input *DisableRuleInput) (*FirewallRule, error) {
|
||||
path := fmt.Sprintf("/%s/fwrules/%s/disable", c.client.AccountName, input.ID)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodPost,
|
||||
Path: path,
|
||||
Body: input,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing DisableRule request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *FirewallRule
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding DisableRule response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type DeleteRuleInput struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func (c *FirewallClient) DeleteRule(ctx context.Context, input *DeleteRuleInput) error {
|
||||
path := fmt.Sprintf("/%s/fwrules/%s", c.client.AccountName, input.ID)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodDelete,
|
||||
Path: path,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing DeleteRule request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListMachineRulesInput struct {
|
||||
MachineID string
|
||||
}
|
||||
|
||||
func (c *FirewallClient) ListMachineRules(ctx context.Context, input *ListMachineRulesInput) ([]*FirewallRule, error) {
|
||||
path := fmt.Sprintf("/%s/machines/%s/firewallrules", c.client.AccountName, input.MachineID)
|
||||
reqInputs := client.RequestInput{
|
||||
Method: http.MethodGet,
|
||||
Path: path,
|
||||
}
|
||||
respReader, err := c.client.ExecuteRequest(ctx, reqInputs)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing ListMachineRules request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result []*FirewallRule
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding ListRules response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@ -1,164 +0,0 @@
|
||||
package triton
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
)
|
||||
|
||||
type RolesClient struct {
|
||||
*Client
|
||||
}
|
||||
|
||||
// Roles returns a c used for accessing functions pertaining
|
||||
// to Role functionality in the Triton API.
|
||||
func (c *Client) Roles() *RolesClient {
|
||||
return &RolesClient{c}
|
||||
}
|
||||
|
||||
type Role struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Policies []string `json:"policies"`
|
||||
Members []string `json:"policies"`
|
||||
DefaultMembers []string `json:"default_members"`
|
||||
}
|
||||
|
||||
type ListRolesInput struct{}
|
||||
|
||||
func (client *RolesClient) ListRoles(ctx context.Context, _ *ListRolesInput) ([]*Role, error) {
|
||||
path := fmt.Sprintf("/%s/roles", client.accountName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing ListRoles request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result []*Role
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding ListRoles response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type GetRoleInput struct {
|
||||
RoleID string
|
||||
}
|
||||
|
||||
func (client *RolesClient) GetRole(ctx context.Context, input *GetRoleInput) (*Role, error) {
|
||||
path := fmt.Sprintf("/%s/roles/%s", client.accountName, input.RoleID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodGet, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing GetRole request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *Role
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding GetRole response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CreateRoleInput represents the options that can be specified
|
||||
// when creating a new role.
|
||||
type CreateRoleInput struct {
|
||||
// Name of the role. Required.
|
||||
Name string `json:"name"`
|
||||
|
||||
// This account's policies to be given to this role. Optional.
|
||||
Policies []string `json:"policies,omitempty"`
|
||||
|
||||
// This account's user logins to be added to this role. Optional.
|
||||
Members []string `json:"members,omitempty"`
|
||||
|
||||
// This account's user logins to be added to this role and have
|
||||
// it enabled by default. Optional.
|
||||
DefaultMembers []string `json:"default_members,omitempty"`
|
||||
}
|
||||
|
||||
func (client *RolesClient) CreateRole(ctx context.Context, input *CreateRoleInput) (*Role, error) {
|
||||
path := fmt.Sprintf("/%s/roles", client.accountName)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPost, path, input)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing CreateRole request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *Role
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding CreateRole response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// UpdateRoleInput represents the options that can be specified
|
||||
// when updating a role. Anything but ID can be modified.
|
||||
type UpdateRoleInput struct {
|
||||
// ID of the role to modify. Required.
|
||||
RoleID string `json:"id"`
|
||||
|
||||
// Name of the role. Required.
|
||||
Name string `json:"name"`
|
||||
|
||||
// This account's policies to be given to this role. Optional.
|
||||
Policies []string `json:"policies,omitempty"`
|
||||
|
||||
// This account's user logins to be added to this role. Optional.
|
||||
Members []string `json:"members,omitempty"`
|
||||
|
||||
// This account's user logins to be added to this role and have
|
||||
// it enabled by default. Optional.
|
||||
DefaultMembers []string `json:"default_members,omitempty"`
|
||||
}
|
||||
|
||||
func (client *RolesClient) UpdateRole(ctx context.Context, input *UpdateRoleInput) (*Role, error) {
|
||||
path := fmt.Sprintf("/%s/roles/%s", client.accountName, input.RoleID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodPost, path, input)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("Error executing UpdateRole request: {{err}}", err)
|
||||
}
|
||||
|
||||
var result *Role
|
||||
decoder := json.NewDecoder(respReader)
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, errwrap.Wrapf("Error decoding UpdateRole response: {{err}}", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type DeleteRoleInput struct {
|
||||
RoleID string
|
||||
}
|
||||
|
||||
func (client *RolesClient) DeleteRoles(ctx context.Context, input *DeleteRoleInput) error {
|
||||
path := fmt.Sprintf("/%s/roles/%s", client.accountName, input.RoleID)
|
||||
respReader, err := client.executeRequest(ctx, http.MethodDelete, path, nil)
|
||||
if respReader != nil {
|
||||
defer respReader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Error executing DeleteRole request: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package triton
|
||||
|
||||
import (
|
||||
"github.com/joyent/triton-go/authentication"
|
||||
)
|
||||
|
||||
// Universal package used for defining configuration used across all client
|
||||
// constructors.
|
||||
|
||||
// ClientConfig is a placeholder/input struct around the behavior of configuring
|
||||
// a client constructor through the implementation's runtime environment
|
||||
// (SDC/MANTA env vars).
|
||||
type ClientConfig struct {
|
||||
TritonURL string
|
||||
MantaURL string
|
||||
AccountName string
|
||||
Signers []authentication.Signer
|
||||
}
|
||||
Loading…
Reference in new issue