Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit ceb4016

Browse files
authored
Merge pull request #18 from philips-software/feature/autoconfig
Autoconfig support for iam, cartel and logging
2 parents 1a8a08c + c951ce8 commit ceb4016

32 files changed

+363
-119
lines changed

cartel/add_security_groups_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
func TestAddSecurityGroups(t *testing.T) {
1111
var addResponse = `{"message": "Security group(s) foo added to foo.dev.com"}`
1212

13-
teardown, err := setup(t, Config{
13+
teardown, err := setup(t, &Config{
1414
NoTLS: true,
1515
SkipVerify: true,
1616
Token: sharedToken,

cartel/add_tags_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
func TestAddTags(t *testing.T) {
1111
var addResponse = `{"message": "Added tags foo, bar to foo.dev"}`
1212

13-
teardown, err := setup(t, Config{
13+
teardown, err := setup(t, &Config{
1414
NoTLS: true,
1515
SkipVerify: true,
1616
Token: sharedToken,

cartel/add_user_groups_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
func TestAddUserGroups(t *testing.T) {
1111
var addResponse = `{"foo.dev.com": {"ldap_groups": ["foo", "bar"]}}`
1212

13-
teardown, err := setup(t, Config{
13+
teardown, err := setup(t, &Config{
1414
NoTLS: true,
1515
SkipVerify: true,
1616
Token: sharedToken,

cartel/all_instances_test.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
)
99

1010
func TestAllInstances(t *testing.T) {
11-
teardown, err := setup(t, Config{
11+
teardown, err := setup(t, &Config{
1212
NoTLS: true,
1313
SkipVerify: true,
1414
Token: sharedToken,
@@ -19,13 +19,10 @@ func TestAllInstances(t *testing.T) {
1919

2020
muxCartel.HandleFunc("/v3/api/get_all_instances", endpointMocker([]byte(sharedSecret),
2121
responseBody))
22-
23-
defer teardown()
24-
25-
if err != nil {
26-
t.Fatal(err)
22+
if !assert.Nil(t, err) {
23+
return
2724
}
28-
25+
defer teardown()
2926
instances, resp, err := client.GetAllInstances()
3027
assert.Nil(t, err)
3128
if !assert.NotNil(t, resp) {

cartel/client.go

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ import (
1717
"os"
1818
"strings"
1919

20-
"github.com/google/go-querystring/query"
20+
autoconf "github.com/philips-software/go-hsdp-api/config"
2121

22-
"github.com/philips-software/go-hsdp-api/fhir"
22+
"github.com/google/go-querystring/query"
2323
)
2424

2525
const (
@@ -29,13 +29,15 @@ const (
2929

3030
// Config the client
3131
type Config struct {
32-
Token string `cloud:"token" json:"token"`
33-
Secret string `cloud:"secret" json:"secret"`
34-
SkipVerify bool `cloud:"skip_verify" json:"skip_verify"`
35-
NoTLS bool `cloud:"no_tls" json:"no_tls"`
36-
Host string `cloud:"host" json:"host"`
37-
Debug bool `cloud:"-" json:"debug,omitempty"`
38-
DebugLog string `cloud:"-" json:"debug_log,omitempty"`
32+
Region string `cloud:"-", json:"-"`
33+
Environment string `cloud:"-" json:"-"`
34+
Token string `cloud:"token" json:"token"`
35+
Secret string `cloud:"secret" json:"secret"`
36+
SkipVerify bool `cloud:"skip_verify" json:"skip_verify"`
37+
NoTLS bool `cloud:"no_tls" json:"no_tls"`
38+
Host string `cloud:"host" json:"host"`
39+
Debug bool `cloud:"-" json:"debug,omitempty"`
40+
DebugLog string `cloud:"-" json:"debug_log,omitempty"`
3941
}
4042

4143
// Valid returns if all required config fields are present, false otherwise
@@ -54,7 +56,7 @@ func (c *Config) Valid() (bool, error) {
5456

5557
// Client holds the client state
5658
type Client struct {
57-
config Config
59+
config *Config
5860
httpClient *http.Client
5961
baseURL *url.URL
6062
userAgent string
@@ -77,8 +79,24 @@ func newResponse(r *http.Response) *Response {
7779
return response
7880
}
7981

82+
func doAutoconf(config *Config) {
83+
r := config.Region
84+
e := config.Environment
85+
if r != "" && e != "" {
86+
ac, err := autoconf.New(
87+
autoconf.WithRegion(r),
88+
autoconf.WithEnv(e))
89+
if err == nil {
90+
loggingService := ac.Service("cartel")
91+
if host, err := loggingService.GetString("host"); err == nil && config.Host == "" {
92+
config.Host = host
93+
}
94+
}
95+
}
96+
}
97+
8098
// NewClient returns an instance of the logger client with the given Config
81-
func NewClient(httpClient *http.Client, config Config) (*Client, error) {
99+
func NewClient(httpClient *http.Client, config *Config) (*Client, error) {
82100
if httpClient == nil {
83101
httpClient = &http.Client{}
84102
tr := &http.Transport{}
@@ -89,7 +107,7 @@ func NewClient(httpClient *http.Client, config Config) (*Client, error) {
89107
}
90108
httpClient.Transport = tr
91109
}
92-
110+
doAutoconf(config)
93111
if valid, err := config.Valid(); !valid {
94112
return nil, err
95113
}
@@ -107,13 +125,17 @@ func NewClient(httpClient *http.Client, config Config) (*Client, error) {
107125
if !strings.HasSuffix(host, "/") {
108126
host += "/"
109127
}
110-
111128
var err error
112129
cartel.baseURL, err = url.Parse(host)
113130
if err != nil {
114131
return nil, err
115132
}
116133

134+
configDebug(&cartel)
135+
return &cartel, nil
136+
}
137+
138+
func configDebug(cartel *Client) {
117139
if cartel.config.Debug {
118140
if cartel.config.DebugLog != "" {
119141
debugFile, err := os.OpenFile(cartel.config.DebugLog, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
@@ -125,7 +147,6 @@ func NewClient(httpClient *http.Client, config Config) (*Client, error) {
125147
cartel.debugFile = os.Stderr
126148
}
127149
}
128-
return &cartel, nil
129150
}
130151

131152
// Do sends an API request and returns the API response. The API response is
@@ -150,9 +171,9 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
150171
if c.config.Debug {
151172
if resp != nil {
152173
dumped, _ := httputil.DumpResponse(resp, true)
153-
fmt.Fprintf(c.debugFile, "RESPONSE: %s\n", string(dumped))
174+
_, _ = fmt.Fprintf(c.debugFile, "RESPONSE: %s\n", string(dumped))
154175
} else {
155-
fmt.Fprintf(c.debugFile, "Error sending response: %s\n", err)
176+
_, _ = fmt.Fprintf(c.debugFile, "Error sending response: %s\n", err)
156177
}
157178
}
158179

@@ -182,31 +203,13 @@ type ErrorResponse struct {
182203
Description string `json:"description"`
183204
}
184205

185-
func (e ErrorResponse) Error() string {
186-
path, _ := url.QueryUnescape(e.Response.Request.URL.Opaque)
187-
u := fmt.Sprintf("%s://%s%s", e.Response.Request.URL.Scheme, e.Response.Request.URL.Host, path)
188-
return fmt.Sprintf("%s %s: %d %s", e.Response.Request.Method, u, e.Response.StatusCode, e.Message)
189-
}
190-
191206
// CheckResponse checks the API response for errors, and returns them if present.
192207
func CheckResponse(r *http.Response) error {
193208
switch r.StatusCode {
194209
case 200, 201, 202, 204, 304:
195210
return nil
196211
}
197-
198-
errorResponse := &ErrorResponse{Response: r}
199-
data, err := ioutil.ReadAll(r.Body)
200-
if err == nil && data != nil {
201-
var raw interface{}
202-
if err := json.Unmarshal(data, &raw); err != nil {
203-
errorResponse.Message = "failed to parse unknown error format"
204-
}
205-
206-
errorResponse.Message = fhir.ParseError(raw)
207-
}
208-
209-
return errorResponse
212+
return ErrNonHttp20xResponse
210213
}
211214

212215
// NewRequest creates an API request. A relative URL path can be provided in

cartel/client_test.go

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ import (
55
"net/http"
66
"net/http/httptest"
77
"net/url"
8+
"os"
89
"testing"
10+
11+
"github.com/stretchr/testify/assert"
912
)
1013

1114
var (
@@ -41,7 +44,7 @@ func endpointMocker(secret []byte, responseBody string, statusCode ...int) func(
4144
}
4245
}
4346

44-
func setup(t *testing.T, config Config) (func(), error) {
47+
func setup(t *testing.T, config *Config) (func(), error) {
4548
var err error
4649

4750
muxCartel = http.NewServeMux()
@@ -62,3 +65,59 @@ func setup(t *testing.T, config Config) (func(), error) {
6265
cartelServer.Close()
6366
}, nil
6467
}
68+
69+
func TestDebug(t *testing.T) {
70+
tmpfile, err := ioutil.TempFile("", "cartel")
71+
if err != nil {
72+
t.Fatalf("Error: %v", err)
73+
}
74+
teardown, err := setup(t, &Config{
75+
NoTLS: true,
76+
SkipVerify: true,
77+
Token: sharedToken,
78+
Secret: sharedSecret,
79+
Host: "foo",
80+
Debug: true,
81+
DebugLog: tmpfile.Name(),
82+
})
83+
var responseBody = `[{"instance_id":"i-deadbeaf","name_tag":"some.dev","owner":"xxx","role":"container-host"}]`
84+
85+
muxCartel.HandleFunc("/v3/api/get_all_instances", endpointMocker([]byte(sharedSecret),
86+
responseBody))
87+
if !assert.Nil(t, err) {
88+
return
89+
}
90+
defer teardown()
91+
_, _, err = client.GetAllInstances()
92+
if !assert.Nil(t, err) {
93+
return
94+
}
95+
defer func() {
96+
_ = os.Remove(tmpfile.Name())
97+
}() // clean up
98+
fi, err := tmpfile.Stat()
99+
if !assert.Nil(t, err) {
100+
return
101+
}
102+
assert.Less(t, int64(0), fi.Size())
103+
}
104+
105+
func TestAutoconfig(t *testing.T) {
106+
cfg := &Config{
107+
Token: "alice",
108+
Secret: "foo",
109+
Region: "us-east",
110+
Environment: "client-test",
111+
}
112+
_, err := NewClient(nil, cfg)
113+
if !assert.Nil(t, err) {
114+
return
115+
}
116+
assert.NotEmpty(t, cfg.Host)
117+
118+
// Explicit config always wins over autoconfig
119+
foo := "foo.com"
120+
cfg.Host = foo
121+
_, _ = NewClient(nil, cfg)
122+
assert.Equal(t, foo, cfg.Host)
123+
}

cartel/create_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func TestCreate(t *testing.T) {
2121
"result": "Success"
2222
}`
2323

24-
teardown, err := setup(t, Config{
24+
teardown, err := setup(t, &Config{
2525
Token: sharedToken,
2626
Secret: sharedSecret,
2727
Host: "foo",

cartel/deployment_state_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
func TestDeploymentState(t *testing.T) {
1111
var deployResponse = `{"foo.dev":{"deploy_state":"succeeded"}}`
1212

13-
teardown, err := setup(t, Config{
13+
teardown, err := setup(t, &Config{
1414
NoTLS: true,
1515
SkipVerify: true,
1616
Token: sharedToken,

cartel/destroy_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func TestDestroy(t *testing.T) {
1515
}
1616
}`
1717

18-
teardown, err := setup(t, Config{
18+
teardown, err := setup(t, &Config{
1919
Token: sharedToken,
2020
Secret: sharedSecret,
2121
Host: "foo",

cartel/details_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
)
1010

1111
func TestDetails(t *testing.T) {
12-
teardown, err := setup(t, Config{
12+
teardown, err := setup(t, &Config{
1313
NoTLS: true,
1414
SkipVerify: true,
1515
Token: sharedToken,

cartel/errors.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ package cartel
33
import errors "golang.org/x/xerrors"
44

55
var (
6-
ErrMissingSecret = errors.New("missing secret")
7-
ErrMissingToken = errors.New("missing token")
8-
ErrMissingHost = errors.New("missing host")
9-
ErrNotImplemented = errors.New("not implemented")
10-
ErrNotFound = errors.New("not found")
6+
ErrMissingSecret = errors.New("missing secret")
7+
ErrMissingToken = errors.New("missing token")
8+
ErrMissingHost = errors.New("missing host")
9+
ErrNotImplemented = errors.New("not implemented")
10+
ErrNotFound = errors.New("not found")
11+
ErrNonHttp20xResponse = errors.New("non http 20x response")
1112
)

cartel/remove_security_groups_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
func TestRemoveSecurityGroups(t *testing.T) {
1111
var addResponse = `{"message": "Security group(s) foo removed from foo.dev.com"}`
1212

13-
teardown, err := setup(t, Config{
13+
teardown, err := setup(t, &Config{
1414
NoTLS: true,
1515
SkipVerify: true,
1616
Token: sharedToken,

cartel/remove_user_groups_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
func TestRemoveUserGroups(t *testing.T) {
1111
var addResponse = `{"message": "Security group(s) foo removed from foo.dev.com"}`
1212

13-
teardown, err := setup(t, Config{
13+
teardown, err := setup(t, &Config{
1414
NoTLS: true,
1515
SkipVerify: true,
1616
Token: sharedToken,

cartel/roles_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
)
99

1010
func TestRoles(t *testing.T) {
11-
teardown, err := setup(t, Config{
11+
teardown, err := setup(t, &Config{
1212
NoTLS: true,
1313
SkipVerify: true,
1414
Token: sharedToken,

cartel/security_group_details_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func TestSecurityGroupDetails(t *testing.T) {
2020
}
2121
]
2222
}`
23-
teardown, err := setup(t, Config{
23+
teardown, err := setup(t, &Config{
2424
Token: sharedToken,
2525
Secret: sharedSecret,
2626
Host: "foo",

cartel/security_groups_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
)
1010

1111
func TestSecurityGroups(t *testing.T) {
12-
teardown, err := setup(t, Config{
12+
teardown, err := setup(t, &Config{
1313
Token: sharedToken,
1414
Secret: sharedSecret,
1515
Host: "foo",

cartel/set_protection_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
func TestSetProtect(t *testing.T) {
1111
var protectResponse = `{"message": "Termination protection enabled for: foo.dev.com"}`
1212

13-
teardown, err := setup(t, Config{
13+
teardown, err := setup(t, &Config{
1414
Token: sharedToken,
1515
Secret: sharedSecret,
1616
Host: "foo",

0 commit comments

Comments
 (0)