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

..13-Nov-2018-

authentication/H13-Nov-2018-672480

client/H13-Nov-2018-601444

compute/H13-Nov-2018-2,2851,839

errors/H13-Nov-2018-298212

CHANGELOG.mdH A D13-Nov-20184 KiB10165

GNUmakefileH A D13-Nov-20181.2 KiB4738

Gopkg.lockH A D13-Nov-20185.1 KiB231198

Gopkg.tomlH A D13-Nov-20181.4 KiB7559

LICENSEH A D13-Nov-201816.3 KiB374293

README.mdH A D13-Nov-20188.2 KiB249202

triton.goH A D13-Nov-20181.3 KiB4721

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