Authenticate Handler API and SDK, and much more (#183)
This commit is contained in:
1 parent
acce195dcb
commit
28dbcd84bd
89 files changed
+5296
-1943
No files matched your search
@@ -0,0 +1,78 @@
|
||||
// Code generated by "make api"; DO NOT EDIT.
|
||||
package authtokens
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
|
||||
"github.com/hashicorp/watchtower/api"
|
||||
"github.com/hashicorp/watchtower/api/internal/strutil"
|
||||
)
|
||||
|
||||
type AuthToken struct {
|
||||
Client *api.Client `json:"-"`
|
||||
|
||||
defaultFields []string
|
||||
|
||||
// The ID of the AuthToken
|
||||
// Output only.
|
||||
Id string `json:"id,omitempty"`
|
||||
// The token. This will only be populated after login and is only ever visible to the end user whose login
|
||||
// request resulted in this auth token being created.
|
||||
// Output only.
|
||||
Token string `json:"token,omitempty"`
|
||||
// The id of the user of this AuthToken.
|
||||
// Output only.
|
||||
UserId string `json:"user_id,omitempty"`
|
||||
// The id of the user of this AuthToken.
|
||||
// Output only.
|
||||
AuthMethodId string `json:"auth_method_id,omitempty"`
|
||||
// The time this resource was created
|
||||
// Output only.
|
||||
CreatedTime time.Time `json:"created_time,omitempty"`
|
||||
// The time this resource was last updated.
|
||||
// Output only.
|
||||
UpdatedTime time.Time `json:"updated_time,omitempty"`
|
||||
// The approximate time this AuthToken was last used.
|
||||
// Output only.
|
||||
ApproximateLastUsedTime time.Time `json:"approximate_last_used_time,omitempty"`
|
||||
// The time this AuthToken expires.
|
||||
// Output only.
|
||||
ExpirationTime time.Time `json:"expiration_time,omitempty"`
|
||||
}
|
||||
|
||||
func (s *AuthToken) SetDefault(key string) {
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"approximatelastusedtime": "approximate_last_used_time", "authmethodid": "auth_method_id", "createdtime": "created_time", "expirationtime": "expiration_time", "id": "id", "token": "token", "updatedtime": "updated_time", "userid": "user_id"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *AuthToken) UnsetDefault(key string) {
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"approximatelastusedtime": "approximate_last_used_time", "authmethodid": "auth_method_id", "createdtime": "created_time", "expirationtime": "expiration_time", "id": "id", "token": "token", "updatedtime": "updated_time", "userid": "user_id"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s AuthToken) MarshalJSON() ([]byte, error) {
|
||||
m := structs.Map(s)
|
||||
if m == nil {
|
||||
m = make(map[string]interface{})
|
||||
}
|
||||
for _, k := range s.defaultFields {
|
||||
m[k] = nil
|
||||
}
|
||||
return json.Marshal(m)
|
||||
}
|
||||
+39
-7
@@ -143,6 +143,7 @@ func DefaultConfig() (*Config, error) {
|
||||
Addr: "https://127.0.0.1:9200",
|
||||
HttpClient: cleanhttp.DefaultPooledClient(),
|
||||
Timeout: time.Second * 60,
|
||||
TLSConfig: &TLSConfig{},
|
||||
}
|
||||
|
||||
// We read the environment now; after DefaultClient returns we can override
|
||||
@@ -217,10 +218,10 @@ func (c *Config) ConfigureTLS() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// setAddress parses a given string and looks for org and project info, setting
|
||||
// the actual address to the base. Note that if a very malformed URL is passed
|
||||
// in, this may not return what one expects. For now this is on purpose to
|
||||
// avoid requiring error handling.
|
||||
// setAddr parses a given string and looks for org and project info, setting the
|
||||
// actual address to the base. Note that if a very malformed URL is passed in,
|
||||
// this may not return what one expects. For now this is on purpose to avoid
|
||||
// requiring error handling.
|
||||
//
|
||||
// This also removes any trailing "/v1"; we'll use that in our commands so we
|
||||
// don't require it from users.
|
||||
@@ -449,6 +450,14 @@ func (c *Client) SetAddr(addr string) error {
|
||||
return c.config.setAddr(addr)
|
||||
}
|
||||
|
||||
// Org fetches the org the client will use by default
|
||||
func (c *Client) Org() string {
|
||||
c.modifyLock.Lock()
|
||||
defer c.modifyLock.Unlock()
|
||||
|
||||
return c.config.Org
|
||||
}
|
||||
|
||||
// SetOrg sets the org the client will use by default
|
||||
func (c *Client) SetOrg(org string) {
|
||||
c.modifyLock.Lock()
|
||||
@@ -457,6 +466,14 @@ func (c *Client) SetOrg(org string) {
|
||||
c.config.Org = org
|
||||
}
|
||||
|
||||
// Project fetches the project the client will use by default
|
||||
func (c *Client) Project() string {
|
||||
c.modifyLock.Lock()
|
||||
defer c.modifyLock.Unlock()
|
||||
|
||||
return c.config.Project
|
||||
}
|
||||
|
||||
// SetProject sets the project the client will use by default
|
||||
func (c *Client) SetProject(project string) {
|
||||
c.modifyLock.Lock()
|
||||
@@ -519,6 +536,14 @@ func (c *Client) SetOutputCurlString(curl bool) {
|
||||
c.config.OutputCurlString = curl
|
||||
}
|
||||
|
||||
// Token gets the configured token.
|
||||
func (c *Client) Token() string {
|
||||
c.modifyLock.Lock()
|
||||
defer c.modifyLock.Unlock()
|
||||
|
||||
return c.config.Token
|
||||
}
|
||||
|
||||
// SetToken sets the token directly. This won't perform any auth
|
||||
// verification, it simply sets the token properly for future requests.
|
||||
func (c *Client) SetToken(token string) {
|
||||
@@ -700,18 +725,25 @@ func (c *Client) NewRequest(ctx context.Context, method, requestPath string, bod
|
||||
orgProjPath = path.Join(orgProjPath, "projects", project)
|
||||
}
|
||||
|
||||
p := path.Join(u.Path, "/v1", orgProjPath)
|
||||
if strings.HasPrefix(requestPath, ":") {
|
||||
p = p + requestPath
|
||||
} else {
|
||||
p = path.Join(p, requestPath)
|
||||
}
|
||||
|
||||
req := &http.Request{
|
||||
Method: method,
|
||||
URL: &url.URL{
|
||||
User: u.User,
|
||||
Scheme: u.Scheme,
|
||||
Host: host,
|
||||
Path: path.Join(u.Path, "/v1", orgProjPath, requestPath),
|
||||
Path: p,
|
||||
},
|
||||
Host: u.Host,
|
||||
}
|
||||
req.Header = headers
|
||||
req.Header.Add("authorization", "bearer: "+token)
|
||||
req.Header.Add("authorization", "Bearer "+token)
|
||||
req.Header.Set("content-type", "application/json")
|
||||
if ctx != nil {
|
||||
req = req.WithContext(ctx)
|
||||
@@ -786,7 +818,7 @@ func (c *Client) Do(r *retryablehttp.Request) (*Response, error) {
|
||||
}
|
||||
|
||||
result, err := client.Do(r)
|
||||
if result != nil && err == nil && result.StatusCode == 307 {
|
||||
if result != nil && err == nil && result.StatusCode == http.StatusTemporaryRedirect {
|
||||
loc, err := result.Location()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting new location during redirect: %w", err)
|
||||
|
||||
+20
-5
@@ -3,6 +3,7 @@ package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
|
||||
@@ -13,22 +14,36 @@ type Error struct {
|
||||
defaultFields []string
|
||||
|
||||
// The HTTP Status code applicable to this error
|
||||
Status *int32 `json:"status,omitempty"`
|
||||
Status int32 `json:"status,omitempty"`
|
||||
// An application-specific error string
|
||||
Code *string `json:"code,omitempty"`
|
||||
Code string `json:"code,omitempty"`
|
||||
// A human readable explanation specific to this occurrence of the error
|
||||
Message *string `json:"message,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
// Additional metadata regarding the error. Depending on the error
|
||||
// different fields will be populated.
|
||||
Details *ErrorDetails `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Error) SetDefault(key string) {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"code": "code", "details": "details", "message": "message", "status": "status"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Error) UnsetDefault(key string) {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"code": "code", "details": "details", "message": "message", "status": "status"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s Error) MarshalJSON() ([]byte, error) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
|
||||
@@ -12,17 +13,31 @@ import (
|
||||
type ErrorDetails struct {
|
||||
defaultFields []string
|
||||
|
||||
TraceId *string `json:"TraceId,omitempty"`
|
||||
RequestId *string `json:"request_id,omitempty"`
|
||||
TraceId string `json:"TraceId,omitempty"`
|
||||
RequestId string `json:"request_id,omitempty"`
|
||||
RequestFields []*FieldError `json:"request_fields,omitempty"`
|
||||
}
|
||||
|
||||
func (s *ErrorDetails) SetDefault(key string) {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"requestfields": "request_fields", "requestid": "request_id", "traceid": "TraceId"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ErrorDetails) UnsetDefault(key string) {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"requestfields": "request_fields", "requestid": "request_id", "traceid": "TraceId"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s ErrorDetails) MarshalJSON() ([]byte, error) {
|
||||
|
||||
+19
-4
@@ -3,6 +3,7 @@ package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
|
||||
@@ -12,16 +13,30 @@ import (
|
||||
type FieldError struct {
|
||||
defaultFields []string
|
||||
|
||||
Name *string `json:"name,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
func (s *FieldError) SetDefault(key string) {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"description": "description", "name": "name"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *FieldError) UnsetDefault(key string) {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"description": "description", "name": "name"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s FieldError) MarshalJSON() ([]byte, error) {
|
||||
|
||||
+17
-2
@@ -3,6 +3,7 @@ package groups
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
@@ -34,11 +35,25 @@ type Group struct {
|
||||
}
|
||||
|
||||
func (s *Group) SetDefault(key string) {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "name": "name", "updatedtime": "updated_time"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Group) UnsetDefault(key string) {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "name": "name", "updatedtime": "updated_time"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s Group) MarshalJSON() ([]byte, error) {
|
||||
|
||||
@@ -116,8 +116,8 @@ func TestGroup_Crud(t *testing.T) {
|
||||
checkGroup := func(step string, g *groups.Group, apiErr *api.Error, err error, wantedName string) {
|
||||
assert := assert.New(t)
|
||||
assert.NoError(err, step)
|
||||
if !assert.Nil(apiErr, step) && apiErr.Message != nil {
|
||||
t.Errorf("ApiError message: %q", *apiErr.Message)
|
||||
if !assert.Nil(apiErr, step) && apiErr.Message != "" {
|
||||
t.Errorf("ApiError message: %q", apiErr.Message)
|
||||
}
|
||||
assert.NotNil(g, "returned no resource", step)
|
||||
gotName := ""
|
||||
@@ -216,17 +216,17 @@ func TestGroup_Errors(t *testing.T) {
|
||||
_, apiErr, err = tt.scope.ReadGroup(ctx, &groups.Group{Id: iam.GroupPrefix + "_doesntexis"})
|
||||
assert.NoError(err)
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(*apiErr.Status, http.StatusNotFound)
|
||||
assert.EqualValues(apiErr.Status, http.StatusNotFound)
|
||||
|
||||
_, apiErr, err = tt.scope.ReadGroup(ctx, &groups.Group{Id: "invalid id"})
|
||||
assert.NoError(err)
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(*apiErr.Status, http.StatusBadRequest)
|
||||
assert.EqualValues(apiErr.Status, http.StatusBadRequest)
|
||||
|
||||
_, apiErr, err = tt.scope.UpdateGroup(ctx, &groups.Group{Id: u.Id})
|
||||
assert.NoError(err)
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(*apiErr.Status, http.StatusBadRequest)
|
||||
assert.EqualValues(apiErr.Status, http.StatusBadRequest)
|
||||
})
|
||||
}
|
||||
}
|
||||
+17
-2
@@ -3,6 +3,7 @@ package hosts
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
@@ -38,11 +39,25 @@ type Host struct {
|
||||
}
|
||||
|
||||
func (s *Host) SetDefault(key string) {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"address": "address", "createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "name": "name", "type": "type", "updatedtime": "updated_time"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Host) UnsetDefault(key string) {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"address": "address", "createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "name": "name", "type": "type", "updatedtime": "updated_time"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s Host) MarshalJSON() ([]byte, error) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package hosts
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
@@ -39,11 +40,25 @@ type HostCatalog struct {
|
||||
}
|
||||
|
||||
func (s *HostCatalog) SetDefault(key string) {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"attributes": "attributes", "createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "name": "name", "type": "type", "updatedtime": "updated_time"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *HostCatalog) UnsetDefault(key string) {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"attributes": "attributes", "createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "name": "name", "type": "type", "updatedtime": "updated_time"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s HostCatalog) MarshalJSON() ([]byte, error) {
|
||||
|
||||
@@ -29,8 +29,8 @@ func TestCatalogs_Crud(t *testing.T) {
|
||||
checkCatalog := func(step string, hc *hosts.HostCatalog, apiErr *api.Error, err error, wantedName string) {
|
||||
assert := assert.New(t)
|
||||
assert.NoError(err, step)
|
||||
if !assert.Nil(apiErr, step) && apiErr.Message != nil {
|
||||
t.Errorf("ApiError message: %q", *apiErr.Message)
|
||||
if !assert.Nil(apiErr, step) && apiErr.Message != "" {
|
||||
t.Errorf("ApiError message: %q", apiErr.Message)
|
||||
}
|
||||
assert.NotNil(hc, "returned no resource", step)
|
||||
gotName := ""
|
||||
@@ -94,15 +94,15 @@ func TestCatalogs_Errors(t *testing.T) {
|
||||
assert.NoError(err)
|
||||
// TODO: Should this be nil instead of just a catalog that has no values set
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(*apiErr.Status, http.StatusNotFound)
|
||||
assert.EqualValues(apiErr.Status, http.StatusNotFound)
|
||||
|
||||
_, apiErr, err = p.ReadHostCatalog(ctx, &hosts.HostCatalog{Id: "invalid id"})
|
||||
assert.NoError(err)
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(*apiErr.Status, http.StatusBadRequest)
|
||||
assert.EqualValues(apiErr.Status, http.StatusBadRequest)
|
||||
|
||||
_, apiErr, err = p.UpdateHostCatalog(ctx, &hosts.HostCatalog{Id: hc.Id, Type: api.String("Cant Update")})
|
||||
assert.NoError(err)
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(*apiErr.Status, http.StatusBadRequest)
|
||||
assert.EqualValues(apiErr.Status, http.StatusBadRequest)
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package hosts
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
@@ -44,11 +45,25 @@ type HostSet struct {
|
||||
}
|
||||
|
||||
func (s *HostSet) SetDefault(key string) {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "hosts": "hosts", "id": "id", "name": "name", "size": "size", "type": "type", "updatedtime": "updated_time"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *HostSet) UnsetDefault(key string) {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "hosts": "hosts", "id": "id", "name": "name", "size": "size", "type": "type", "updatedtime": "updated_time"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s HostSet) MarshalJSON() ([]byte, error) {
|
||||
|
||||
+86
-117
@@ -12,150 +12,119 @@ type structInfo struct {
|
||||
parentName string
|
||||
detailName string
|
||||
templateType templateType
|
||||
nameJsonMap map[string]string
|
||||
}
|
||||
|
||||
var inputStructs = []*structInfo{
|
||||
{
|
||||
os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/error.pb.go",
|
||||
"Error",
|
||||
os.Getenv("GEN_BASEPATH") + "/api/error.gen.go",
|
||||
"Error",
|
||||
"api",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
templateTypeResource,
|
||||
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/error.pb.go",
|
||||
inName: "Error",
|
||||
outFile: os.Getenv("GEN_BASEPATH") + "/api/error.gen.go",
|
||||
outName: "Error",
|
||||
outPkg: "api",
|
||||
},
|
||||
{
|
||||
os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/error.pb.go",
|
||||
"ErrorDetails",
|
||||
os.Getenv("GEN_BASEPATH") + "/api/error_details.gen.go",
|
||||
"ErrorDetails",
|
||||
"api",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
templateTypeResource,
|
||||
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/error.pb.go",
|
||||
inName: "ErrorDetails",
|
||||
outFile: os.Getenv("GEN_BASEPATH") + "/api/error_details.gen.go",
|
||||
outName: "ErrorDetails",
|
||||
outPkg: "api",
|
||||
},
|
||||
{
|
||||
os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/error.pb.go",
|
||||
"FieldError",
|
||||
os.Getenv("GEN_BASEPATH") + "/api/field_error.gen.go",
|
||||
"FieldError",
|
||||
"api",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
templateTypeResource,
|
||||
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/error.pb.go",
|
||||
inName: "FieldError",
|
||||
outFile: os.Getenv("GEN_BASEPATH") + "/api/field_error.gen.go",
|
||||
outName: "FieldError",
|
||||
outPkg: "api",
|
||||
},
|
||||
{
|
||||
os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/hosts/host.pb.go",
|
||||
"Host",
|
||||
os.Getenv("GEN_BASEPATH") + "/api/hosts/host.gen.go",
|
||||
"Host",
|
||||
"hosts",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
templateTypeResource,
|
||||
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/hosts/host.pb.go",
|
||||
inName: "Host",
|
||||
outFile: os.Getenv("GEN_BASEPATH") + "/api/hosts/host.gen.go",
|
||||
outName: "Host",
|
||||
outPkg: "hosts",
|
||||
},
|
||||
{
|
||||
os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/hosts/host_set.pb.go",
|
||||
"HostSet",
|
||||
os.Getenv("GEN_BASEPATH") + "/api/hosts/host_set.gen.go",
|
||||
"HostSet",
|
||||
"hosts",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
templateTypeResource,
|
||||
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/hosts/host_set.pb.go",
|
||||
inName: "HostSet",
|
||||
outFile: os.Getenv("GEN_BASEPATH") + "/api/hosts/host_set.gen.go",
|
||||
outName: "HostSet",
|
||||
outPkg: "hosts",
|
||||
},
|
||||
{
|
||||
os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/hosts/host_catalog.pb.go",
|
||||
"HostCatalog",
|
||||
os.Getenv("GEN_BASEPATH") + "/api/hosts/host_catalog.gen.go",
|
||||
"HostCatalog",
|
||||
"hosts",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
templateTypeResource,
|
||||
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/hosts/host_catalog.pb.go",
|
||||
inName: "HostCatalog",
|
||||
outFile: os.Getenv("GEN_BASEPATH") + "/api/hosts/host_catalog.gen.go",
|
||||
outName: "HostCatalog",
|
||||
outPkg: "hosts",
|
||||
},
|
||||
{
|
||||
os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/scopes/org.pb.go",
|
||||
"Org",
|
||||
os.Getenv("GEN_BASEPATH") + "/api/scopes/org.gen.go",
|
||||
"Org",
|
||||
"scopes",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
templateTypeResource,
|
||||
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/scopes/org.pb.go",
|
||||
inName: "Org",
|
||||
outFile: os.Getenv("GEN_BASEPATH") + "/api/scopes/org.gen.go",
|
||||
outName: "Org",
|
||||
outPkg: "scopes",
|
||||
},
|
||||
{
|
||||
os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/scopes/project.pb.go",
|
||||
"Project",
|
||||
os.Getenv("GEN_BASEPATH") + "/api/scopes/project.gen.go",
|
||||
"Project",
|
||||
"scopes",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
templateTypeResource,
|
||||
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/authtokens/authtoken.pb.go",
|
||||
inName: "AuthToken",
|
||||
outFile: os.Getenv("GEN_BASEPATH") + "/api/authtokens/authtoken.gen.go",
|
||||
outName: "AuthToken",
|
||||
outPkg: "authtokens",
|
||||
},
|
||||
{
|
||||
os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/users/user.pb.go",
|
||||
"User",
|
||||
os.Getenv("GEN_BASEPATH") + "/api/users/user.gen.go",
|
||||
"User",
|
||||
"users",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
templateTypeResource,
|
||||
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/scopes/project.pb.go",
|
||||
inName: "Project",
|
||||
outFile: os.Getenv("GEN_BASEPATH") + "/api/scopes/project.gen.go",
|
||||
outName: "Project",
|
||||
outPkg: "scopes",
|
||||
},
|
||||
{
|
||||
os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/groups/group.pb.go",
|
||||
"Group",
|
||||
os.Getenv("GEN_BASEPATH") + "/api/groups/group.gen.go",
|
||||
"Group",
|
||||
"groups",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
templateTypeResource,
|
||||
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/users/user.pb.go",
|
||||
inName: "User",
|
||||
outFile: os.Getenv("GEN_BASEPATH") + "/api/users/user.gen.go",
|
||||
outName: "User",
|
||||
outPkg: "users",
|
||||
},
|
||||
{
|
||||
os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/roles/role.pb.go",
|
||||
"Role",
|
||||
os.Getenv("GEN_BASEPATH") + "/api/roles/role.gen.go",
|
||||
"Role",
|
||||
"roles",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
templateTypeResource,
|
||||
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/groups/group.pb.go",
|
||||
inName: "Group",
|
||||
outFile: os.Getenv("GEN_BASEPATH") + "/api/groups/group.gen.go",
|
||||
outName: "Group",
|
||||
outPkg: "groups",
|
||||
},
|
||||
{
|
||||
os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/hosts/host_catalog.pb.go",
|
||||
"StaticHostCatalogDetails",
|
||||
os.Getenv("GEN_BASEPATH") + "/api/hosts/static_host_catalog.gen.go",
|
||||
"StaticHostCatalogDetails",
|
||||
"hosts",
|
||||
"",
|
||||
"HostCatalog",
|
||||
"StaticHostCatalog",
|
||||
templateTypeDetail,
|
||||
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/roles/role.pb.go",
|
||||
inName: "Role",
|
||||
outFile: os.Getenv("GEN_BASEPATH") + "/api/roles/role.gen.go",
|
||||
outName: "Role",
|
||||
outPkg: "roles",
|
||||
},
|
||||
{
|
||||
os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/hosts/host_catalog.pb.go",
|
||||
"AwsEc2HostCatalogDetails",
|
||||
os.Getenv("GEN_BASEPATH") + "/api/hosts/awsec2_host_catalog.gen.go",
|
||||
"AwsEc2HostCatalogDetails",
|
||||
"hosts",
|
||||
"",
|
||||
"HostCatalog",
|
||||
"AwsEc2HostCatalog",
|
||||
templateTypeDetail,
|
||||
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/roles/role.pb.go",
|
||||
inName: "Principal",
|
||||
outFile: os.Getenv("GEN_BASEPATH") + "/api/roles/principal.gen.go",
|
||||
outName: "Principal",
|
||||
outPkg: "roles",
|
||||
},
|
||||
{
|
||||
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/hosts/host_catalog.pb.go",
|
||||
inName: "StaticHostCatalogDetails",
|
||||
outFile: os.Getenv("GEN_BASEPATH") + "/api/hosts/static_host_catalog.gen.go",
|
||||
outName: "StaticHostCatalogDetails",
|
||||
outPkg: "hosts",
|
||||
parentName: "HostCatalog",
|
||||
detailName: "StaticHostCatalog",
|
||||
templateType: templateTypeDetail,
|
||||
},
|
||||
{
|
||||
inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/hosts/host_catalog.pb.go",
|
||||
inName: "AwsEc2HostCatalogDetails",
|
||||
outFile: os.Getenv("GEN_BASEPATH") + "/api/hosts/awsec2_host_catalog.gen.go",
|
||||
outName: "AwsEc2HostCatalogDetails",
|
||||
outPkg: "hosts",
|
||||
parentName: "HostCatalog",
|
||||
detailName: "AwsEc2HostCatalog",
|
||||
templateType: templateTypeDetail,
|
||||
},
|
||||
}
|
||||
@@ -38,6 +38,7 @@ func parsePBs() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
inputStruct.nameJsonMap = make(map[string]string)
|
||||
ast.Walk(visitFn(func(n ast.Node) {
|
||||
spec, ok := n.(*ast.TypeSpec)
|
||||
if !ok {
|
||||
@@ -114,11 +115,6 @@ func parsePBs() {
|
||||
var selectorExpr *ast.SelectorExpr
|
||||
switch typ := field.Type.(type) {
|
||||
case *ast.Ident:
|
||||
// Id values are immutable and should always exist, so
|
||||
// don't make it a pointer
|
||||
if field.Names[0].Name != "Id" {
|
||||
typ.Name = "*" + typ.Name
|
||||
}
|
||||
goto TAGMODIFY
|
||||
case *ast.ArrayType:
|
||||
goto TAGMODIFY
|
||||
@@ -222,7 +218,10 @@ func parsePBs() {
|
||||
}
|
||||
|
||||
TAGMODIFY:
|
||||
st.Fields.List[i].Tag.Value = "`" + regex.FindString(st.Fields.List[i].Tag.Value) + "`"
|
||||
tagString := regex.FindString(st.Fields.List[i].Tag.Value)
|
||||
st.Fields.List[i].Tag.Value = "`" + tagString + "`"
|
||||
tagString = strings.TrimSuffix(strings.TrimPrefix(tagString, `json:"`), `,omitempty"`)
|
||||
inputStruct.nameJsonMap[strings.ToLower(field.Names[0].Name)] = tagString
|
||||
}
|
||||
}), inAst)
|
||||
|
||||
|
||||
@@ -37,11 +37,6 @@ var readFuncs = map[string][]*readInfo{
|
||||
targetType: "users.User",
|
||||
path: "users",
|
||||
},
|
||||
{
|
||||
baseType: "Project",
|
||||
targetType: "hosts.HostCatalog",
|
||||
path: "host-catalogs",
|
||||
},
|
||||
{
|
||||
baseType: "Project",
|
||||
targetType: "groups.Group",
|
||||
@@ -52,6 +47,11 @@ var readFuncs = map[string][]*readInfo{
|
||||
targetType: "roles.Role",
|
||||
path: "roles",
|
||||
},
|
||||
{
|
||||
baseType: "Project",
|
||||
targetType: "hosts.HostCatalog",
|
||||
path: "host-catalogs",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -25,10 +25,12 @@ func writeStructTemplates() {
|
||||
Name string
|
||||
Package string
|
||||
StructFields string
|
||||
NameJsonMap map[string]string
|
||||
}{
|
||||
Name: inputStruct.outName,
|
||||
Package: inputStruct.outPkg,
|
||||
StructFields: inputStruct.structFields,
|
||||
NameJsonMap: inputStruct.nameJsonMap,
|
||||
})
|
||||
|
||||
case templateTypeDetail:
|
||||
@@ -61,11 +63,12 @@ func writeStructTemplates() {
|
||||
// TODO: Add documentation around SetDefault and how it behaves when the field corresponding to the provided key is already set.
|
||||
var structTemplate = template.Must(template.New("").Parse(
|
||||
`// Code generated by "make api"; DO NOT EDIT.
|
||||
package {{ .Package }}
|
||||
package {{ .Package }}
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
|
||||
@@ -82,11 +85,25 @@ type {{ .Name }} struct {
|
||||
}
|
||||
|
||||
func (s *{{ .Name }}) SetDefault(key string) {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := {{ printf "%#v" .NameJsonMap }}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *{{ .Name }}) UnsetDefault(key string) {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := {{ printf "%#v" .NameJsonMap }}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s {{ .Name }}) MarshalJSON() ([]byte, error) {
|
||||
|
||||
+26
-11
@@ -32,25 +32,40 @@ func (r *Response) Decode(inStruct interface{}) (*Error, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// TODO Remove as we'll use the common err format for this
|
||||
if r.resp.StatusCode == 403 {
|
||||
// Nothing to be done
|
||||
return &Error{
|
||||
Status: http.StatusForbidden,
|
||||
Message: "Forbidden",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if inStruct == nil {
|
||||
return nil, fmt.Errorf("nil value given to decode into and not a 204 response")
|
||||
}
|
||||
|
||||
r.Body = new(bytes.Buffer)
|
||||
if _, err := r.Body.ReadFrom(r.resp.Body); err != nil {
|
||||
return nil, fmt.Errorf("error reading response body: %w", err)
|
||||
apiErr := &Error{
|
||||
Status: int32(r.resp.StatusCode),
|
||||
}
|
||||
if r.resp.Body != nil {
|
||||
r.Body = new(bytes.Buffer)
|
||||
if _, err := r.Body.ReadFrom(r.resp.Body); err != nil {
|
||||
return nil, fmt.Errorf("error reading response body: %w", err)
|
||||
}
|
||||
|
||||
dec := json.NewDecoder(bytes.NewReader(r.Body.Bytes()))
|
||||
var apiErr Error
|
||||
if r.resp.StatusCode >= 400 {
|
||||
inStruct = &apiErr
|
||||
}
|
||||
if err := dec.Decode(inStruct); err != nil {
|
||||
return nil, fmt.Errorf("error decoding response: %w; response was %s", err, r.Body.String())
|
||||
if r.Body.Len() != 0 {
|
||||
dec := json.NewDecoder(bytes.NewReader(r.Body.Bytes()))
|
||||
if r.resp.StatusCode >= 400 {
|
||||
inStruct = apiErr
|
||||
}
|
||||
if err := dec.Decode(inStruct); err != nil {
|
||||
return nil, fmt.Errorf("error decoding response: %w; response was %s", err, r.Body.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
if r.resp.StatusCode >= 400 {
|
||||
return &apiErr, nil
|
||||
return apiErr, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
|
||||
+29
-15
@@ -7,16 +7,17 @@ import (
|
||||
"github.com/hashicorp/watchtower/api"
|
||||
)
|
||||
|
||||
func (s Role) AddPrincipals(ctx context.Context, groups, users []string) (*Role, *api.Error, error) {
|
||||
func (s Role) AddPrincipals(ctx context.Context, principalIds []string) (*Role, *api.Error, error) {
|
||||
if s.Client == nil {
|
||||
return nil, nil, fmt.Errorf("nil client in AddPrincipals request")
|
||||
}
|
||||
// We assume that the client provided has the org and optionally the project id of the request.
|
||||
|
||||
body := map[string]interface{}{
|
||||
"group_ids": groups,
|
||||
"user_ids": users,
|
||||
"version": s.Version,
|
||||
"version": s.Version,
|
||||
}
|
||||
if len(principalIds) > 0 {
|
||||
body["principal_ids"] = principalIds
|
||||
}
|
||||
|
||||
req, err := s.Client.NewRequest(ctx, "POST", fmt.Sprintf("roles/%s:add-principals", s.Id), body)
|
||||
@@ -40,16 +41,20 @@ func (s Role) AddPrincipals(ctx context.Context, groups, users []string) (*Role,
|
||||
return target, apiErr, nil
|
||||
}
|
||||
|
||||
func (s Role) SetPrincipals(ctx context.Context, groups, users []string) (*Role, *api.Error, error) {
|
||||
func (s Role) SetPrincipals(ctx context.Context, principalIds []string) (*Role, *api.Error, error) {
|
||||
if s.Client == nil {
|
||||
return nil, nil, fmt.Errorf("nil client in SetPrincipals request")
|
||||
}
|
||||
// We assume that the client provided has the org and optionally the project id of the request.
|
||||
|
||||
body := map[string]interface{}{
|
||||
"group_ids": groups,
|
||||
"user_ids": users,
|
||||
"version": s.Version,
|
||||
"version": s.Version,
|
||||
}
|
||||
if len(principalIds) > 0 {
|
||||
body["principal_ids"] = principalIds
|
||||
} else if principalIds != nil {
|
||||
// In this function, a non-nil but empty list means clear out
|
||||
body["principal_ids"] = nil
|
||||
}
|
||||
|
||||
req, err := s.Client.NewRequest(ctx, "POST", fmt.Sprintf("roles/%s:set-principals", s.Id), body)
|
||||
@@ -73,16 +78,17 @@ func (s Role) SetPrincipals(ctx context.Context, groups, users []string) (*Role,
|
||||
return target, apiErr, nil
|
||||
}
|
||||
|
||||
func (s Role) RemovePrincipals(ctx context.Context, groups, users []string) (*Role, *api.Error, error) {
|
||||
func (s Role) RemovePrincipals(ctx context.Context, principalIds []string) (*Role, *api.Error, error) {
|
||||
if s.Client == nil {
|
||||
return nil, nil, fmt.Errorf("nil client in RemovePrincipals request")
|
||||
}
|
||||
// We assume that the client provided has the org and optionally the project id of the request.
|
||||
|
||||
body := map[string]interface{}{
|
||||
"group_ids": groups,
|
||||
"user_ids": users,
|
||||
"version": s.Version,
|
||||
"version": s.Version,
|
||||
}
|
||||
if len(principalIds) > 0 {
|
||||
body["principal_ids"] = principalIds
|
||||
}
|
||||
|
||||
req, err := s.Client.NewRequest(ctx, "POST", fmt.Sprintf("roles/%s:remove-principals", s.Id), body)
|
||||
@@ -113,9 +119,11 @@ func (s Role) AddGrants(ctx context.Context, grants []string) (*Role, *api.Error
|
||||
// We assume that the client provided has the org and optionally the project id of the request.
|
||||
|
||||
body := map[string]interface{}{
|
||||
"grants": grants,
|
||||
"version": s.Version,
|
||||
}
|
||||
if len(grants) > 0 {
|
||||
body["grants"] = grants
|
||||
}
|
||||
|
||||
req, err := s.Client.NewRequest(ctx, "POST", fmt.Sprintf("roles/%s:add-grants", s.Id), body)
|
||||
if err != nil {
|
||||
@@ -145,9 +153,13 @@ func (s Role) SetGrants(ctx context.Context, grants []string) (*Role, *api.Error
|
||||
// We assume that the client provided has the org and optionally the project id of the request.
|
||||
|
||||
body := map[string]interface{}{
|
||||
"grants": grants,
|
||||
"version": s.Version,
|
||||
}
|
||||
if len(grants) > 0 {
|
||||
body["grants"] = grants
|
||||
} else if grants != nil {
|
||||
body["grants"] = nil
|
||||
}
|
||||
|
||||
req, err := s.Client.NewRequest(ctx, "POST", fmt.Sprintf("roles/%s:set-grants", s.Id), body)
|
||||
if err != nil {
|
||||
@@ -177,9 +189,11 @@ func (s Role) RemoveGrants(ctx context.Context, grants []string) (*Role, *api.Er
|
||||
// We assume that the client provided has the org and optionally the project id of the request.
|
||||
|
||||
body := map[string]interface{}{
|
||||
"grants": grants,
|
||||
"version": s.Version,
|
||||
}
|
||||
if len(grants) > 0 {
|
||||
body["grants"] = grants
|
||||
}
|
||||
|
||||
req, err := s.Client.NewRequest(ctx, "POST", fmt.Sprintf("roles/%s:remove-grants", s.Id), body)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// Code generated by "make api"; DO NOT EDIT.
|
||||
package roles
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
|
||||
"github.com/hashicorp/watchtower/api"
|
||||
"github.com/hashicorp/watchtower/api/internal/strutil"
|
||||
)
|
||||
|
||||
type Principal struct {
|
||||
Client *api.Client `json:"-"`
|
||||
|
||||
defaultFields []string
|
||||
|
||||
// The ID of the principal.
|
||||
// Output only.
|
||||
Id string `json:"id,omitempty"`
|
||||
// The type of the principal.
|
||||
// Output only.
|
||||
Type string `json:"type,omitempty"`
|
||||
// The scope ID of the principal.
|
||||
// Output only.
|
||||
ScopeId string `json:"scope_id,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Principal) SetDefault(key string) {
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"id": "id", "scopeid": "scope_id", "type": "type"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Principal) UnsetDefault(key string) {
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"id": "id", "scopeid": "scope_id", "type": "type"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s Principal) MarshalJSON() ([]byte, error) {
|
||||
m := structs.Map(s)
|
||||
if m == nil {
|
||||
m = make(map[string]interface{})
|
||||
}
|
||||
for _, k := range s.defaultFields {
|
||||
m[k] = nil
|
||||
}
|
||||
return json.Marshal(m)
|
||||
}
|
||||
+23
-7
@@ -3,6 +3,7 @@ package roles
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
@@ -40,13 +41,14 @@ type Role struct {
|
||||
// The version can be used in subsiquent write requests to ensure this resource
|
||||
// has not changed and to fail the write if it has.
|
||||
// Output only.
|
||||
Version *uint32 `json:"version,omitempty"`
|
||||
// The principals that are assigned this role.
|
||||
Version uint32 `json:"version,omitempty"`
|
||||
// The IDs (only) of principals that are assigned to this role.
|
||||
// Output only.
|
||||
UserIds []string `json:"user_ids,omitempty"`
|
||||
PrincipalIds []string `json:"principal_ids,omitempty"`
|
||||
// The principals that are assigned to this role.
|
||||
// Output only.
|
||||
GroupIds []string `json:"group_ids,omitempty"`
|
||||
// The grants that this role provides for it's principals.
|
||||
Principals []*Principal `json:"principals,omitempty"`
|
||||
// The grants that this role provides for its principals.
|
||||
// Output only.
|
||||
Grants []string `json:"grants,omitempty"`
|
||||
// The canonical version of the grants in the grants field with the same index.
|
||||
@@ -58,11 +60,25 @@ type Role struct {
|
||||
}
|
||||
|
||||
func (s *Role) SetDefault(key string) {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "grants": "grants", "grantscanonical": "grants_canonical", "grantscopeid": "grant_scope_id", "grantsjson": "grants_json", "id": "id", "name": "name", "principalids": "principal_ids", "principals": "principals", "updatedtime": "updated_time", "version": "version"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Role) UnsetDefault(key string) {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "grants": "grants", "grantscanonical": "grants_canonical", "grantscopeid": "grant_scope_id", "grantsjson": "grants_json", "id": "id", "name": "name", "principalids": "principal_ids", "principals": "principals", "updatedtime": "updated_time", "version": "version"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s Role) MarshalJSON() ([]byte, error) {
|
||||
|
||||
+86
-56
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/vault/sdk/helper/strutil"
|
||||
"github.com/hashicorp/watchtower/api"
|
||||
"github.com/hashicorp/watchtower/api/groups"
|
||||
"github.com/hashicorp/watchtower/api/roles"
|
||||
@@ -27,7 +28,7 @@ type roleCrud interface {
|
||||
}
|
||||
|
||||
func TestCustom(t *testing.T) {
|
||||
tc := controller.NewTestController(t, nil)
|
||||
tc := controller.NewTestController(t, &controller.TestControllerOpts{DisableAuthorizationFailures: true})
|
||||
defer tc.Shutdown()
|
||||
|
||||
client := tc.Client()
|
||||
@@ -56,6 +57,22 @@ func TestCustom(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
hasPrincipal := func(role *roles.Role, principalId string) bool {
|
||||
var foundInPrincipals bool
|
||||
var foundInPrincipalIds bool
|
||||
for _, v := range role.Principals {
|
||||
if v.Id == principalId {
|
||||
foundInPrincipals = true
|
||||
}
|
||||
}
|
||||
for _, v := range role.PrincipalIds {
|
||||
if v == principalId {
|
||||
foundInPrincipalIds = true
|
||||
}
|
||||
}
|
||||
return foundInPrincipals && foundInPrincipalIds
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
require := require.New(t)
|
||||
@@ -70,63 +87,52 @@ func TestCustom(t *testing.T) {
|
||||
require.Nil(apiErr)
|
||||
require.NotNil(r)
|
||||
|
||||
updatedRole, apiErr, err := r.AddPrincipals(ctx, []string{g.Id}, nil)
|
||||
updatedRole, apiErr, err := r.AddPrincipals(ctx, []string{g.Id})
|
||||
require.NoError(err)
|
||||
require.Nil(apiErr, "Got error ", errorMessage(apiErr))
|
||||
assert.Equal(t, *updatedRole.Version, (*r.Version)+1)
|
||||
assert.Contains(t, updatedRole.GroupIds, g.Id)
|
||||
assert.Empty(t, updatedRole.UserIds)
|
||||
require.Nil(apiErr, "Got error ", apiErr)
|
||||
assert.Equal(t, updatedRole.Version, r.Version+1)
|
||||
assert.True(t, hasPrincipal(updatedRole, g.Id))
|
||||
|
||||
r = updatedRole
|
||||
updatedRole, apiErr, err = r.SetPrincipals(ctx, nil, []string{user.Id})
|
||||
updatedRole, apiErr, err = r.SetPrincipals(ctx, []string{user.Id})
|
||||
require.NoError(err)
|
||||
require.Nil(apiErr, "Got error ", errorMessage(apiErr))
|
||||
assert.Equal(t, *updatedRole.Version, (*r.Version)+1)
|
||||
assert.Empty(t, updatedRole.GroupIds)
|
||||
assert.Contains(t, updatedRole.UserIds, user.Id)
|
||||
require.Nil(apiErr, "Got error ", apiErr)
|
||||
assert.Equal(t, updatedRole.Version, r.Version+1)
|
||||
assert.True(t, hasPrincipal(updatedRole, user.Id))
|
||||
|
||||
r = updatedRole
|
||||
updatedRole, apiErr, err = r.RemovePrincipals(ctx, nil, []string{user.Id})
|
||||
updatedRole, apiErr, err = r.RemovePrincipals(ctx, []string{user.Id})
|
||||
require.NoError(err)
|
||||
require.Nil(apiErr, "Got error ", errorMessage(apiErr))
|
||||
assert.Equal(t, *updatedRole.Version, (*r.Version)+1)
|
||||
assert.Empty(t, updatedRole.GroupIds)
|
||||
assert.Empty(t, updatedRole.UserIds)
|
||||
require.Nil(apiErr, "Got error ", apiErr)
|
||||
assert.Equal(t, updatedRole.Version, r.Version+1)
|
||||
assert.Empty(t, updatedRole.Principals)
|
||||
|
||||
r = updatedRole
|
||||
updatedRole, apiErr, err = r.AddGrants(ctx, []string{"id=*;actions=read"})
|
||||
require.NoError(err)
|
||||
require.Nil(apiErr, "Got error ", errorMessage(apiErr))
|
||||
assert.Equal(t, *updatedRole.Version, (*r.Version)+1)
|
||||
require.Nil(apiErr, "Got error ", apiErr)
|
||||
assert.Equal(t, updatedRole.Version, r.Version+1)
|
||||
assert.Contains(t, updatedRole.Grants, "id=*;actions=read")
|
||||
|
||||
r = updatedRole
|
||||
updatedRole, apiErr, err = r.SetGrants(ctx, []string{"id=*;actions=*"})
|
||||
require.NoError(err)
|
||||
require.Nil(apiErr, "Got error ", errorMessage(apiErr))
|
||||
assert.Equal(t, *updatedRole.Version, (*r.Version)+1)
|
||||
require.Nil(apiErr, "Got error ", apiErr)
|
||||
assert.Equal(t, updatedRole.Version, r.Version+1)
|
||||
assert.Contains(t, updatedRole.Grants, "id=*;actions=*")
|
||||
|
||||
r = updatedRole
|
||||
updatedRole, apiErr, err = r.RemoveGrants(ctx, []string{"id=*;actions=*"})
|
||||
require.NoError(err)
|
||||
require.Nil(apiErr, "Got error ", errorMessage(apiErr))
|
||||
assert.Equal(t, *updatedRole.Version, (*r.Version)+1)
|
||||
require.Nil(apiErr, "Got error ", apiErr)
|
||||
assert.Equal(t, updatedRole.Version, r.Version+1)
|
||||
assert.Empty(t, updatedRole.Grants)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func errorMessage(in *api.Error) string {
|
||||
if in == nil {
|
||||
return ""
|
||||
}
|
||||
return *in.Message
|
||||
}
|
||||
|
||||
func TestRole_List(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
tc := controller.NewTestController(t, nil)
|
||||
tc := controller.NewTestController(t, &controller.TestControllerOpts{DisableAuthorizationFailures: true})
|
||||
defer tc.Shutdown()
|
||||
|
||||
client := tc.Client()
|
||||
@@ -153,12 +159,19 @@ func TestRole_List(t *testing.T) {
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
ctx := context.Background()
|
||||
|
||||
pl, apiErr, err := tc.scope.ListRoles(ctx)
|
||||
assert.NoError(err)
|
||||
p1, apiErr, err := tc.scope.ListRoles(ctx)
|
||||
require.NoError(err)
|
||||
assert.Nil(apiErr)
|
||||
assert.Empty(pl)
|
||||
var defaultRoleIds []string
|
||||
if tc.name == "org" {
|
||||
require.True(2 == len(p1))
|
||||
defaultRoleIds = []string{p1[0].Id, p1[1].Id}
|
||||
} else {
|
||||
require.Empty(p1)
|
||||
}
|
||||
|
||||
var expected []*roles.Role
|
||||
for i := 0; i < 10; i++ {
|
||||
@@ -166,21 +179,35 @@ func TestRole_List(t *testing.T) {
|
||||
}
|
||||
|
||||
expected[0], apiErr, err = tc.scope.CreateRole(ctx, expected[0])
|
||||
assert.NoError(err)
|
||||
require.NoError(err)
|
||||
assert.Nil(apiErr)
|
||||
|
||||
pl, apiErr, err = tc.scope.ListRoles(ctx)
|
||||
p2, apiErr, err := tc.scope.ListRoles(ctx)
|
||||
assert.NoError(err)
|
||||
assert.Nil(apiErr)
|
||||
assert.ElementsMatch(comparableSlice(expected[:1]), comparableSlice(pl))
|
||||
var p2ForComparison []*roles.Role
|
||||
for _, v := range p2 {
|
||||
if !strutil.StrListContains(defaultRoleIds, v.Id) {
|
||||
p2ForComparison = append(p2ForComparison, v)
|
||||
}
|
||||
}
|
||||
assert.ElementsMatch(comparableSlice(expected[:1]), comparableSlice(p2ForComparison))
|
||||
|
||||
for i := 1; i < 10; i++ {
|
||||
expected[i], apiErr, err = tc.scope.CreateRole(ctx, expected[i])
|
||||
assert.NoError(err)
|
||||
assert.Nil(apiErr)
|
||||
}
|
||||
pl, apiErr, err = tc.scope.ListRoles(ctx)
|
||||
assert.ElementsMatch(comparableSlice(expected), comparableSlice(pl))
|
||||
p3, apiErr, err := tc.scope.ListRoles(ctx)
|
||||
require.NoError(err)
|
||||
assert.Nil(apiErr)
|
||||
var p3ForComparison []*roles.Role
|
||||
for _, v := range p3 {
|
||||
if !strutil.StrListContains(defaultRoleIds, v.Id) {
|
||||
p3ForComparison = append(p3ForComparison, v)
|
||||
}
|
||||
}
|
||||
assert.ElementsMatch(comparableSlice(expected), comparableSlice(p3ForComparison))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -202,7 +229,7 @@ func comparableSlice(in []*roles.Role) []roles.Role {
|
||||
}
|
||||
|
||||
func TestRole_Crud(t *testing.T) {
|
||||
tc := controller.NewTestController(t, nil)
|
||||
tc := controller.NewTestController(t, &controller.TestControllerOpts{DisableAuthorizationFailures: true})
|
||||
defer tc.Shutdown()
|
||||
|
||||
client := tc.Client()
|
||||
@@ -217,8 +244,8 @@ func TestRole_Crud(t *testing.T) {
|
||||
checkRole := func(step string, g *roles.Role, apiErr *api.Error, err error, wantedName string) {
|
||||
assert := assert.New(t)
|
||||
assert.NoError(err, step)
|
||||
if !assert.Nil(apiErr, step) && apiErr.Message != nil {
|
||||
t.Errorf("ApiError message: %q", *apiErr.Message)
|
||||
if !assert.Nil(apiErr, step) && apiErr.Message != "" {
|
||||
t.Errorf("ApiError message: %q", apiErr.Message)
|
||||
}
|
||||
assert.NotNil(g, "returned no resource", step)
|
||||
gotName := ""
|
||||
@@ -244,6 +271,7 @@ func TestRole_Crud(t *testing.T) {
|
||||
|
||||
for _, tt := range cases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
g, apiErr, err := tt.scope.CreateRole(tc.Context(), &roles.Role{Name: api.String("foo")})
|
||||
checkRole("create", g, apiErr, err, "foo")
|
||||
|
||||
@@ -261,19 +289,20 @@ func TestRole_Crud(t *testing.T) {
|
||||
checkRole("update", g, apiErr, err, "")
|
||||
|
||||
existed, apiErr, err := tt.scope.DeleteRole(tc.Context(), g)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, existed, "Expected existing user when deleted, but it wasn't.")
|
||||
require.NoError(err)
|
||||
assert.Nil(apiErr)
|
||||
assert.True(existed, "Expected existing user when deleted, but it wasn't.")
|
||||
|
||||
existed, apiErr, err = tt.scope.DeleteRole(tc.Context(), g)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, existed, "Expected user to not exist when deleted, but it did.")
|
||||
require.NoError(err)
|
||||
assert.Nil(apiErr)
|
||||
assert.False(existed, "Expected user to not exist when deleted, but it did.")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRole_Errors(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
tc := controller.NewTestController(t, nil)
|
||||
tc := controller.NewTestController(t, &controller.TestControllerOpts{DisableAuthorizationFailures: true})
|
||||
defer tc.Shutdown()
|
||||
ctx := tc.Context()
|
||||
|
||||
@@ -302,30 +331,31 @@ func TestRole_Errors(t *testing.T) {
|
||||
|
||||
for _, tt := range cases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
u, apiErr, err := tt.scope.CreateRole(ctx, &roles.Role{Name: api.String("first")})
|
||||
assert.NoError(err)
|
||||
require.NoError(err)
|
||||
assert.Nil(apiErr)
|
||||
assert.NotNil(u)
|
||||
|
||||
// Create another resource with the same name.
|
||||
_, apiErr, err = tt.scope.CreateRole(ctx, &roles.Role{Name: api.String("first")})
|
||||
assert.NoError(err)
|
||||
require.NoError(err)
|
||||
assert.NotNil(apiErr)
|
||||
|
||||
_, apiErr, err = tt.scope.ReadRole(ctx, &roles.Role{Id: iam.RolePrefix + "_doesntexis"})
|
||||
assert.NoError(err)
|
||||
require.NoError(err)
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(*apiErr.Status, http.StatusNotFound)
|
||||
assert.EqualValues(http.StatusNotFound, apiErr.Status)
|
||||
|
||||
_, apiErr, err = tt.scope.ReadRole(ctx, &roles.Role{Id: "invalid id"})
|
||||
assert.NoError(err)
|
||||
require.NoError(err)
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(*apiErr.Status, http.StatusBadRequest)
|
||||
assert.EqualValues(http.StatusBadRequest, apiErr.Status)
|
||||
|
||||
_, apiErr, err = tt.scope.UpdateRole(ctx, &roles.Role{Id: u.Id})
|
||||
assert.NoError(err)
|
||||
require.NoError(err)
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(*apiErr.Status, http.StatusBadRequest)
|
||||
assert.EqualValues(http.StatusBadRequest, apiErr.Status)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package scopes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/watchtower/api"
|
||||
"github.com/hashicorp/watchtower/api/authtokens"
|
||||
)
|
||||
|
||||
// TODO: This will need to be changed when we add Auth Method API to watchtower. We'll also need a better
|
||||
// way to handle different auth method types.
|
||||
func (s Org) Authenticate(ctx context.Context, authMethodId, name, password string) (*authtokens.AuthToken, *api.Error, error) {
|
||||
if s.Client == nil {
|
||||
return nil, nil, fmt.Errorf("nil client in Authenticate request")
|
||||
}
|
||||
if s.Id == "" {
|
||||
// Assume the client has been configured with org already and
|
||||
// move on
|
||||
} else {
|
||||
// If it's explicitly set here, override anything that might be in the
|
||||
// client
|
||||
ctx = context.WithValue(ctx, "org", s.Id)
|
||||
}
|
||||
|
||||
reqBody := map[string]interface{}{
|
||||
"credentials": map[string]string{
|
||||
"name": name,
|
||||
"password": password,
|
||||
},
|
||||
}
|
||||
|
||||
req, err := s.Client.NewRequest(ctx, "POST", fmt.Sprintf("auth-methods/%s:authenticate", authMethodId), reqBody)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error creating Authenticate request: %w", err)
|
||||
}
|
||||
|
||||
resp, err := s.Client.Do(req)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error performing client request during Authenticate call: %w", err)
|
||||
}
|
||||
|
||||
target := new(authtokens.AuthToken)
|
||||
apiErr, err := resp.Decode(target)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error decoding Authenticate response: %w", err)
|
||||
}
|
||||
|
||||
if target.Token != "" {
|
||||
s.Client.SetToken(target.Token)
|
||||
}
|
||||
|
||||
return target, apiErr, nil
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package scopes_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/watchtower/api/scopes"
|
||||
"github.com/hashicorp/watchtower/internal/servers/controller"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAuthenticate(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
tc := controller.NewTestController(t, nil)
|
||||
defer tc.Shutdown()
|
||||
|
||||
client := tc.Client()
|
||||
org := &scopes.Org{
|
||||
Client: client,
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
tok, apiErr, err := org.Authenticate(ctx, "am_anything", "admin", "hunter2")
|
||||
assert.NoError(err)
|
||||
assert.Nil(apiErr)
|
||||
assert.NotNil(tok)
|
||||
|
||||
_, apiErr, err = org.Authenticate(ctx, "am_anything", "wrong", "wrong")
|
||||
assert.NoError(err)
|
||||
require.NotNil(t, apiErr)
|
||||
assert.EqualValuesf(http.StatusUnauthorized, apiErr.Status, "Expected unauthenticated, got %q", apiErr.Message)
|
||||
}
|
||||
+17
-2
@@ -3,6 +3,7 @@ package scopes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
@@ -32,11 +33,25 @@ type Org struct {
|
||||
}
|
||||
|
||||
func (s *Org) SetDefault(key string) {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"createdtime": "created_time", "description": "description", "id": "id", "name": "name", "updatedtime": "updated_time"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Org) UnsetDefault(key string) {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"createdtime": "created_time", "description": "description", "id": "id", "name": "name", "updatedtime": "updated_time"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s Org) MarshalJSON() ([]byte, error) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package scopes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
@@ -34,11 +35,25 @@ type Project struct {
|
||||
}
|
||||
|
||||
func (s *Project) SetDefault(key string) {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "name": "name", "updatedtime": "updated_time"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Project) UnsetDefault(key string) {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "name": "name", "updatedtime": "updated_time"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s Project) MarshalJSON() ([]byte, error) {
|
||||
|
||||
@@ -133,10 +133,10 @@ func TestProject_Errors(t *testing.T) {
|
||||
assert.NoError(err)
|
||||
// TODO: Should this be nil instead of just a Project that has no values set
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(*apiErr.Status, http.StatusNotFound)
|
||||
assert.EqualValues(apiErr.Status, http.StatusNotFound)
|
||||
|
||||
_, apiErr, err = org.ReadProject(ctx, &scopes.Project{Id: "invalid id"})
|
||||
assert.NoError(err)
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(*apiErr.Status, http.StatusBadRequest)
|
||||
assert.EqualValues(apiErr.Status, http.StatusBadRequest)
|
||||
}
|
||||
+41
-41
@@ -177,47 +177,6 @@ func (s Org) ReadUser(ctx context.Context, r *users.User) (*users.User, *api.Err
|
||||
return target, apiErr, nil
|
||||
}
|
||||
|
||||
func (s Project) ReadHostCatalog(ctx context.Context, r *hosts.HostCatalog) (*hosts.HostCatalog, *api.Error, error) {
|
||||
if s.Client == nil {
|
||||
return nil, nil, fmt.Errorf("nil client in ReadHostCatalog request")
|
||||
}
|
||||
if s.Id == "" {
|
||||
|
||||
// Assume the client has been configured with project already and move
|
||||
// on
|
||||
|
||||
} else {
|
||||
// If it's explicitly set here, override anything that might be in the
|
||||
// client
|
||||
|
||||
ctx = context.WithValue(ctx, "project", s.Id)
|
||||
|
||||
}
|
||||
if r.Id == "" {
|
||||
return nil, nil, fmt.Errorf("empty hosts.HostCatalog ID field in ReadHostCatalog request")
|
||||
}
|
||||
|
||||
req, err := s.Client.NewRequest(ctx, "GET", fmt.Sprintf("%s/%s", "host-catalogs", r.Id), r)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error creating ReadHostCatalog request: %w", err)
|
||||
}
|
||||
|
||||
resp, err := s.Client.Do(req)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error performing client request during ReadHostCatalog call: %w", err)
|
||||
}
|
||||
|
||||
target := new(hosts.HostCatalog)
|
||||
apiErr, err := resp.Decode(target)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error decoding ReadHostCatalog repsonse: %w", err)
|
||||
}
|
||||
|
||||
target.Client = s.Client
|
||||
|
||||
return target, apiErr, nil
|
||||
}
|
||||
|
||||
func (s Project) ReadGroup(ctx context.Context, r *groups.Group) (*groups.Group, *api.Error, error) {
|
||||
if s.Client == nil {
|
||||
return nil, nil, fmt.Errorf("nil client in ReadGroup request")
|
||||
@@ -299,3 +258,44 @@ func (s Project) ReadRole(ctx context.Context, r *roles.Role) (*roles.Role, *api
|
||||
|
||||
return target, apiErr, nil
|
||||
}
|
||||
|
||||
func (s Project) ReadHostCatalog(ctx context.Context, r *hosts.HostCatalog) (*hosts.HostCatalog, *api.Error, error) {
|
||||
if s.Client == nil {
|
||||
return nil, nil, fmt.Errorf("nil client in ReadHostCatalog request")
|
||||
}
|
||||
if s.Id == "" {
|
||||
|
||||
// Assume the client has been configured with project already and move
|
||||
// on
|
||||
|
||||
} else {
|
||||
// If it's explicitly set here, override anything that might be in the
|
||||
// client
|
||||
|
||||
ctx = context.WithValue(ctx, "project", s.Id)
|
||||
|
||||
}
|
||||
if r.Id == "" {
|
||||
return nil, nil, fmt.Errorf("empty hosts.HostCatalog ID field in ReadHostCatalog request")
|
||||
}
|
||||
|
||||
req, err := s.Client.NewRequest(ctx, "GET", fmt.Sprintf("%s/%s", "host-catalogs", r.Id), r)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error creating ReadHostCatalog request: %w", err)
|
||||
}
|
||||
|
||||
resp, err := s.Client.Do(req)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error performing client request during ReadHostCatalog call: %w", err)
|
||||
}
|
||||
|
||||
target := new(hosts.HostCatalog)
|
||||
apiErr, err := resp.Decode(target)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error decoding ReadHostCatalog repsonse: %w", err)
|
||||
}
|
||||
|
||||
target.Client = s.Client
|
||||
|
||||
return target, apiErr, nil
|
||||
}
|
||||
+17
-2
@@ -3,6 +3,7 @@ package users
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
@@ -34,11 +35,25 @@ type User struct {
|
||||
}
|
||||
|
||||
func (s *User) SetDefault(key string) {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "name": "name", "updatedtime": "updated_time"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *User) UnsetDefault(key string) {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, key)
|
||||
lowerKey := strings.ToLower(key)
|
||||
validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "name": "name", "updatedtime": "updated_time"}
|
||||
for k, v := range validMap {
|
||||
if k == lowerKey || v == lowerKey {
|
||||
s.defaultFields = strutil.StrListDelete(s.defaultFields, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s User) MarshalJSON() ([]byte, error) {
|
||||
|
||||
+13
-8
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/hashicorp/watchtower/internal/iam"
|
||||
"github.com/hashicorp/watchtower/internal/servers/controller"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestUsers_List(t *testing.T) {
|
||||
@@ -50,6 +51,8 @@ func TestUsers_List(t *testing.T) {
|
||||
assert.Nil(apiErr)
|
||||
}
|
||||
ul, apiErr, err = org.ListUsers(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Nil(apiErr)
|
||||
assert.ElementsMatch(comparableSlice(expected), comparableSlice(ul))
|
||||
}
|
||||
|
||||
@@ -81,8 +84,8 @@ func TestUser_Crud(t *testing.T) {
|
||||
checkUser := func(step string, u *users.User, apiErr *api.Error, err error, wantedName string) {
|
||||
assert := assert.New(t)
|
||||
assert.NoError(err, step)
|
||||
if !assert.Nil(apiErr, step) && apiErr.Message != nil {
|
||||
t.Errorf("ApiError message: %q", *apiErr.Message)
|
||||
if !assert.Nil(apiErr, step) && apiErr.Message != "" {
|
||||
t.Errorf("ApiError message: %q", apiErr.Message)
|
||||
}
|
||||
assert.NotNil(u, "returned no resource", step)
|
||||
gotName := ""
|
||||
@@ -108,12 +111,14 @@ func TestUser_Crud(t *testing.T) {
|
||||
u, apiErr, err = org.UpdateUser(tc.Context(), u)
|
||||
checkUser("update", u, apiErr, err, "")
|
||||
|
||||
existed, apiErr, err := org.DeleteUser(tc.Context(), u)
|
||||
assert.NoError(t, err)
|
||||
existed, _, err := org.DeleteUser(tc.Context(), u)
|
||||
require.NoError(t, err)
|
||||
assert.Nil(t, apiErr)
|
||||
assert.True(t, existed, "Expected existing user when deleted, but it wasn't.")
|
||||
|
||||
existed, apiErr, err = org.DeleteUser(tc.Context(), u)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.Nil(t, apiErr)
|
||||
assert.False(t, existed, "Expected user to not exist when deleted, but it did.")
|
||||
}
|
||||
|
||||
@@ -141,15 +146,15 @@ func TestUser_Errors(t *testing.T) {
|
||||
_, apiErr, err = org.ReadUser(ctx, &users.User{Id: iam.UserPrefix + "_doesntexis"})
|
||||
assert.NoError(err)
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(*apiErr.Status, http.StatusNotFound)
|
||||
assert.EqualValues(apiErr.Status, http.StatusNotFound)
|
||||
|
||||
_, apiErr, err = org.ReadUser(ctx, &users.User{Id: "invalid id"})
|
||||
assert.NoError(err)
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(*apiErr.Status, http.StatusBadRequest)
|
||||
assert.EqualValues(apiErr.Status, http.StatusBadRequest)
|
||||
|
||||
_, apiErr, err = org.UpdateUser(ctx, &users.User{Id: u.Id})
|
||||
assert.NoError(err)
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(*apiErr.Status, http.StatusBadRequest)
|
||||
assert.EqualValues(apiErr.Status, http.StatusBadRequest)
|
||||
}
|
||||
Reference in new issue
Block a user