-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathrsapi.go
140 lines (131 loc) · 4.36 KB
/
rsapi.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package rsapi
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"strconv"
"strings"
"time"
"github.com/rightscale/rsc/cmd"
"github.com/rightscale/rsc/metadata"
)
// RightScale client
// Instances of this struct should be created through `New`, `NewRL10` or `FromCommandLine`.
type Api struct {
AccountId int // Account in which client is currently operating
Auth Authenticator // Authenticator, signs requests for auth
Logger *log.Logger // Optional logger, if specified requests and responses get logged
Host string // API host, e.g. "us-3.rightscale.com"
Client HttpClient // Underlying http client
DumpRequestResponse bool // Whether to dump HTTP requests and responses to STDOUT
FetchLocationResource bool // Whether to fetch resource pointed by Location header
Metadata ApiMetadata // Generated API metadata
}
// Api metadata consists of resource metadata indexed by resource name
type ApiMetadata map[string]*metadata.Resource
// Generic API parameter type, used to specify optional parameters for example
type ApiParams map[string]interface{}
// Use interface instead of raw http.Client to ease testing
type HttpClient interface {
Do(req *http.Request) (*http.Response, error)
}
// New returns a API client that uses User oauth authentication.
// logger and client are optional.
// host may be blank in which case client attempts to resolve it using auth.
// If no HTTP client is specified then the default client is used.
func New(accountId int, host string, auth Authenticator, logger *log.Logger, client HttpClient) (*Api, error) {
if client == nil {
client = http.DefaultClient
}
host, err := auth.ResolveHost(host,accountId)
if err != nil {
return nil,err
}
return &Api{
AccountId: accountId,
Auth: auth,
Logger: logger,
Host: host,
Client: client,
}, nil
}
// NewRL10 returns a API client that uses the information stored in /var/run/rll-secret to do
// auth and configure the host. The client behaves identically to the client returned by New in
// all other regards.
func NewRL10(logger *log.Logger, client HttpClient) (*Api, error) {
rllConfig, err := ioutil.ReadFile("/var/run/rll-secret")
if err != nil {
return nil, fmt.Errorf("Failed to load RLL config: %s", err)
}
var port string
var secret string
for _, line := range strings.Split(string(rllConfig), "\n") {
elems := strings.Split(line, "=")
if len(elems) != 2 {
return nil, fmt.Errorf("Invalid RLL configuration line '%s'", line)
}
switch elems[0] {
case "RS_RLL_PORT":
port = elems[1]
if _, err := strconv.Atoi(elems[1]); err != nil {
return nil, fmt.Errorf("Invalid port value '%s'", port)
}
case "RS_RLL_SECRET":
secret = elems[1]
}
}
auth := RL10Authenticator{secret}
host := "localhost:" + port
return &Api{
Auth: &auth,
Logger: logger,
Host: host,
Client: client,
}, nil
}
// Build client from command line
func FromCommandLine(cmdLine *cmd.CommandLine) (*Api, error) {
var client *Api
var httpClient *http.Client
if cmdLine.NoRedirect {
httpClient = &http.Client{
CheckRedirect: func(*http.Request, []*http.Request) error {
return fmt.Errorf("Client configured to prevent redirection")
},
}
} else {
httpClient = http.DefaultClient
}
var err error
if cmdLine.RL10 {
client, err = NewRL10(nil, httpClient)
} else if cmdLine.Token != "" {
auth := OAuthAuthenticator{
RefreshToken: cmdLine.Token,
AccessToken: "",
RefreshAt: time.Now().Add(-time.Duration(5) * time.Minute),
Client: httpClient,
}
client, err = New(cmdLine.Account, cmdLine.Host, &auth, nil, httpClient)
} else {
auth := LoginAuthenticator{
Username: cmdLine.Username,
Password: cmdLine.Password,
RefreshAt: time.Now().Add(-time.Duration(5) * time.Minute),
Client: httpClient,
}
client, err = New(cmdLine.Account, cmdLine.Host, &auth, nil, httpClient)
}
if err != nil {
return nil, fmt.Errorf("Failed to create API session: %v", err)
}
if !cmdLine.ShowHelp {
if cmdLine.Token == "" && cmdLine.Username == "" && !cmdLine.RL10 {
return nil, fmt.Errorf("Missing authentication information, use '--email EMAIL --password PWD', '--token TOKEN' or 'setup'")
}
client.DumpRequestResponse = cmdLine.Dump
client.FetchLocationResource = cmdLine.FetchResource
}
return client, nil
}