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

..03-May-2022-

account/H16-Apr-2020-

authentication/H16-Apr-2020-

client/H16-Apr-2020-

cmd/H16-Apr-2020-

compute/H16-Apr-2020-

errors/H16-Apr-2020-

examples/H16-Apr-2020-

identity/H16-Apr-2020-

network/H16-Apr-2020-

scripts/H16-Apr-2020-

services/H16-Apr-2020-

storage/H16-Apr-2020-

testutils/H16-Apr-2020-

vendor/H16-Apr-2020-

.gitignoreH A D16-Apr-2020153

.travis.ymlH A D16-Apr-2020217

CHANGELOG.mdH A D16-Apr-20204.4 KiB

Gopkg.lockH A D16-Apr-20208.4 KiB

Gopkg.tomlH A D16-Apr-20201.4 KiB

LICENSEH A D16-Apr-202016.3 KiB

MakefileH A D16-Apr-20201.1 KiB

README.mdH A D16-Apr-20208.4 KiB

go.modH A D16-Apr-20201.2 KiB

go.sumH A D16-Apr-202024.3 KiB

triton.goH A D16-Apr-20201.3 KiB

triton_test.goH A D16-Apr-2020686

version.goH A D16-Apr-20201.3 KiB

README.md

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