deps: Add joyent/triton-go

This commit is contained in:
James Nugent 2017-04-26 12:12:57 -07:00
parent 648b7f471b
commit 237180a95b
28 changed files with 4054 additions and 0 deletions

363
vendor/github.com/hashicorp/go-retryablehttp/LICENSE generated vendored Normal file
View File

@ -0,0 +1,363 @@
Mozilla Public License, version 2.0
1. Definitions
1.1. "Contributor"
means each individual or legal entity that creates, contributes to the
creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used by a
Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached the
notice in Exhibit A, the Executable Form of such Source Code Form, and
Modifications of such Source Code Form, in each case including portions
thereof.
1.5. "Incompatible With Secondary Licenses"
means
a. that the initial Contributor has attached the notice described in
Exhibit B to the Covered Software; or
b. that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the terms of
a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in a
separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible, whether
at the time of the initial grant or subsequently, any and all of the
rights conveyed by this License.
1.10. "Modifications"
means any of the following:
a. any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered Software; or
b. any new file in Source Code Form that contains any Covered Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the License,
by the making, using, selling, offering for sale, having made, import,
or transfer of either its Contributions or its Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU Lesser
General Public License, Version 2.1, the GNU Affero General Public
License, Version 3.0, or any later versions of those licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that controls, is
controlled by, or is under common control with You. For purposes of this
definition, "control" means (a) the power, direct or indirect, to cause
the direction or management of such entity, whether by contract or
otherwise, or (b) ownership of more than fifty percent (50%) of the
outstanding shares or beneficial ownership of such entity.
2. License Grants and Conditions
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
a. under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
b. under Patent Claims of such Contributor to make, use, sell, offer for
sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
a. for any code that a Contributor has removed from Covered Software; or
b. for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
c. under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights to
grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
Section 2.1.
3. Responsibilities
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
a. such Covered Software must also be made available in Source Code Form,
as described in Section 3.1, and You must inform recipients of the
Executable Form how they can obtain a copy of such Source Code Form by
reasonable means in a timely manner, at a charge no more than the cost
of distribution to the recipient; and
b. You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter the
recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty, or
limitations of liability) contained within the Source Code Form of the
Covered Software, except that You may alter any license notices to the
extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
If it is impossible for You to comply with any of the terms of this License
with respect to some or all of the Covered Software due to statute,
judicial order, or regulation then You must: (a) comply with the terms of
this License to the maximum extent possible; and (b) describe the
limitations and the code they affect. Such description must be placed in a
text file included with all distributions of the Covered Software under
this License. Except to the extent prohibited by statute or regulation,
such description must be sufficiently detailed for a recipient of ordinary
skill to be able to understand it.
5. Termination
5.1. The rights granted under this License will terminate automatically if You
fail to comply with any of its terms. However, if You become compliant,
then the rights granted under this License from a particular Contributor
are reinstated (a) provisionally, unless and until such Contributor
explicitly and finally terminates Your grants, and (b) on an ongoing
basis, if such Contributor fails to notify You of the non-compliance by
some reasonable means prior to 60 days after You have come back into
compliance. Moreover, Your grants from a particular Contributor are
reinstated on an ongoing basis if such Contributor notifies You of the
non-compliance by some reasonable means, this is the first time You have
received notice of non-compliance with this License from such
Contributor, and You become compliant prior to 30 days after Your receipt
of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
license agreements (excluding distributors and resellers) which have been
validly granted by You or Your distributors under this License prior to
termination shall survive termination.
6. Disclaimer of Warranty
Covered Software is provided under this License on an "as is" basis,
without warranty of any kind, either expressed, implied, or statutory,
including, without limitation, warranties that the Covered Software is free
of defects, merchantable, fit for a particular purpose or non-infringing.
The entire risk as to the quality and performance of the Covered Software
is with You. Should any Covered Software prove defective in any respect,
You (not any Contributor) assume the cost of any necessary servicing,
repair, or correction. This disclaimer of warranty constitutes an essential
part of this License. No use of any Covered Software is authorized under
this License except under this disclaimer.
7. Limitation of Liability
Under no circumstances and under no legal theory, whether tort (including
negligence), contract, or otherwise, shall any Contributor, or anyone who
distributes Covered Software as permitted above, be liable to You for any
direct, indirect, special, incidental, or consequential damages of any
character including, without limitation, damages for lost profits, loss of
goodwill, work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses, even if such party shall have been
informed of the possibility of such damages. This limitation of liability
shall not apply to liability for death or personal injury resulting from
such party's negligence to the extent applicable law prohibits such
limitation. Some jurisdictions do not allow the exclusion or limitation of
incidental or consequential damages, so this exclusion and limitation may
not apply to You.
8. Litigation
Any litigation relating to this License may be brought only in the courts
of a jurisdiction where the defendant maintains its principal place of
business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions. Nothing
in this Section shall prevent a party's ability to bring cross-claims or
counter-claims.
9. Miscellaneous
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides that
the language of a contract shall be construed against the drafter shall not
be used to construe this License against a Contributor.
10. Versions of the License
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses If You choose to distribute Source Code Form that is
Incompatible With Secondary Licenses under the terms of this version of
the License, the notice described in Exhibit B of this License must be
attached.
Exhibit A - Source Code Form License Notice
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular file,
then You may include the notice in a location (such as a LICENSE file in a
relevant directory) where a recipient would be likely to look for such a
notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
This Source Code Form is "Incompatible
With Secondary Licenses", as defined by
the Mozilla Public License, v. 2.0.

11
vendor/github.com/hashicorp/go-retryablehttp/Makefile generated vendored Normal file
View File

@ -0,0 +1,11 @@
default: test
test:
go vet ./...
go test -race ./...
updatedeps:
go get -f -t -u ./...
go get -f -u ./...
.PHONY: default test updatedeps

43
vendor/github.com/hashicorp/go-retryablehttp/README.md generated vendored Normal file
View File

@ -0,0 +1,43 @@
go-retryablehttp
================
[![Build Status](http://img.shields.io/travis/hashicorp/go-retryablehttp.svg?style=flat-square)][travis]
[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs]
[travis]: http://travis-ci.org/hashicorp/go-retryablehttp
[godocs]: http://godoc.org/github.com/hashicorp/go-retryablehttp
The `retryablehttp` package provides a familiar HTTP client interface with
automatic retries and exponential backoff. It is a thin wrapper over the
standard `net/http` client library and exposes nearly the same public API. This
makes `retryablehttp` very easy to drop into existing programs.
`retryablehttp` performs automatic retries under certain conditions. Mainly, if
an error is returned by the client (connection errors, etc.), or if a 500-range
response code is received, then a retry is invoked after a wait period.
Otherwise, the response is returned and left to the caller to interpret.
The main difference from `net/http` is that requests which take a request body
(POST/PUT et. al) require an `io.ReadSeeker` to be provided. This enables the
request body to be "rewound" if the initial request fails so that the full
request can be attempted again.
Example Use
===========
Using this library should look almost identical to what you would do with
`net/http`. The most simple example of a GET request is shown below:
```go
resp, err := retryablehttp.Get("/foo")
if err != nil {
panic(err)
}
```
The returned response object is an `*http.Response`, the same thing you would
usually get from `net/http`. Had the request failed one or more times, the above
call would block and retry with exponential backoff.
For more usage and examples see the
[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp).

302
vendor/github.com/hashicorp/go-retryablehttp/client.go generated vendored Normal file
View File

@ -0,0 +1,302 @@
// The retryablehttp package provides a familiar HTTP client interface with
// automatic retries and exponential backoff. It is a thin wrapper over the
// standard net/http client library and exposes nearly the same public API.
// This makes retryablehttp very easy to drop into existing programs.
//
// retryablehttp performs automatic retries under certain conditions. Mainly, if
// an error is returned by the client (connection errors etc), or if a 500-range
// response is received, then a retry is invoked. Otherwise, the response is
// returned and left to the caller to interpret.
//
// The main difference from net/http is that requests which take a request body
// (POST/PUT et. al) require an io.ReadSeeker to be provided. This enables the
// request body to be "rewound" if the initial request fails so that the full
// request can be attempted again.
package retryablehttp
import (
"fmt"
"io"
"io/ioutil"
"log"
"math"
"net/http"
"net/url"
"os"
"strings"
"time"
"github.com/hashicorp/go-cleanhttp"
)
var (
// Default retry configuration
defaultRetryWaitMin = 1 * time.Second
defaultRetryWaitMax = 30 * time.Second
defaultRetryMax = 4
// defaultClient is used for performing requests without explicitly making
// a new client. It is purposely private to avoid modifications.
defaultClient = NewClient()
// We need to consume response bodies to maintain http connections, but
// limit the size we consume to respReadLimit.
respReadLimit = int64(4096)
)
// LenReader is an interface implemented by many in-memory io.Reader's. Used
// for automatically sending the right Content-Length header when possible.
type LenReader interface {
Len() int
}
// Request wraps the metadata needed to create HTTP requests.
type Request struct {
// body is a seekable reader over the request body payload. This is
// used to rewind the request data in between retries.
body io.ReadSeeker
// Embed an HTTP request directly. This makes a *Request act exactly
// like an *http.Request so that all meta methods are supported.
*http.Request
}
// NewRequest creates a new wrapped request.
func NewRequest(method, url string, body io.ReadSeeker) (*Request, error) {
// Wrap the body in a noop ReadCloser if non-nil. This prevents the
// reader from being closed by the HTTP client.
var rcBody io.ReadCloser
if body != nil {
rcBody = ioutil.NopCloser(body)
}
// Make the request with the noop-closer for the body.
httpReq, err := http.NewRequest(method, url, rcBody)
if err != nil {
return nil, err
}
// Check if we can set the Content-Length automatically.
if lr, ok := body.(LenReader); ok {
httpReq.ContentLength = int64(lr.Len())
}
return &Request{body, httpReq}, nil
}
// RequestLogHook allows a function to run before each retry. The HTTP
// request which will be made, and the retry number (0 for the initial
// request) are available to users. The internal logger is exposed to
// consumers.
type RequestLogHook func(*log.Logger, *http.Request, int)
// ResponseLogHook is like RequestLogHook, but allows running a function
// on each HTTP response. This function will be invoked at the end of
// every HTTP request executed, regardless of whether a subsequent retry
// needs to be performed or not. If the response body is read or closed
// from this method, this will affect the response returned from Do().
type ResponseLogHook func(*log.Logger, *http.Response)
// CheckRetry specifies a policy for handling retries. It is called
// following each request with the response and error values returned by
// the http.Client. If CheckRetry returns false, the Client stops retrying
// and returns the response to the caller. If CheckRetry returns an error,
// that error value is returned in lieu of the error from the request. The
// Client will close any response body when retrying, but if the retry is
// aborted it is up to the CheckResponse callback to properly close any
// response body before returning.
type CheckRetry func(resp *http.Response, err error) (bool, error)
// Client is used to make HTTP requests. It adds additional functionality
// like automatic retries to tolerate minor outages.
type Client struct {
HTTPClient *http.Client // Internal HTTP client.
Logger *log.Logger // Customer logger instance.
RetryWaitMin time.Duration // Minimum time to wait
RetryWaitMax time.Duration // Maximum time to wait
RetryMax int // Maximum number of retries
// RequestLogHook allows a user-supplied function to be called
// before each retry.
RequestLogHook RequestLogHook
// ResponseLogHook allows a user-supplied function to be called
// with the response from each HTTP request executed.
ResponseLogHook ResponseLogHook
// CheckRetry specifies the policy for handling retries, and is called
// after each request. The default policy is DefaultRetryPolicy.
CheckRetry CheckRetry
}
// NewClient creates a new Client with default settings.
func NewClient() *Client {
return &Client{
HTTPClient: cleanhttp.DefaultClient(),
Logger: log.New(os.Stderr, "", log.LstdFlags),
RetryWaitMin: defaultRetryWaitMin,
RetryWaitMax: defaultRetryWaitMax,
RetryMax: defaultRetryMax,
CheckRetry: DefaultRetryPolicy,
}
}
// DefaultRetryPolicy provides a default callback for Client.CheckRetry, which
// will retry on connection errors and server errors.
func DefaultRetryPolicy(resp *http.Response, err error) (bool, error) {
if err != nil {
return true, err
}
// Check the response code. We retry on 500-range responses to allow
// the server time to recover, as 500's are typically not permanent
// errors and may relate to outages on the server side. This will catch
// invalid response codes as well, like 0 and 999.
if resp.StatusCode == 0 || resp.StatusCode >= 500 {
return true, nil
}
return false, nil
}
// Do wraps calling an HTTP method with retries.
func (c *Client) Do(req *Request) (*http.Response, error) {
c.Logger.Printf("[DEBUG] %s %s", req.Method, req.URL)
for i := 0; ; i++ {
var code int // HTTP response code
// Always rewind the request body when non-nil.
if req.body != nil {
if _, err := req.body.Seek(0, 0); err != nil {
return nil, fmt.Errorf("failed to seek body: %v", err)
}
}
if c.RequestLogHook != nil {
c.RequestLogHook(c.Logger, req.Request, i)
}
// Attempt the request
resp, err := c.HTTPClient.Do(req.Request)
// Check if we should continue with retries.
checkOK, checkErr := c.CheckRetry(resp, err)
if err != nil {
c.Logger.Printf("[ERR] %s %s request failed: %v", req.Method, req.URL, err)
} else {
// Call this here to maintain the behavior of logging all requests,
// even if CheckRetry signals to stop.
if c.ResponseLogHook != nil {
// Call the response logger function if provided.
c.ResponseLogHook(c.Logger, resp)
}
}
// Now decide if we should continue.
if !checkOK {
if checkErr != nil {
err = checkErr
}
return resp, err
}
// We're going to retry, consume any response to reuse the connection.
if err == nil {
c.drainBody(resp.Body)
}
remain := c.RetryMax - i
if remain == 0 {
break
}
wait := backoff(c.RetryWaitMin, c.RetryWaitMax, i)
desc := fmt.Sprintf("%s %s", req.Method, req.URL)
if code > 0 {
desc = fmt.Sprintf("%s (status: %d)", desc, code)
}
c.Logger.Printf("[DEBUG] %s: retrying in %s (%d left)", desc, wait, remain)
time.Sleep(wait)
}
// Return an error if we fall out of the retry loop
return nil, fmt.Errorf("%s %s giving up after %d attempts",
req.Method, req.URL, c.RetryMax+1)
}
// Try to read the response body so we can reuse this connection.
func (c *Client) drainBody(body io.ReadCloser) {
defer body.Close()
_, err := io.Copy(ioutil.Discard, io.LimitReader(body, respReadLimit))
if err != nil {
c.Logger.Printf("[ERR] error reading response body: %v", err)
}
}
// Get is a shortcut for doing a GET request without making a new client.
func Get(url string) (*http.Response, error) {
return defaultClient.Get(url)
}
// Get is a convenience helper for doing simple GET requests.
func (c *Client) Get(url string) (*http.Response, error) {
req, err := NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
return c.Do(req)
}
// Head is a shortcut for doing a HEAD request without making a new client.
func Head(url string) (*http.Response, error) {
return defaultClient.Head(url)
}
// Head is a convenience method for doing simple HEAD requests.
func (c *Client) Head(url string) (*http.Response, error) {
req, err := NewRequest("HEAD", url, nil)
if err != nil {
return nil, err
}
return c.Do(req)
}
// Post is a shortcut for doing a POST request without making a new client.
func Post(url, bodyType string, body io.ReadSeeker) (*http.Response, error) {
return defaultClient.Post(url, bodyType, body)
}
// Post is a convenience method for doing simple POST requests.
func (c *Client) Post(url, bodyType string, body io.ReadSeeker) (*http.Response, error) {
req, err := NewRequest("POST", url, body)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", bodyType)
return c.Do(req)
}
// PostForm is a shortcut to perform a POST with form data without creating
// a new client.
func PostForm(url string, data url.Values) (*http.Response, error) {
return defaultClient.PostForm(url, data)
}
// PostForm is a convenience method for doing simple POST operations using
// pre-filled url.Values form data.
func (c *Client) PostForm(url string, data url.Values) (*http.Response, error) {
return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}
// backoff is used to calculate how long to sleep before retrying
// after observing failures. It takes the minimum/maximum wait time and
// iteration, and returns the duration to wait.
func backoff(min, max time.Duration, iter int) time.Duration {
mult := math.Pow(2, float64(iter)) * float64(min)
sleep := time.Duration(mult)
if float64(sleep) != mult || sleep > max {
sleep = max
}
return sleep
}

373
vendor/github.com/joyent/triton-go/LICENSE generated vendored Normal file
View File

@ -0,0 +1,373 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

216
vendor/github.com/joyent/triton-go/README.md generated vendored Normal file
View File

@ -0,0 +1,216 @@
# triton-go
`go-triton` is an idiomatic library exposing a client SDK for Go applications using the Joyent Triton API.
## Usage
Triton uses [HTTP Signature][4] to sign the Date header in each HTTP request made to the Triton API. Currently, requests can be signed using either a private key file loaded from disk (using an [`authentication.PrivateKeySigner`][5]), or using a key stored with the local SSH Agent (using an [`SSHAgentSigner`][6].
To construct a Signer, use the `New*` range of methods in the `authentication` package. In the case of `authentication.NewSSHAgentSigner`, the parameters are the fingerprint of the key with which to sign, and the account name (normally stored in the `SDC_ACCOUNT` environment variable). For example:
```
const fingerprint := "a4:c6:f3:75:80:27:e0:03:a9:98:79:ef:c5:0a:06:11"
sshKeySigner, err := authentication.NewSSHAgentSigner(fingerprint, "AccountName")
if err != nil {
log.Fatalf("NewSSHAgentSigner: %s", err)
}
```
An appropriate key fingerprint can be generated using `ssh-keygen`:
```
ssh-keygen -Emd5 -lf ~/.ssh/id_rsa.pub | cut -d " " -f 2 | sed 's/MD5://'
```
To construct a Client, use the `NewClient` function, passing in the endpoint, account name and constructed signer:
```go
client, err := triton.NewClient("https://us-sw-1.api.joyent.com/", "AccountName", sshKeySigner)
if err != nil {
log.Fatalf("NewClient: %s", err)
}
```
Having constructed a `triton.Client`, use the methods available to access functionality by functional grouping. For example, for access to operations on SSH keys, use the `Keys()` method to obtain a client which has access to the `CreateKey`, `ListKeys` and `DeleteKey` operations. For access to operations on Machines, use the `Machines()` method to obtain a client which has access to the `RenameMachine`, `GetMachineMetadata`, `GetMachineTag`, and other operations.
Operation methods take their formal parameters via a struct named `OperationInput` - for example when creating an SSH key, the `CreateKeyInput` struct is used with the `func CreateKey(*CreateKeyInput) (*Key, error)` method. This allows specification of named parameters:
```
client := state.Client().Keys()
key, err := client.CreateKey(&CreateKeyInput{
Name: "tempKey",
Key: "ssh-rsa .....",
})
if err != nil {
panic(err)
}
// Key contains the return value.
```
## Error Handling
If an error is returned by the HTTP API, the `error` returned from the function will contain an instance of `triton.TritonError` in the chain. Error wrapping is performed using the [errwrap][7] library from HashiCorp.
## Completeness
The following list is updated as new functionality is added. The complete list of operations is taken from the [CloudAPI documentation](https://apidocs.joyent.com/cloudapi).
- Accounts
- [x] GetAccount
- [x] UpdateAccount
- Keys
- [x] ListKeys
- [x] GetKey
- [x] CreateKey
- [x] DeleteKey
- Users
- [ ] ListUsers
- [ ] GetUser
- [ ] CreateUser
- [ ] UpdateUser
- [ ] ChangeUserPassword
- [ ] DeleteUser
- Roles
- [x] ListRoles
- [x] GetRole
- [x] CreateRole
- [x] UpdateRole
- [x] DeleteRole
- Role Tags
- [ ] SetRoleTags
- Policies
- [ ] ListPolicies
- [ ] GetPolicy
- [ ] CreatePolicy
- [ ] UpdatePolicy
- [ ] DeletePolicy
- User SSH Keys
- [x] ListUserKeys
- [x] GetUserKey
- [x] CreateUserKey
- [x] DeleteUserKey
- Config
- [x] GetConfig
- [x] UpdateConfig
- Datacenters
- [x] ListDatacenters
- [x] GetDatacenter
- Services
- [x] ListServices
- Images
- [x] ListImages
- [x] GetImage
- [x] DeleteImage
- [x] ExportImage
- [x] CreateImageFromMachine
- [x] UpdateImage
- Packages
- [x] ListPackages
- [x] GetPackage
- Instances
- [ ] ListMachines
- [x] GetMachine
- [x] CreateMachine
- [ ] StopMachine
- [ ] StartMachine
- [ ] RebootMachine
- [x] ResizeMachine
- [x] RenameMachine
- [x] EnableMachineFirewall
- [x] DisableMachineFirewall
- [ ] CreateMachineSnapshot
- [ ] StartMachineFromSnapshot
- [ ] ListMachineSnapshots
- [ ] GetMachineSnapshot
- [ ] DeleteMachineSnapshot
- [x] UpdateMachineMetadata
- [ ] ListMachineMetadata
- [ ] GetMachineMetadata
- [ ] DeleteMachineMetadata
- [ ] DeleteAllMachineMetadata
- [x] AddMachineTags
- [x] ReplaceMachineTags
- [x] ListMachineTags
- [x] GetMachineTag
- [x] DeleteMachineTag
- [x] DeleteMachineTags
- [x] DeleteMachine
- [ ] MachineAudit
- Analytics
- [ ] DescribeAnalytics
- [ ] ListInstrumentations
- [ ] GetInstrumentation
- [ ] GetInstrumentationValue
- [ ] GetInstrumentationHeatmap
- [ ] GetInstrumentationHeatmapDetails
- [ ] CreateInstrumentation
- [ ] DeleteInstrumentation
- Firewall Rules
- [x] ListFirewallRules
- [x] GetFirewallRule
- [x] CreateFirewallRule
- [x] UpdateFirewallRule
- [x] EnableFirewallRule
- [x] DisableFirewallRule
- [x] DeleteFirewallRule
- [ ] ListMachineFirewallRules
- [x] ListFirewallRuleMachines
- Fabrics
- [x] ListFabricVLANs
- [x] CreateFabricVLAN
- [x] GetFabricVLAN
- [x] UpdateFabricVLAN
- [x] DeleteFabricVLAN
- [x] ListFabricNetworks
- [x] CreateFabricNetwork
- [x] GetFabricNetwork
- [x] DeleteFabricNetwork
- Networks
- [x] ListNetworks
- [x] GetNetwork
- Nics
- [ ] ListNics
- [ ] GetNic
- [x] AddNic
- [x] RemoveNic
## Running Acceptance Tests
Acceptance Tests run directly against the Triton API, so you will need either a local installation or Triton or an account with Joyent in order to run them. The tests create real resources (and thus cost real money!)
In order to run acceptance tests, the following environment variables must be set:
- `TRITON_TEST` - must be set to any value in order to indicate desire to create resources
- `SDC_URL` - the base endpoint for the Triton API
- `SDC_ACCOUNT` - the account name for the Triton API
- `SDC_KEY_ID` - the fingerprint of the SSH key identifying the key
Additionally, you may set `SDC_KEY_MATERIAL` to the contents of an unencrypted private key. If this is set, the PrivateKeySigner (see above) will be used - if not the SSHAgentSigner will be used.
### Example Run
The verbose output has been removed for brevity here.
```
$ HTTP_PROXY=http://localhost:8888 \
TRITON_TEST=1 \
SDC_URL=https://us-sw-1.api.joyent.com \
SDC_ACCOUNT=AccountName \
SDC_KEY_ID=a4:c6:f3:75:80:27:e0:03:a9:98:79:ef:c5:0a:06:11 \
go test -v -run "TestAccKey"
=== RUN TestAccKey_Create
--- PASS: TestAccKey_Create (12.46s)
=== RUN TestAccKey_Get
--- PASS: TestAccKey_Get (4.30s)
=== RUN TestAccKey_Delete
--- PASS: TestAccKey_Delete (15.08s)
PASS
ok github.com/jen20/triton-go 31.861s
```
[4]: https://github.com/joyent/node-http-signature/blob/master/http_signing.md
[5]: https://godoc.org/github.com/joyent/go-triton/authentication
[6]: https://godoc.org/github.com/joyent/go-triton/authentication
[7]: https://github.com/hashicorp/go-errwrap

94
vendor/github.com/joyent/triton-go/accounts.go generated vendored Normal file
View File

@ -0,0 +1,94 @@
package triton
import (
"encoding/json"
"net/http"
"time"
"fmt"
"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(input *GetAccountInput) (*Account, error) {
path := fmt.Sprintf("/%s", client.accountName)
respReader, err := client.executeRequest(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(input *UpdateAccountInput) (*Account, error) {
respReader, err := client.executeRequest(http.MethodPost, fmt.Sprintf("/%s", client.accountName), 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
}

View File

@ -0,0 +1,66 @@
package authentication
import (
"encoding/asn1"
"encoding/base64"
"fmt"
"math/big"
"github.com/hashicorp/errwrap"
"golang.org/x/crypto/ssh"
)
type ecdsaSignature struct {
hashAlgorithm string
R *big.Int
S *big.Int
}
func (s *ecdsaSignature) SignatureType() string {
return fmt.Sprintf("ecdsa-%s", s.hashAlgorithm)
}
func (s *ecdsaSignature) String() string {
toEncode := struct {
R *big.Int
S *big.Int
}{
R: s.R,
S: s.S,
}
signatureBytes, err := asn1.Marshal(toEncode)
if err != nil {
panic(fmt.Sprintf("Error marshaling signature: %s", err))
}
return base64.StdEncoding.EncodeToString(signatureBytes)
}
func newECDSASignature(signatureBlob []byte) (*ecdsaSignature, error) {
var ecSig struct {
R *big.Int
S *big.Int
}
if err := ssh.Unmarshal(signatureBlob, &ecSig); err != nil {
return nil, errwrap.Wrapf("Error unmarshaling signature: {{err}}", err)
}
rValue := ecSig.R.Bytes()
var hashAlgorithm string
switch len(rValue) {
case 31, 32:
hashAlgorithm = "sha256"
case 65, 66:
hashAlgorithm = "sha512"
default:
return nil, fmt.Errorf("Unsupported key length: %d", len(rValue))
}
return &ecdsaSignature{
hashAlgorithm: hashAlgorithm,
R: ecSig.R,
S: ecSig.S,
}, nil
}

View File

@ -0,0 +1,76 @@
package authentication
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
"strings"
"github.com/hashicorp/errwrap"
"golang.org/x/crypto/ssh"
)
type PrivateKeySigner struct {
formattedKeyFingerprint string
keyFingerprint string
accountName string
hashFunc crypto.Hash
privateKey *rsa.PrivateKey
}
func NewPrivateKeySigner(keyFingerprint string, privateKeyMaterial []byte, accountName string) (*PrivateKeySigner, error) {
keyFingerprintMD5 := strings.Replace(keyFingerprint, ":", "", -1)
block, _ := pem.Decode(privateKeyMaterial)
if block == nil {
return nil, errors.New("Error PEM-decoding private key material: nil block received")
}
rsakey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, errwrap.Wrapf("Error parsing private key: {{err}}", err)
}
sshPublicKey, err := ssh.NewPublicKey(rsakey.Public())
if err != nil {
return nil, errwrap.Wrapf("Error parsing SSH key from private key: {{err}}", err)
}
matchKeyFingerprint := formatPublicKeyFingerprint(sshPublicKey, false)
displayKeyFingerprint := formatPublicKeyFingerprint(sshPublicKey, true)
if matchKeyFingerprint != keyFingerprintMD5 {
return nil, errors.New("Private key file does not match public key fingerprint")
}
return &PrivateKeySigner{
formattedKeyFingerprint: displayKeyFingerprint,
keyFingerprint: keyFingerprint,
accountName: accountName,
hashFunc: crypto.SHA1,
privateKey: rsakey,
}, nil
}
func (s *PrivateKeySigner) Sign(dateHeader string) (string, error) {
const headerName = "date"
hash := s.hashFunc.New()
hash.Write([]byte(fmt.Sprintf("%s: %s", headerName, dateHeader)))
digest := hash.Sum(nil)
signed, err := rsa.SignPKCS1v15(rand.Reader, s.privateKey, s.hashFunc, digest)
if err != nil {
return "", errwrap.Wrapf("Error signing date header: {{err}}", err)
}
signedBase64 := base64.StdEncoding.EncodeToString(signed)
keyID := fmt.Sprintf("/%s/keys/%s", s.accountName, s.formattedKeyFingerprint)
return fmt.Sprintf(authorizationHeaderFormat, keyID, "rsa-sha1", headerName, signedBase64), nil
}

View File

@ -0,0 +1,25 @@
package authentication
import (
"encoding/base64"
)
type rsaSignature struct {
hashAlgorithm string
signature []byte
}
func (s *rsaSignature) SignatureType() string {
return s.hashAlgorithm
}
func (s *rsaSignature) String() string {
return base64.StdEncoding.EncodeToString(s.signature)
}
func newRSASignature(signatureBlob []byte) (*rsaSignature, error) {
return &rsaSignature{
hashAlgorithm: "rsa-sha1",
signature: signatureBlob,
}, nil
}

View File

@ -0,0 +1,27 @@
package authentication
import (
"regexp"
"fmt"
)
type httpAuthSignature interface {
SignatureType() string
String() string
}
func keyFormatToKeyType(keyFormat string) (string, error) {
if keyFormat == "ssh-rsa" {
return "rsa", nil
}
if keyFormat == "ssh-ed25519" {
return "ed25519", nil
}
if regexp.MustCompile("^ecdsa-sha2-*").Match([]byte(keyFormat)) {
return "ecdsa", nil
}
return "", fmt.Errorf("Unknown key format: %s", keyFormat)
}

View File

@ -0,0 +1,7 @@
package authentication
const authorizationHeaderFormat = `Signature keyId="%s",algorithm="%s",headers="%s",signature="%s"`
type Signer interface {
Sign(dateHeader string) (string, error)
}

View File

@ -0,0 +1,104 @@
package authentication
import (
"crypto/md5"
"errors"
"fmt"
"net"
"os"
"strings"
"github.com/hashicorp/errwrap"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
type SSHAgentSigner struct {
formattedKeyFingerprint string
keyFingerprint string
accountName string
keyIdentifier string
agent agent.Agent
key ssh.PublicKey
}
func NewSSHAgentSigner(keyFingerprint, accountName string) (*SSHAgentSigner, error) {
sshAgentAddress := os.Getenv("SSH_AUTH_SOCK")
if sshAgentAddress == "" {
return nil, errors.New("SSH_AUTH_SOCK is not set")
}
conn, err := net.Dial("unix", sshAgentAddress)
if err != nil {
return nil, errwrap.Wrapf("Error dialing SSH agent: {{err}}", err)
}
ag := agent.NewClient(conn)
keys, err := ag.List()
if err != nil {
return nil, errwrap.Wrapf("Error listing keys in SSH Agent: %s", err)
}
keyFingerprintMD5 := strings.Replace(keyFingerprint, ":", "", -1)
var matchingKey ssh.PublicKey
for _, key := range keys {
h := md5.New()
h.Write(key.Marshal())
fp := fmt.Sprintf("%x", h.Sum(nil))
if fp == keyFingerprintMD5 {
matchingKey = key
}
}
if matchingKey == nil {
return nil, fmt.Errorf("No key in the SSH Agent matches fingerprint: %s", keyFingerprint)
}
formattedKeyFingerprint := formatPublicKeyFingerprint(matchingKey, true)
return &SSHAgentSigner{
formattedKeyFingerprint: formattedKeyFingerprint,
keyFingerprint: keyFingerprint,
accountName: accountName,
agent: ag,
key: matchingKey,
keyIdentifier: fmt.Sprintf("/%s/keys/%s", accountName, formattedKeyFingerprint),
}, nil
}
func (s *SSHAgentSigner) Sign(dateHeader string) (string, error) {
const headerName = "date"
signature, err := s.agent.Sign(s.key, []byte(fmt.Sprintf("%s: %s", headerName, dateHeader)))
if err != nil {
return "", errwrap.Wrapf("Error signing date header: {{err}}", err)
}
keyFormat, err := keyFormatToKeyType(signature.Format)
if err != nil {
return "", errwrap.Wrapf("Error reading signature: {{err}}", err)
}
var authSignature httpAuthSignature
switch keyFormat {
case "rsa":
authSignature, err = newRSASignature(signature.Blob)
if err != nil {
return "", errwrap.Wrapf("Error reading signature: {{err}}", err)
}
case "ecdsa":
authSignature, err = newECDSASignature(signature.Blob)
if err != nil {
return "", errwrap.Wrapf("Error reading signature: {{err}}", err)
}
default:
return "", fmt.Errorf("Unsupported algorithm from SSH agent: %s", signature.Format)
}
return fmt.Sprintf(authorizationHeaderFormat, s.keyIdentifier,
authSignature.SignatureType(), headerName, authSignature.String()), nil
}

View File

@ -0,0 +1,29 @@
package authentication
import (
"crypto/md5"
"fmt"
"strings"
"golang.org/x/crypto/ssh"
)
// formatPublicKeyFingerprint produces the MD5 fingerprint of the given SSH
// public key. If display is true, the fingerprint is formatted with colons
// between each byte, as per the output of OpenSSL.
func formatPublicKeyFingerprint(key ssh.PublicKey, display bool) string {
publicKeyFingerprint := md5.New()
publicKeyFingerprint.Write(key.Marshal())
publicKeyFingerprintString := fmt.Sprintf("%x", publicKeyFingerprint.Sum(nil))
if !display {
return publicKeyFingerprintString
}
formatted := ""
for i := 0; i < len(publicKeyFingerprintString); i = i + 2 {
formatted = fmt.Sprintf("%s%s:", formatted, publicKeyFingerprintString[i:i+2])
}
return strings.TrimSuffix(formatted, ":")
}

188
vendor/github.com/joyent/triton-go/client.go generated vendored Normal file
View File

@ -0,0 +1,188 @@
package triton
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net"
"net/http"
"net/url"
"os"
"time"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/go-retryablehttp"
"github.com/joyent/triton-go/authentication"
)
// Client represents a connection to the Triton API.
type Client struct {
client *retryablehttp.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) {
defaultRetryWaitMin := 1 * time.Second
defaultRetryWaitMax := 5 * time.Minute
defaultRetryMax := 32
apiURL, err := url.Parse(endpoint)
if err != nil {
return nil, errwrap.Wrapf("invalid endpoint: {{err}}", err)
}
if accountName == "" {
return nil, fmt.Errorf("account name can not be empty")
}
httpClient := &http.Client{
Transport: &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,
},
CheckRedirect: doNotFollowRedirects,
}
retryableClient := &retryablehttp.Client{
HTTPClient: httpClient,
Logger: log.New(os.Stderr, "", log.LstdFlags),
RetryWaitMin: defaultRetryWaitMin,
RetryWaitMax: defaultRetryWaitMax,
RetryMax: defaultRetryMax,
CheckRetry: retryablehttp.DefaultRetryPolicy,
}
return &Client{
client: retryableClient,
authorizer: signers,
apiURL: *apiURL,
accountName: accountName,
}, nil
}
func doNotFollowRedirects(*http.Request, []*http.Request) error {
return http.ErrUseLastResponse
}
func (c *Client) executeRequestURIParams(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 := retryablehttp.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)
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 {
tritonError := &TritonError{
StatusCode: statusCode,
}
errorDecoder := json.NewDecoder(body)
if err := errorDecoder.Decode(tritonError); err != nil {
return errwrap.Wrapf("Error decoding error response: {{err}}", err)
}
return tritonError
}
func (c *Client) executeRequest(method, path string, body interface{}) (io.ReadCloser, error) {
return c.executeRequestURIParams(method, path, body, nil)
}
func (c *Client) executeRequestRaw(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 := retryablehttp.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)
if err != nil {
return nil, errwrap.Wrapf("Error executing HTTP request: {{err}}", err)
}
return resp, nil
}

71
vendor/github.com/joyent/triton-go/config.go generated vendored Normal file
View File

@ -0,0 +1,71 @@
package triton
import (
"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(input *GetConfigInput) (*Config, error) {
respReader, err := client.executeRequest(http.MethodGet, fmt.Sprintf("/%s/config", client.accountName), 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.
// TODO(jen20) Work out a safe way to test this (after networks c implemented)
func (client *ConfigClient) UpdateConfig(input *UpdateConfigInput) (*Config, error) {
respReader, err := client.executeRequest(http.MethodPut, fmt.Sprintf("/%s/config", client.accountName), 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
}

92
vendor/github.com/joyent/triton-go/datacenters.go generated vendored Normal file
View File

@ -0,0 +1,92 @@
package triton
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"sort"
"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(*ListDataCentersInput) ([]*DataCenter, error) {
path := fmt.Sprintf("/%s/datacenters", client.accountName)
respReader, err := client.executeRequest(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(input *GetDataCenterInput) (*DataCenter, error) {
path := fmt.Sprintf("/%s/datacenters/%s", client.accountName, input.Name)
resp, err := client.executeRequestRaw(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
}

126
vendor/github.com/joyent/triton-go/errors.go generated vendored Normal file
View File

@ -0,0 +1,126 @@
package triton
import (
"fmt"
"github.com/hashicorp/errwrap"
)
// 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
// code BadRequest
func IsBadRequest(err error) bool {
return isSpecificError(err, "BadRequest")
}
// IsInternalError tests whether err wraps a TritonError with
// code InternalError
func IsInternalError(err error) bool {
return isSpecificError(err, "InternalError")
}
// IsInUseError tests whether err wraps a TritonError with
// code InUseError
func IsInUseError(err error) bool {
return isSpecificError(err, "InUseError")
}
// IsInvalidArgument tests whether err wraps a TritonError with
// code InvalidArgument
func IsInvalidArgument(err error) bool {
return isSpecificError(err, "InvalidArgument")
}
// IsInvalidCredentials tests whether err wraps a TritonError with
// code InvalidCredentials
func IsInvalidCredentials(err error) bool {
return isSpecificError(err, "InvalidCredentials")
}
// IsInvalidHeader tests whether err wraps a TritonError with
// code InvalidHeader
func IsInvalidHeader(err error) bool {
return isSpecificError(err, "InvalidHeader")
}
// IsInvalidVersion tests whether err wraps a TritonError with
// code InvalidVersion
func IsInvalidVersion(err error) bool {
return isSpecificError(err, "InvalidVersion")
}
// IsMissingParameter tests whether err wraps a TritonError with
// code MissingParameter
func IsMissingParameter(err error) bool {
return isSpecificError(err, "MissingParameter")
}
// IsNotAuthorized tests whether err wraps a TritonError with
// code NotAuthorized
func IsNotAuthorized(err error) bool {
return isSpecificError(err, "NotAuthorized")
}
// IsRequestThrottled tests whether err wraps a TritonError with
// code RequestThrottled
func IsRequestThrottled(err error) bool {
return isSpecificError(err, "RequestThrottled")
}
// IsRequestTooLarge tests whether err wraps a TritonError with
// code RequestTooLarge
func IsRequestTooLarge(err error) bool {
return isSpecificError(err, "RequestTooLarge")
}
// IsRequestMoved tests whether err wraps a TritonError with
// code RequestMoved
func IsRequestMoved(err error) bool {
return isSpecificError(err, "RequestMoved")
}
// IsResourceNotFound tests whether err wraps a TritonError with
// code ResourceNotFound
func IsResourceNotFound(err error) bool {
return isSpecificError(err, "ResourceNotFound")
}
// IsUnknownError tests whether err wraps a 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.
func isSpecificError(err error, errorCode string) bool {
if err == nil {
return false
}
tritonErrorInterface := errwrap.GetType(err.(error), &TritonError{})
if tritonErrorInterface == nil {
return false
}
tritonErr := tritonErrorInterface.(*TritonError)
if tritonErr.Code == errorCode {
return true
}
return false
}

233
vendor/github.com/joyent/triton-go/fabrics.go generated vendored Normal file
View File

@ -0,0 +1,233 @@
package triton
import (
"encoding/json"
"fmt"
"net/http"
"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(*ListFabricVLANsInput) ([]*FabricVLAN, error) {
path := fmt.Sprintf("/%s/fabrics/default/vlans", client.accountName)
respReader, err := client.executeRequest(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(input *CreateFabricVLANInput) (*FabricVLAN, error) {
path := fmt.Sprintf("/%s/fabrics/default/vlans", client.accountName)
respReader, err := client.executeRequest(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(input *UpdateFabricVLANInput) (*FabricVLAN, error) {
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d", client.accountName, input.ID)
respReader, err := client.executeRequest(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(input *GetFabricVLANInput) (*FabricVLAN, error) {
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d", client.accountName, input.ID)
respReader, err := client.executeRequest(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(input *DeleteFabricVLANInput) error {
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d", client.accountName, input.ID)
respReader, err := client.executeRequest(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(input *ListFabricNetworksInput) ([]*Network, error) {
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d/networks", client.accountName, input.FabricVLANID)
respReader, err := client.executeRequest(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(input *CreateFabricNetworkInput) (*Network, error) {
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d/networks", client.accountName, input.FabricVLANID)
respReader, err := client.executeRequest(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(input *GetFabricNetworkInput) (*Network, error) {
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d/networks/%s", client.accountName, input.FabricVLANID, input.NetworkID)
respReader, err := client.executeRequest(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(input *DeleteFabricNetworkInput) error {
path := fmt.Sprintf("/%s/fabrics/default/vlans/%d/networks/%s", client.accountName, input.FabricVLANID, input.NetworkID)
respReader, err := client.executeRequest(http.MethodDelete, path, nil)
if respReader != nil {
defer respReader.Close()
}
if err != nil {
return errwrap.Wrapf("Error executing DeleteFabricNetwork request: {{err}}", err)
}
return nil
}

214
vendor/github.com/joyent/triton-go/firewall.go generated vendored Normal file
View File

@ -0,0 +1,214 @@
package triton
import (
"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(*ListFirewallRulesInput) ([]*FirewallRule, error) {
path := fmt.Sprintf("/%s/fwrules", client.accountName)
respReader, err := client.executeRequest(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(input *GetFirewallRuleInput) (*FirewallRule, error) {
path := fmt.Sprintf("/%s/fwrules/%s", client.accountName, input.ID)
respReader, err := client.executeRequest(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(input *CreateFirewallRuleInput) (*FirewallRule, error) {
respReader, err := client.executeRequest(http.MethodPost, fmt.Sprintf("/%s/fwrules", client.accountName), 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(input *UpdateFirewallRuleInput) (*FirewallRule, error) {
respReader, err := client.executeRequest(http.MethodPost, fmt.Sprintf("/%s/fwrules/%s", client.accountName, input.ID), 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(input *EnableFirewallRuleInput) (*FirewallRule, error) {
respReader, err := client.executeRequest(http.MethodPost, fmt.Sprintf("/%s/fwrules/%s/enable", client.accountName, input.ID), 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(input *DisableFirewallRuleInput) (*FirewallRule, error) {
respReader, err := client.executeRequest(http.MethodPost, fmt.Sprintf("/%s/fwrules/%s/disable", client.accountName, input.ID), 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(input *DeleteFirewallRuleInput) error {
path := fmt.Sprintf("/%s/fwrules/%s", client.accountName, input.ID)
respReader, err := client.executeRequest(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(input *ListMachineFirewallRulesInput) ([]*FirewallRule, error) {
path := fmt.Sprintf("/%s/machines/%s/firewallrules", client.accountName, input.MachineID)
respReader, err := client.executeRequest(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
}

205
vendor/github.com/joyent/triton-go/images.go generated vendored Normal file
View File

@ -0,0 +1,205 @@
package triton
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
"github.com/hashicorp/errwrap"
)
type ImagesClient struct {
*Client
}
// Images returns a c used for accessing functions pertaining to
// Images functionality in the Triton API.
func (c *Client) Images() *ImagesClient {
return &ImagesClient{c}
}
type ImageFile struct {
Compression string `json:"compression"`
SHA1 string `json:"sha1"`
Size int64 `json:"size"`
}
type Image struct {
ID string `json:"id"`
Name string `json:"name"`
OS string `json:"os"`
Description string `json:"description"`
Version string `json:"version"`
Type string `json:"type"`
Requirements map[string]interface{} `json:"requirements"`
Homepage string `json:"homepage"`
Files []*ImageFile `json:"files"`
PublishedAt time.Time `json:"published_at"`
Owner string `json:"owner"`
Public bool `json:"public"`
State string `json:"state"`
Tags map[string]string `json:"tags"`
EULA string `json:"eula"`
ACL []string `json:"acl"`
Error TritonError `json:"error"`
}
type ListImagesInput struct{}
func (client *ImagesClient) ListImages(*ListImagesInput) ([]*Image, error) {
path := fmt.Sprintf("/%s/images", client.accountName)
respReader, err := client.executeRequest(http.MethodGet, path, nil)
if respReader != nil {
defer respReader.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing ListImages request: {{err}}", err)
}
var result []*Image
decoder := json.NewDecoder(respReader)
if err = decoder.Decode(&result); err != nil {
return nil, errwrap.Wrapf("Error decoding ListImages response: {{err}}", err)
}
return result, nil
}
type GetImageInput struct {
ImageID string
}
func (client *ImagesClient) GetImage(input *GetImageInput) (*Image, error) {
path := fmt.Sprintf("/%s/images/%s", client.accountName, input.ImageID)
respReader, err := client.executeRequest(http.MethodGet, path, nil)
if respReader != nil {
defer respReader.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing GetImage request: {{err}}", err)
}
var result *Image
decoder := json.NewDecoder(respReader)
if err = decoder.Decode(&result); err != nil {
return nil, errwrap.Wrapf("Error decoding GetImage response: {{err}}", err)
}
return result, nil
}
type DeleteImageInput struct {
ImageID string
}
func (client *ImagesClient) DeleteImage(input *DeleteImageInput) error {
path := fmt.Sprintf("/%s/images/%s", client.accountName, input.ImageID)
respReader, err := client.executeRequest(http.MethodDelete, path, nil)
if respReader != nil {
defer respReader.Close()
}
if err != nil {
return errwrap.Wrapf("Error executing DeleteKey request: {{err}}", err)
}
return nil
}
type ExportImageInput struct {
ImageID string
MantaPath string
}
type MantaLocation struct {
MantaURL string `json:"manta_url"`
ImagePath string `json:"image_path"`
ManifestPath string `json:"manifest_path"`
}
func (client *ImagesClient) ExportImage(input *ExportImageInput) (*MantaLocation, error) {
path := fmt.Sprintf("/%s/images/%s", client.accountName, input.ImageID)
query := &url.Values{}
query.Set("action", "export")
query.Set("manta_path", input.MantaPath)
respReader, err := client.executeRequestURIParams(http.MethodGet, path, nil, query)
if respReader != nil {
defer respReader.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing GetImage request: {{err}}", err)
}
var result *MantaLocation
decoder := json.NewDecoder(respReader)
if err = decoder.Decode(&result); err != nil {
return nil, errwrap.Wrapf("Error decoding GetImage response: {{err}}", err)
}
return result, nil
}
type CreateImageFromMachineInput struct {
MachineID string `json:"machine"`
Name string `json:"name"`
Version string `json:"version,omitempty"`
Description string `json:"description,omitempty"`
HomePage string `json:"homepage,omitempty"`
EULA string `json:"eula,omitempty"`
ACL []string `json:"acl,omitempty"`
Tags map[string]string `json:"tags,omitempty"`
}
func (client *ImagesClient) CreateImageFromMachine(input *CreateImageFromMachineInput) (*Image, error) {
path := fmt.Sprintf("/%s/images", client.accountName)
respReader, err := client.executeRequest(http.MethodPost, path, input)
if respReader != nil {
defer respReader.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing CreateImageFromMachine request: {{err}}", err)
}
var result *Image
decoder := json.NewDecoder(respReader)
if err = decoder.Decode(&result); err != nil {
return nil, errwrap.Wrapf("Error decoding CreateImageFromMachine response: {{err}}", err)
}
return result, nil
}
type UpdateImageInput struct {
ImageID string `json:"-"`
Name string `json:"name"`
Version string `json:"version,omitempty"`
Description string `json:"description,omitempty"`
HomePage string `json:"homepage,omitempty"`
EULA string `json:"eula,omitempty"`
ACL []string `json:"acl,omitempty"`
Tags map[string]string `json:"tags,omitempty"`
}
func (client *ImagesClient) UpdateImage(input *UpdateImageInput) (*Image, error) {
path := fmt.Sprintf("/%s/images/%s", client.accountName, input.ImageID)
query := &url.Values{}
query.Set("action", "update")
respReader, err := client.executeRequestURIParams(http.MethodPost, path, input, query)
if respReader != nil {
defer respReader.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing UpdateImage request: {{err}}", err)
}
var result *Image
decoder := json.NewDecoder(respReader)
if err = decoder.Decode(&result); err != nil {
return nil, errwrap.Wrapf("Error decoding UpdateImage response: {{err}}", err)
}
return result, nil
}

123
vendor/github.com/joyent/triton-go/keys.go generated vendored Normal file
View File

@ -0,0 +1,123 @@
package triton
import (
"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(*ListKeysInput) ([]*Key, error) {
path := fmt.Sprintf("/%s/keys")
respReader, err := client.executeRequest(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(input *GetKeyInput) (*Key, error) {
path := fmt.Sprintf("/%s/keys/%s", client.accountName, input.KeyName)
respReader, err := client.executeRequest(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(input *DeleteKeyInput) error {
path := fmt.Sprintf("/%s/keys/%s", client.accountName, input.KeyName)
respReader, err := client.executeRequest(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(input *CreateKeyInput) (*Key, error) {
respReader, err := client.executeRequest(http.MethodPost, fmt.Sprintf("/%s/keys", client.accountName), 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
}

663
vendor/github.com/joyent/triton-go/machines.go generated vendored Normal file
View File

@ -0,0 +1,663 @@
package triton
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
"net/url"
"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(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(http.MethodGet, path, nil)
if response != nil {
defer response.Body.Close()
}
if response.StatusCode == http.StatusNotFound || response.StatusCode == http.StatusGone {
return nil, &TritonError{
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
}
func (client *MachinesClient) GetMachines() ([]*Machine, error) {
path := fmt.Sprintf("/%s/machines", client.accountName)
response, err := client.executeRequestRaw(http.MethodGet, path, nil)
if response != nil {
defer response.Body.Close()
}
if response.StatusCode == http.StatusNotFound {
return nil, &TritonError{
Code: "ResourceNotFound",
}
}
if err != nil {
return nil, errwrap.Wrapf("Error executing GetMachines 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 GetMachines 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(input *CreateMachineInput) (*Machine, error) {
path := fmt.Sprintf("/%s/machines", client.accountName)
respReader, err := client.executeRequest(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(input *DeleteMachineInput) error {
path := fmt.Sprintf("/%s/machines/%s", client.accountName, input.ID)
response, err := client.executeRequestRaw(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 DeleteMachine request: {{err}}",
client.decodeError(response.StatusCode, response.Body))
}
return nil
}
type DeleteMachineTagsInput struct {
ID string
}
func (client *MachinesClient) DeleteMachineTags(input *DeleteMachineTagsInput) error {
path := fmt.Sprintf("/%s/machines/%s/tags", client.accountName, input.ID)
response, err := client.executeRequestRaw(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(input *DeleteMachineTagInput) error {
path := fmt.Sprintf("/%s/machines/%s/tags/%s", client.accountName, input.ID, input.Key)
response, err := client.executeRequestRaw(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(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(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(input *ReplaceMachineTagsInput) error {
path := fmt.Sprintf("/%s/machines/%s/tags", client.accountName, input.ID)
respReader, err := client.executeRequest(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(input *AddMachineTagsInput) error {
path := fmt.Sprintf("/%s/machines/%s/tags", client.accountName, input.ID)
respReader, err := client.executeRequest(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(input *GetMachineTagInput) (string, error) {
path := fmt.Sprintf("/%s/machines/%s/tags/%s", client.accountName, input.ID, input.Key)
respReader, err := client.executeRequest(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(input *ListMachineTagsInput) (map[string]string, error) {
path := fmt.Sprintf("/%s/machines/%s/tags", client.accountName, input.ID)
respReader, err := client.executeRequest(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(input *UpdateMachineMetadataInput) (map[string]string, error) {
path := fmt.Sprintf("/%s/machines/%s/tags", client.accountName, input.ID)
respReader, err := client.executeRequest(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(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(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(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(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(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(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(input *ListNICsInput) ([]*NIC, error) {
path := fmt.Sprintf("/%s/machines/%s/nics", client.accountName, input.MachineID)
respReader, err := client.executeRequest(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(input *AddNICInput) (*NIC, error) {
path := fmt.Sprintf("/%s/machines/%s/nics", client.accountName, input.MachineID)
respReader, err := client.executeRequest(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(input *RemoveNICInput) error {
path := fmt.Sprintf("/%s/machines/%s/nics/%s", client.accountName, input.MachineID, input.MAC)
respReader, err := client.executeRequest(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(input *StopMachineInput) error {
path := fmt.Sprintf("/%s/machines/%s", client.accountName, input.MachineID)
params := &url.Values{}
params.Set("action", "stop")
respReader, err := client.executeRequestURIParams(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(input *StartMachineInput) error {
path := fmt.Sprintf("/%s/machines/%s", client.accountName, input.MachineID)
params := &url.Values{}
params.Set("action", "start")
respReader, err := client.executeRequestURIParams(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, ",")
}
}

78
vendor/github.com/joyent/triton-go/networks.go generated vendored Normal file
View File

@ -0,0 +1,78 @@
package triton
import (
"encoding/json"
"net/http"
"fmt"
"github.com/hashicorp/errwrap"
)
type NetworksClient struct {
*Client
}
// Networks returns a c used for accessing functions pertaining to
// Network functionality in the Triton API.
func (c *Client) Networks() *NetworksClient {
return &NetworksClient{c}
}
type Network struct {
Id string `json:"id"`
Name string `json:"name"`
Public bool `json:"public"`
Fabric bool `json:"fabric"`
Description string `json:"description"`
Subnet string `json:"subnet"`
ProvisioningStartIP string `json:"provision_start_ip"`
ProvisioningEndIP string `json:"provision_end_ip"`
Gateway string `json:"gateway"`
Resolvers []string `json:"resolvers"`
Routes map[string]string `json:"routes"`
InternetNAT bool `json:"internet_nat"`
}
type ListNetworksInput struct{}
func (client *NetworksClient) ListNetworks(*ListNetworksInput) ([]*Network, error) {
path := fmt.Sprintf("/%s/networks", client.accountName)
respReader, err := client.executeRequest(http.MethodGet, path, nil)
if respReader != nil {
defer respReader.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing ListNetworks request: {{err}}", err)
}
var result []*Network
decoder := json.NewDecoder(respReader)
if err = decoder.Decode(&result); err != nil {
return nil, errwrap.Wrapf("Error decoding ListNetworks response: {{err}}", err)
}
return result, nil
}
type GetNetworkInput struct {
ID string
}
func (client *NetworksClient) GetNetwork(input *GetNetworkInput) (*Network, error) {
path := fmt.Sprintf("/%s/networks/%s", client.accountName, input.ID)
respReader, err := client.executeRequest(http.MethodGet, path, nil)
if respReader != nil {
defer respReader.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing GetNetwork request: {{err}}", err)
}
var result *Network
decoder := json.NewDecoder(respReader)
if err = decoder.Decode(&result); err != nil {
return nil, errwrap.Wrapf("Error decoding GetNetwork response: {{err}}", err)
}
return result, nil
}

85
vendor/github.com/joyent/triton-go/packages.go generated vendored Normal file
View File

@ -0,0 +1,85 @@
package triton
import (
"encoding/json"
"fmt"
"net/http"
"github.com/hashicorp/errwrap"
)
type PackagesClient struct {
*Client
}
// Packages returns a c used for accessing functions pertaining
// to Packages functionality in the Triton API.
func (c *Client) Packages() *PackagesClient {
return &PackagesClient{c}
}
type Package struct {
ID string `json:"id"`
Name string `json:"name"`
Memory int64 `json:"memory"`
Disk int64 `json:"disk"`
Swap int64 `json:"swap"`
LWPs int64 `json:"lwps"`
VCPUs int64 `json:"vcpus"`
Version string `json:"version"`
Group string `json:"group"`
Description string `json:"description"`
Default bool `json:"default"`
}
type ListPackagesInput struct {
Name string `json:"name"`
Memory int64 `json:"memory"`
Disk int64 `json:"disk"`
Swap int64 `json:"swap"`
LWPs int64 `json:"lwps"`
VCPUs int64 `json:"vcpus"`
Version string `json:"version"`
Group string `json:"group"`
}
func (client *PackagesClient) ListPackages(input *ListPackagesInput) ([]*Package, error) {
respReader, err := client.executeRequest(http.MethodGet, fmt.Sprintf("/%s/packages", client.accountName), input)
if respReader != nil {
defer respReader.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing ListPackages request: {{err}}", err)
}
var result []*Package
decoder := json.NewDecoder(respReader)
if err = decoder.Decode(&result); err != nil {
return nil, errwrap.Wrapf("Error decoding ListPackages response: {{err}}", err)
}
return result, nil
}
type GetPackageInput struct {
ID string
}
func (client *PackagesClient) GetPackage(input *GetPackageInput) (*Package, error) {
path := fmt.Sprintf("/%s/packages/%s", client.accountName, input.ID)
respReader, err := client.executeRequest(http.MethodGet, path, nil)
if respReader != nil {
defer respReader.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing GetPackage request: {{err}}", err)
}
var result *Package
decoder := json.NewDecoder(respReader)
if err = decoder.Decode(&result); err != nil {
return nil, errwrap.Wrapf("Error decoding GetPackage response: {{err}}", err)
}
return result, nil
}

159
vendor/github.com/joyent/triton-go/roles.go generated vendored Normal file
View File

@ -0,0 +1,159 @@
package triton
import (
"fmt"
"github.com/hashicorp/errwrap"
"net/http"
"encoding/json"
)
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(*ListRolesInput) ([]*Role, error) {
respReader, err := client.executeRequest(http.MethodGet, fmt.Sprintf("/%s/roles", client.accountName), 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(input *GetRoleInput) (*Role, error) {
path := fmt.Sprintf("/%s/roles/%s", client.accountName, input.RoleID)
respReader, err := client.executeRequest(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(input *CreateRoleInput) (*Role, error) {
respReader, err := client.executeRequest(http.MethodPost, fmt.Sprintf("/%s/roles", client.accountName), 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(input *UpdateRoleInput) (*Role, error) {
respReader, err := client.executeRequest(http.MethodPost, fmt.Sprintf("/%s/roles/%s", client.accountName, input.RoleID), 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(input *DeleteRoleInput) error {
path := fmt.Sprintf("/%s/roles/%s", client.accountName, input.RoleID)
respReader, err := client.executeRequest(http.MethodDelete, path, nil)
if respReader != nil {
defer respReader.Close()
}
if err != nil {
return errwrap.Wrapf("Error executing DeleteRole request: {{err}}", err)
}
return nil
}

63
vendor/github.com/joyent/triton-go/services.go generated vendored Normal file
View File

@ -0,0 +1,63 @@
package triton
import (
"encoding/json"
"fmt"
"net/http"
"sort"
"github.com/hashicorp/errwrap"
)
type ServicesClient struct {
*Client
}
// Services returns a c used for accessing functions pertaining
// to Services functionality in the Triton API.
func (c *Client) Services() *ServicesClient {
return &ServicesClient{c}
}
type Service struct {
Name string
Endpoint string
}
type ListServicesInput struct{}
func (client *ServicesClient) ListServices(*ListServicesInput) ([]*Service, error) {
respReader, err := client.executeRequest(http.MethodGet, fmt.Sprintf("/%s/services", client.accountName), nil)
if respReader != nil {
defer respReader.Close()
}
if err != nil {
return nil, errwrap.Wrapf("Error executing ListServices 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 ListServices response: {{err}}", err)
}
keys := make([]string, len(intermediate))
i := 0
for k := range intermediate {
keys[i] = k
i++
}
sort.Strings(keys)
result := make([]*Service, len(intermediate))
i = 0
for _, key := range keys {
result[i] = &Service{
Name: key,
Endpoint: intermediate[key],
}
i++
}
return result, nil
}

18
vendor/vendor.json vendored
View File

@ -487,6 +487,12 @@
"path": "github.com/hashicorp/go-multierror",
"revision": "d30f09973e19c1dfcd120b2d9c4f168e68d6b5d5"
},
{
"checksumSHA1": "ErJHGU6AVPZM9yoY/xV11TwSjQs=",
"path": "github.com/hashicorp/go-retryablehttp",
"revision": "2d5f5dbd904dbad432492c3ca2c12c72c9e3045a",
"revisionTime": "2017-04-21T23:29:22Z"
},
{
"checksumSHA1": "A1PcINvF3UiwHRKn8UcgARgvGRs=",
"path": "github.com/hashicorp/go-rootcerts",
@ -513,6 +519,18 @@
"path": "github.com/jmespath/go-jmespath",
"revision": "c01cf91b011868172fdcd9f41838e80c9d716264"
},
{
"checksumSHA1": "TFdaSXpgmpa6vJzfjtUoHLrp1AM=",
"path": "github.com/joyent/triton-go",
"revision": "db2461b5a5a55ca698b4062d95118c03d4aafb88",
"revisionTime": "2017-04-26T18:53:01Z"
},
{
"checksumSHA1": "QzUqkCSn/ZHyIK346xb9V6EBw9U=",
"path": "github.com/joyent/triton-go/authentication",
"revision": "db2461b5a5a55ca698b4062d95118c03d4aafb88",
"revisionTime": "2017-04-26T18:53:01Z"
},
{
"checksumSHA1": "6nmAJBw2phU9MUmkUnqFvbO5urg=",
"path": "github.com/kardianos/osext",