• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..11-Feb-2020-

authentication/H11-Feb-2020-672480

client/H11-Feb-2020-601444

compute/H11-Feb-2020-2,2851,839

errors/H11-Feb-2020-298212

.gitignoreH A D11-Feb-2020153 2019

.travis.ymlH A D11-Feb-2020217 1916

CHANGELOG.mdH A D11-Feb-20204 KiB10165

GNUmakefileH A D11-Feb-20201.2 KiB4738

Gopkg.lockH A D11-Feb-20205.1 KiB231198

Gopkg.tomlH A D11-Feb-20201.4 KiB7559

LICENSEH A D11-Feb-202016.3 KiB374293

README.mdH A D11-Feb-20208.3 KiB250203

triton.goH A D11-Feb-20201.3 KiB4721

version.goH A D11-Feb-20201.3 KiB4316

README.md

1# triton-go
2
3`triton-go` is an idiomatic library exposing a client SDK for Go applications
4using Joyent's Triton Compute and Storage (Manta) APIs.
5
6[![Build Status](https://travis-ci.org/joyent/triton-go.svg?branch=master)](https://travis-ci.org/joyent/triton-go) [![Go Report Card](https://goreportcard.com/badge/github.com/joyent/triton-go)](https://goreportcard.com/report/github.com/joyent/triton-go)
7
8The Triton Go SDK is used in the following open source projects.
9
10- [Consul](https://www.consul.io/docs/agent/cloud-auto-join.html#joyent-triton)
11- [Packer](http://github.com/hashicorp/packer)
12- [Vault](http://github.com/hashicorp/vault)
13- [Terraform](http://github.com/hashicorp/terraform)
14- [Terraform Triton Provider](https://github.com/terraform-providers/terraform-provider-triton)
15- [Docker Machine](https://github.com/joyent/docker-machine-driver-triton)
16- [Triton Kubernetes](https://github.com/joyent/triton-kubernetes)
17- [HashiCorp go-discover](https://github.com/hashicorp/go-discover)
18
19## Usage
20
21Triton uses [HTTP Signature][4] to sign the Date header in each HTTP request
22made to the Triton API. Currently, requests can be signed using either a private
23key file loaded from disk (using an [`authentication.PrivateKeySigner`][5]), or
24using a key stored with the local SSH Agent (using an [`SSHAgentSigner`][6].
25
26To construct a Signer, use the `New*` range of methods in the `authentication`
27package. In the case of `authentication.NewSSHAgentSigner`, the parameters are
28the fingerprint of the key with which to sign, and the account name (normally
29stored in the `TRITON_ACCOUNT` environment variable). There is also support for
30passing in a username, this will allow you to use an account other than the main
31Triton account. For example:
32
33```go
34input := authentication.SSHAgentSignerInput{
35    KeyID:       "a4:c6:f3:75:80:27:e0:03:a9:98:79:ef:c5:0a:06:11",
36    AccountName: "AccountName",
37    Username:    "Username",
38}
39sshKeySigner, err := authentication.NewSSHAgentSigner(input)
40if err != nil {
41    log.Fatalf("NewSSHAgentSigner: %s", err)
42}
43```
44
45An appropriate key fingerprint can be generated using `ssh-keygen`.
46
47```
48ssh-keygen -Emd5 -lf ~/.ssh/id_rsa.pub | cut -d " " -f 2 | sed 's/MD5://'
49```
50
51Each top level package, `account`, `compute`, `identity`, `network`, all have
52their own separate client. In order to initialize a package client, simply pass
53the global `triton.ClientConfig` struct into the client's constructor function.
54
55```go
56config := &triton.ClientConfig{
57    TritonURL:   os.Getenv("TRITON_URL"),
58    MantaURL:    os.Getenv("MANTA_URL"),
59    AccountName: accountName,
60    Username:    os.Getenv("TRITON_USER"),
61    Signers:     []authentication.Signer{sshKeySigner},
62}
63
64c, err := compute.NewClient(config)
65if err != nil {
66    log.Fatalf("compute.NewClient: %s", err)
67}
68```
69
70Constructing `compute.Client` returns an interface which exposes `compute` API
71resources. The same goes for all other packages. Reference their unique
72documentation for more information.
73
74The same `triton.ClientConfig` will initialize the Manta `storage` client as
75well...
76
77```go
78c, err := storage.NewClient(config)
79if err != nil {
80    log.Fatalf("storage.NewClient: %s", err)
81}
82```
83
84## Error Handling
85
86If an error is returned by the HTTP API, the `error` returned from the function
87will contain an instance of `errors.APIError` in the chain. Error wrapping
88is performed using the [pkg/errors][7] library.
89
90## Acceptance Tests
91
92Acceptance Tests run directly against the Triton API, so you will need either a
93local installation of Triton or an account with Joyent's Public Cloud offering
94in order to run them. The tests create real resources (and thus cost real
95money)!
96
97In order to run acceptance tests, the following environment variables must be
98set:
99
100- `TRITON_TEST` - must be set to any value in order to indicate desire to create
101  resources
102- `TRITON_URL` - the base endpoint for the Triton API
103- `TRITON_ACCOUNT` - the account name for the Triton API
104- `TRITON_KEY_ID` - the fingerprint of the SSH key identifying the key
105
106Additionally, you may set `TRITON_KEY_MATERIAL` to the contents of an unencrypted
107private key. If this is set, the PrivateKeySigner (see above) will be used - if
108not the SSHAgentSigner will be used. You can also set `TRITON_USER` to run the tests
109against an account other than the main Triton account
110
111### Example Run
112
113The verbose output has been removed for brevity here.
114
115```
116$ HTTP_PROXY=http://localhost:8888 \
117    TRITON_TEST=1 \
118    TRITON_URL=https://us-sw-1.api.joyent.com \
119    TRITON_ACCOUNT=AccountName \
120    TRITON_KEY_ID=a4:c6:f3:75:80:27:e0:03:a9:98:79:ef:c5:0a:06:11 \
121    go test -v -run "TestAccKey"
122=== RUN   TestAccKey_Create
123--- PASS: TestAccKey_Create (12.46s)
124=== RUN   TestAccKey_Get
125--- PASS: TestAccKey_Get (4.30s)
126=== RUN   TestAccKey_Delete
127--- PASS: TestAccKey_Delete (15.08s)
128PASS
129ok  	github.com/joyent/triton-go	31.861s
130```
131
132## Example API
133
134There's an `examples/` directory available with sample code setup for many of
135the APIs within this library. Most of these can be run using `go run` and
136referencing your SSH key file use by your active `triton` CLI profile.
137
138```sh
139$ eval "$(triton env us-sw-1)"
140$ TRITON_KEY_FILE=~/.ssh/triton-id_rsa go run examples/compute/instances.go
141```
142
143The following is a complete example of how to initialize the `compute` package
144client and list all instances under an account. More detailed usage of this
145library follows.
146
147```go
148
149
150package main
151
152import (
153    "context"
154    "fmt"
155    "io/ioutil"
156    "log"
157    "os"
158    "time"
159
160    triton "github.com/joyent/triton-go"
161    "github.com/joyent/triton-go/authentication"
162    "github.com/joyent/triton-go/compute"
163)
164
165func main() {
166    keyID := os.Getenv("TRITON_KEY_ID")
167    accountName := os.Getenv("TRITON_ACCOUNT")
168    keyMaterial := os.Getenv("TRITON_KEY_MATERIAL")
169    userName := os.Getenv("TRITON_USER")
170
171    var signer authentication.Signer
172    var err error
173
174    if keyMaterial == "" {
175        input := authentication.SSHAgentSignerInput{
176            KeyID:       keyID,
177            AccountName: accountName,
178            Username:    userName,
179        }
180        signer, err = authentication.NewSSHAgentSigner(input)
181        if err != nil {
182            log.Fatalf("Error Creating SSH Agent Signer: {{err}}", err)
183        }
184    } else {
185        var keyBytes []byte
186        if _, err = os.Stat(keyMaterial); err == nil {
187            keyBytes, err = ioutil.ReadFile(keyMaterial)
188            if err != nil {
189                log.Fatalf("Error reading key material from %s: %s",
190                    keyMaterial, err)
191            }
192            block, _ := pem.Decode(keyBytes)
193            if block == nil {
194                log.Fatalf(
195                    "Failed to read key material '%s': no key found", keyMaterial)
196            }
197
198            if block.Headers["Proc-Type"] == "4,ENCRYPTED" {
199                log.Fatalf(
200                    "Failed to read key '%s': password protected keys are\n"+
201                        "not currently supported. Please decrypt the key prior to use.", keyMaterial)
202            }
203
204        } else {
205            keyBytes = []byte(keyMaterial)
206        }
207
208        input := authentication.PrivateKeySignerInput{
209            KeyID:              keyID,
210            PrivateKeyMaterial: keyBytes,
211            AccountName:        accountName,
212            Username:           userName,
213        }
214        signer, err = authentication.NewPrivateKeySigner(input)
215        if err != nil {
216            log.Fatalf("Error Creating SSH Private Key Signer: {{err}}", err)
217        }
218    }
219
220    config := &triton.ClientConfig{
221        TritonURL:   os.Getenv("TRITON_URL"),
222        AccountName: accountName,
223        Username:    userName,
224        Signers:     []authentication.Signer{signer},
225    }
226
227    c, err := compute.NewClient(config)
228    if err != nil {
229        log.Fatalf("compute.NewClient: %s", err)
230    }
231
232    listInput := &compute.ListInstancesInput{}
233    instances, err := c.Instances().List(context.Background(), listInput)
234    if err != nil {
235        log.Fatalf("compute.Instances.List: %v", err)
236    }
237    numInstances := 0
238    for _, instance := range instances {
239        numInstances++
240        fmt.Println(fmt.Sprintf("-- Instance: %v", instance.Name))
241    }
242}
243
244```
245
246[4]: https://github.com/joyent/node-http-signature/blob/master/http_signing.md
247[5]: https://godoc.org/github.com/joyent/triton-go/authentication
248[6]: https://godoc.org/github.com/joyent/triton-go/authentication
249[7]: https://github.com/pkg/errors
250