Generate new version of SDK resources and Add Tests (#331)

This commit is contained in:
Todd Knight authored and GitHub committed 2020-09-08 16:27:51 -04:00
1 parent 96e4b1cdba
commit c3ecea172d
93 files changed
+3414 -2826

No files matched your search

+27 -25
View File
@@ -27,27 +27,42 @@ type Account struct {
Attributes map[string]interface{} `json:"attributes,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, authMethodId string, opt ...Option) (*Account, *api.Error, error) {
if authMethodId == "" {
return nil, nil, fmt.Errorf("empty authMethodId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("auth-methods/%s/accounts", authMethodId), opts.postMap, apiOpts...)
opts.postMap["auth_method_id"] = authMethodId
req, err := c.client.NewRequest(ctx, "POST", "accounts", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -72,22 +87,17 @@ func (c *Client) Create(ctx context.Context, authMethodId string, opt ...Option)
return target, apiErr, nil
}
func (c *Client) Read(ctx context.Context, authMethodId string, accountId string, opt ...Option) (*Account, *api.Error, error) {
if authMethodId == "" {
return nil, nil, fmt.Errorf("empty authMethodId value passed into Read request")
}
func (c *Client) Read(ctx context.Context, accountId string, opt ...Option) (*Account, *api.Error, error) {
if accountId == "" {
return nil, nil, fmt.Errorf("empty accountId value passed into Read request")
return nil, nil, fmt.Errorf("empty accountId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("auth-methods/%s/accounts/%s", authMethodId, accountId), nil, apiOpts...)
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("accounts/%s", accountId), nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Read request: %w", err)
}
@@ -116,10 +126,7 @@ func (c *Client) Read(ctx context.Context, authMethodId string, accountId string
return target, apiErr, nil
}
func (c *Client) Update(ctx context.Context, authMethodId string, accountId string, version uint32, opt ...Option) (*Account, *api.Error, error) {
if authMethodId == "" {
return nil, nil, fmt.Errorf("empty authMethodId value passed into Update request")
}
func (c *Client) Update(ctx context.Context, accountId string, version uint32, opt ...Option) (*Account, *api.Error, error) {
if accountId == "" {
return nil, nil, fmt.Errorf("empty accountId value passed into Update request")
}
@@ -133,7 +140,7 @@ func (c *Client) Update(ctx context.Context, authMethodId string, accountId stri
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, authMethodId, accountId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, accountId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -148,7 +155,7 @@ func (c *Client) Update(ctx context.Context, authMethodId string, accountId stri
opts.postMap["version"] = version
req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("auth-methods/%s/accounts/%s", authMethodId, accountId), opts.postMap, apiOpts...)
req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("accounts/%s", accountId), opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Update request: %w", err)
}
@@ -177,22 +184,17 @@ func (c *Client) Update(ctx context.Context, authMethodId string, accountId stri
return target, apiErr, nil
}
func (c *Client) Delete(ctx context.Context, authMethodId string, accountId string, opt ...Option) (bool, *api.Error, error) {
if authMethodId == "" {
return false, nil, fmt.Errorf("empty authMethodId value passed into Delete request")
}
func (c *Client) Delete(ctx context.Context, accountId string, opt ...Option) (bool, *api.Error, error) {
if accountId == "" {
return false, nil, fmt.Errorf("empty accountId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("auth-methods/%s/accounts/%s", authMethodId, accountId), nil, apiOpts...)
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("accounts/%s", accountId), nil, apiOpts...)
if err != nil {
return false, nil, fmt.Errorf("error creating Delete request: %w", err)
}
@@ -228,14 +230,14 @@ func (c *Client) List(ctx context.Context, authMethodId string, opt ...Option) (
if authMethodId == "" {
return nil, nil, fmt.Errorf("empty authMethodId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["auth_method_id"] = authMethodId
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("auth-methods/%s/accounts", authMethodId), nil, apiOpts...)
req, err := c.client.NewRequest(ctx, "GET", "accounts", nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating List request: %w", err)
}
+35 -48
View File
@@ -3,6 +3,7 @@ package accounts_test
import (
"fmt"
"net/http"
"os"
"testing"
"github.com/hashicorp/boundary/api"
@@ -15,18 +16,21 @@ import (
"github.com/stretchr/testify/require"
)
func TestAccounts_List(t *testing.T) {
func TestList(t *testing.T) {
os.Setenv("BOUNDARY_LOG_URLS", "1")
os.Setenv("BOUNDARY_DEV_SKIP_AUTHZ", "1")
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
require.NotNil(client)
token := tc.Token()
require.NotNil(token)
client.SetToken(token.Token)
org := iam.TestOrg(t, tc.IamRepo(), iam.WithUserId(token.UserId))
amClient := authmethods.NewClient(client)
am, apiErr, err := amClient.Create(tc.Context(), "password")
am, apiErr, err := amClient.Create(tc.Context(), "password", org.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(am)
@@ -77,21 +81,15 @@ func comparableSlice(in []*accounts.Account) []accounts.Account {
return filtered
}
func TestAccount_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
amId := token.AuthMethodId
accountClient := accounts.NewClient(client)
checkAccount := func(step string, u *accounts.Account, apiErr *api.Error, err error, wantedName string, wantedVersion uint32) {
@@ -111,35 +109,30 @@ func TestAccount_Crud(t *testing.T) {
u, apiErr, err := accountClient.Create(tc.Context(), amId, accounts.WithName("foo"), accounts.WithPasswordAccountLoginName("loginname"))
checkAccount("create", u, apiErr, err, "foo", 1)
u, apiErr, err = accountClient.Read(tc.Context(), amId, u.Id)
u, apiErr, err = accountClient.Read(tc.Context(), u.Id)
checkAccount("read", u, apiErr, err, "foo", 1)
u, apiErr, err = accountClient.Update(tc.Context(), amId, u.Id, u.Version, accounts.WithName("bar"))
u, apiErr, err = accountClient.Update(tc.Context(), u.Id, u.Version, accounts.WithName("bar"))
checkAccount("update", u, apiErr, err, "bar", 2)
u, apiErr, err = accountClient.Update(tc.Context(), amId, u.Id, u.Version, accounts.DefaultName())
u, apiErr, err = accountClient.Update(tc.Context(), u.Id, u.Version, accounts.DefaultName())
checkAccount("update", u, apiErr, err, "", 3)
existed, _, err := accountClient.Delete(tc.Context(), amId, u.Id)
existed, _, err := accountClient.Delete(tc.Context(), u.Id)
require.NoError(err)
assert.Nil(apiErr)
assert.True(existed, "Expected existing account when deleted, but it wasn't.")
}
func TestAccount_CustomMethods(t *testing.T) {
func TestCustomMethods(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
amId := token.AuthMethodId
accountClient := accounts.NewClient(client)
@@ -150,34 +143,28 @@ func TestAccount_CustomMethods(t *testing.T) {
acct := al[0]
setAcct, apiErr, err := accountClient.SetPassword(tc.Context(), amId, acct.Id, "setpassword", acct.Version)
setAcct, apiErr, err := accountClient.SetPassword(tc.Context(), acct.Id, "setpassword", acct.Version)
require.NoError(err)
require.Nil(apiErr)
require.NotNil(setAcct)
assert.Equal(acct.Version+1, setAcct.Version)
changeAcct, apiErr, err := accountClient.ChangePassword(tc.Context(), amId, acct.Id, "setpassword", "changepassword", setAcct.Version)
changeAcct, apiErr, err := accountClient.ChangePassword(tc.Context(), acct.Id, "setpassword", "changepassword", setAcct.Version)
require.NoError(err)
require.Nil(apiErr)
require.NotNil(changeAcct)
assert.Equal(setAcct.Version+1, changeAcct.Version)
}
func TestAccount_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
amId := token.AuthMethodId
accountClient := accounts.NewClient(client)
u, apiErr, err := accountClient.Create(tc.Context(), amId, accounts.WithPasswordAccountLoginName("first"))
@@ -190,17 +177,17 @@ func TestAccount_Errors(t *testing.T) {
require.NoError(err)
assert.NotNil(apiErr)
_, apiErr, err = accountClient.Read(tc.Context(), amId, password.AccountPrefix+"_doesntexis")
_, apiErr, err = accountClient.Read(tc.Context(), password.AccountPrefix+"_doesntexis")
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusForbidden, apiErr.Status)
_, apiErr, err = accountClient.Read(tc.Context(), amId, "invalid id")
_, apiErr, err = accountClient.Read(tc.Context(), "invalid id")
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusBadRequest, apiErr.Status)
_, apiErr, err = accountClient.Update(tc.Context(), amId, u.Id, u.Version)
_, apiErr, err = accountClient.Update(tc.Context(), u.Id, u.Version)
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusBadRequest, apiErr.Status)
+6 -9
View File
@@ -9,10 +9,7 @@ import (
"github.com/kr/pretty"
)
func (c *Client) ChangePassword(ctx context.Context, authMethodId, accountId, oldPassword, newPassword string, version uint32, opt ...Option) (*Account, *api.Error, error) {
if authMethodId == "" {
return nil, nil, fmt.Errorf("empty authMethodId value passed into ChangePassword request")
}
func (c *Client) ChangePassword(ctx context.Context, accountId, currentPassword, newPassword string, version uint32, opt ...Option) (*Account, *api.Error, error) {
if accountId == "" {
return nil, nil, fmt.Errorf("empty accountId value passed into ChangePassword request")
}
@@ -26,7 +23,7 @@ func (c *Client) ChangePassword(ctx context.Context, authMethodId, accountId, ol
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, authMethodId, accountId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, accountId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -40,12 +37,12 @@ func (c *Client) ChangePassword(ctx context.Context, authMethodId, accountId, ol
}
reqBody := map[string]interface{}{
"version": version,
"old_password": oldPassword,
"new_password": newPassword,
"version": version,
"current_password": currentPassword,
"new_password": newPassword,
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("auth-methods/%s/accounts/%s:change-password", authMethodId, accountId), reqBody, apiOpts...)
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("accounts/%s:change-password", accountId), reqBody, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating ChangePassword request: %w", err)
}
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+3 -6
View File
@@ -9,10 +9,7 @@ import (
"github.com/kr/pretty"
)
func (c *Client) SetPassword(ctx context.Context, authMethodId, accountId, password string, version uint32, opt ...Option) (*Account, *api.Error, error) {
if authMethodId == "" {
return nil, nil, fmt.Errorf("empty authMethodId value passed into SetPassword request")
}
func (c *Client) SetPassword(ctx context.Context, accountId, password string, version uint32, opt ...Option) (*Account, *api.Error, error) {
if accountId == "" {
return nil, nil, fmt.Errorf("empty accountId value passed into SetPassword request")
}
@@ -26,7 +23,7 @@ func (c *Client) SetPassword(ctx context.Context, authMethodId, accountId, passw
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, authMethodId, accountId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, accountId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -44,7 +41,7 @@ func (c *Client) SetPassword(ctx context.Context, authMethodId, accountId, passw
"password": password,
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("auth-methods/%s/accounts/%s:set-password", authMethodId, accountId), reqBody, apiOpts...)
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("accounts/%s:set-password", accountId), reqBody, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating SetPassword request: %w", err)
}
+2 -7
View File
@@ -8,9 +8,7 @@ import (
"github.com/hashicorp/boundary/api/authtokens"
)
// TODO: This will need to be changed when we add Auth Method API to boundary. We'll also need a better
// way to handle different auth method types.
func (c *Client) Authenticate(ctx context.Context, authMethodId, loginName, password string, opt ...Option) (*authtokens.AuthToken, *api.Error, error) {
func (c *Client) Authenticate(ctx context.Context, authMethodId string, credentials map[string]interface{}, opt ...Option) (*authtokens.AuthToken, *api.Error, error) {
if c.client == nil {
return nil, nil, fmt.Errorf("nil client in Authenticate request")
}
@@ -18,10 +16,7 @@ func (c *Client) Authenticate(ctx context.Context, authMethodId, loginName, pass
_, apiOpts := getOpts(opt...)
reqBody := map[string]interface{}{
"credentials": map[string]string{
"login_name": loginName,
"password": password,
},
"credentials": credentials,
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("auth-methods/%s:authenticate", authMethodId), reqBody, apiOpts...)
+5 -6
View File
@@ -15,22 +15,21 @@ func TestAuthenticate(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
defer tc.Shutdown()
client := tc.Client()
methods := authmethods.NewClient(client)
tok, apiErr, err := methods.Authenticate(tc.Context(), amId, "user", "passpass")
tok, apiErr, err := methods.Authenticate(tc.Context(), amId, map[string]interface{}{"login_name": "user", "password": "passpass"})
require.NoError(err)
assert.Nil(apiErr, pretty.Sprint(apiErr))
assert.NotNil(tok)
_, apiErr, err = methods.Authenticate(tc.Context(), amId, "user", "wrong")
_, apiErr, err = methods.Authenticate(tc.Context(), amId, map[string]interface{}{"login_name": "user", "password": "wrong"})
require.NoError(err)
require.NotNil(t, apiErr)
assert.EqualValuesf(http.StatusUnauthorized, apiErr.Status, "Expected unauthenticated, got %q", apiErr.Message)
+26 -6
View File
@@ -27,16 +27,31 @@ type AuthMethod struct {
Attributes map[string]interface{} `json:"attributes,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
func (c *Client) Create(ctx context.Context, resourceType string, opt ...Option) (*AuthMethod, *api.Error, error) {
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, resourceType string, scopeId string, opt ...Option) (*AuthMethod, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -46,10 +61,13 @@ func (c *Client) Create(ctx context.Context, resourceType string, opt ...Option)
opts.postMap["type"] = resourceType
}
opts.postMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "POST", "auth-methods", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -76,9 +94,8 @@ func (c *Client) Create(ctx context.Context, resourceType string, opt ...Option)
func (c *Client) Read(ctx context.Context, authMethodId string, opt ...Option) (*AuthMethod, *api.Error, error) {
if authMethodId == "" {
return nil, nil, fmt.Errorf("empty authMethodId value passed into Read request")
return nil, nil, fmt.Errorf("empty authMethodId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -176,7 +193,6 @@ func (c *Client) Delete(ctx context.Context, authMethodId string, opt ...Option)
if authMethodId == "" {
return false, nil, fmt.Errorf("empty authMethodId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -215,12 +231,16 @@ func (c *Client) Delete(ctx context.Context, authMethodId string, opt ...Option)
return target.Existed, apiErr, nil
}
func (c *Client) List(ctx context.Context, opt ...Option) ([]*AuthMethod, *api.Error, error) {
func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*AuthMethod, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "auth-methods", nil, apiOpts...)
if err != nil {
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+44 -26
View File
@@ -8,6 +8,7 @@ import (
"github.com/hashicorp/boundary/api/accounts"
"github.com/hashicorp/boundary/api/authmethods"
"github.com/hashicorp/boundary/api/authtokens"
"github.com/hashicorp/boundary/api/roles"
"github.com/hashicorp/boundary/internal/authtoken"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/servers/controller"
@@ -15,21 +16,41 @@ import (
"github.com/stretchr/testify/require"
)
func TestAuthTokens_List(t *testing.T) {
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
defer tc.Shutdown()
token := tc.Token()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
client.SetToken(token.Token)
org := iam.TestOrg(t, tc.IamRepo(), iam.WithUserId(token.UserId))
amClient := authmethods.NewClient(client)
am, apiErr, err := amClient.Create(tc.Context(), "password")
am, apiErr, err := amClient.Create(tc.Context(), "password", org.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(am)
amId := am.Id
amId = am.Id
rolesClient := roles.NewClient(client)
role, apiErr, err := rolesClient.Create(tc.Context(), org.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(role)
role, apiErr, err = rolesClient.AddPrincipals(tc.Context(), role.Id, 0, []string{"u_anon"}, roles.WithAutomaticVersioning(true))
require.NoError(err)
require.Nil(apiErr)
require.NotNil(role)
role, apiErr, err = rolesClient.AddGrants(tc.Context(), role.Id, 0, []string{"type=auth-method;actions=authenticate"}, roles.WithAutomaticVersioning(true))
require.NoError(err)
require.Nil(apiErr)
require.NotNil(role)
acctClient := accounts.NewClient(client)
acct, apiErr, err := acctClient.Create(tc.Context(), amId, accounts.WithPasswordAccountLoginName("user"), accounts.WithPasswordAccountPassword("passpass"))
@@ -38,32 +59,32 @@ func TestAuthTokens_List(t *testing.T) {
require.NotNil(acct)
tokens := authtokens.NewClient(client)
methods := authmethods.NewClient(client)
atl, apiErr, err := tokens.List(tc.Context())
atl, apiErr, err := tokens.List(tc.Context(), org.GetPublicId())
require.NoError(err)
assert.Nil(apiErr)
assert.Empty(atl)
var expected []*authtokens.AuthToken
methods := authmethods.NewClient(client)
at, apiErr, err := methods.Authenticate(tc.Context(), amId, "user", "passpass")
at, apiErr, err := methods.Authenticate(tc.Context(), amId, map[string]interface{}{"login_name": "user", "password": "passpass"})
require.NoError(err)
assert.Nil(apiErr)
expected = append(expected, at)
atl, apiErr, err = tokens.List(tc.Context())
atl, apiErr, err = tokens.List(tc.Context(), org.GetPublicId())
require.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableSlice(expected), comparableSlice(atl))
for i := 1; i < 10; i++ {
at, apiErr, err = methods.Authenticate(tc.Context(), amId, "user", "passpass")
at, apiErr, err = methods.Authenticate(tc.Context(), amId, map[string]interface{}{"login_name": "user", "password": "passpass"})
require.NoError(err)
assert.Nil(apiErr)
expected = append(expected, at)
}
atl, apiErr, err = tokens.List(tc.Context())
atl, apiErr, err = tokens.List(tc.Context(), org.GetPublicId())
require.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableSlice(expected), comparableSlice(atl))
@@ -92,22 +113,23 @@ func comparableSlice(in []*authtokens.AuthToken) []authtokens.AuthToken {
return filtered
}
func TestAuthToken_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
defer tc.Shutdown()
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
tokens := authtokens.NewClient(client)
methods := authmethods.NewClient(client)
want, apiErr, err := methods.Authenticate(tc.Context(), amId, "user", "passpass")
want, apiErr, err := methods.Authenticate(tc.Context(), amId, map[string]interface{}{"login_name": "user", "password": "passpass"})
require.NoError(err)
assert.Empty(apiErr)
@@ -122,18 +144,14 @@ func TestAuthToken_Crud(t *testing.T) {
assert.True(existed, "Expected existing token when deleted, but it wasn't.")
}
func TestAuthToken_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
tokens := authtokens.NewClient(client)
_, apiErr, err := tokens.Read(tc.Context(), authtoken.AuthTokenPrefix+"_doesntexis")
+17 -5
View File
@@ -24,19 +24,28 @@ type AuthToken struct {
ExpirationTime time.Time `json:"expiration_time,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Read(ctx context.Context, authTokenId string, opt ...Option) (*AuthToken, *api.Error, error) {
if authTokenId == "" {
return nil, nil, fmt.Errorf("empty authTokenId value passed into Read request")
return nil, nil, fmt.Errorf("empty authTokenId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -76,7 +85,6 @@ func (c *Client) Delete(ctx context.Context, authTokenId string, opt ...Option)
if authTokenId == "" {
return false, nil, fmt.Errorf("empty authTokenId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -115,12 +123,16 @@ func (c *Client) Delete(ctx context.Context, authTokenId string, opt ...Option)
return target.Existed, apiErr, nil
}
func (c *Client) List(ctx context.Context, opt ...Option) ([]*AuthToken, *api.Error, error) {
func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*AuthToken, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "auth-tokens", nil, apiOpts...)
if err != nil {
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,24 +32,15 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+8 -69
View File
@@ -38,7 +38,6 @@ const EnvBoundaryMaxRetries = "BOUNDARY_MAX_RETRIES"
const EnvBoundaryToken = "BOUNDARY_TOKEN"
const EnvBoundaryRateLimit = "BOUNDARY_RATE_LIMIT"
const EnvBoundarySRVLookup = "BOUNDARY_SRV_LOOKUP"
const EnvBoundaryScopeId = "BOUNDARY_SCOPE_ID"
// Config is used to configure the creation of the client
type Config struct {
@@ -97,9 +96,6 @@ type Config struct {
// SRVLookup enables the client to lookup the host through DNS SRV lookup
SRVLookup bool
// ScopeId is the ID of the scope to use if not overridden per-call
ScopeId string
}
// TLSConfig contains the parameters needed to configure TLS on the HTTP client
@@ -140,7 +136,6 @@ func DefaultConfig() (*Config, error) {
HttpClient: cleanhttp.DefaultPooledClient(),
Timeout: time.Second * 60,
TLSConfig: &TLSConfig{},
ScopeId: "global",
}
// We read the environment now; after DefaultClient returns we can override
@@ -215,10 +210,9 @@ func (c *Config) ConfigureTLS() error {
return nil
}
// setAddr parses a given string and looks for scope 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, 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.
@@ -229,11 +223,12 @@ func (c *Config) setAddr(addr string) error {
}
c.Addr = fmt.Sprintf("%s://%s", u.Scheme, u.Host)
// If there is a scopes segment, elide everything after it. Do this only for
// the last "scopes" segment in case it's part of the base path.
if lastIndex := strings.LastIndex(u.Path, "scopes"); lastIndex != -1 {
// If there is a v1 segment, elide everything after it. Do this only for
// the last v1 segment in case it's part of the base path.
if lastIndex := strings.LastIndex(u.Path, "v1"); lastIndex != -1 {
u.Path = u.Path[:lastIndex]
}
// Remove trailing or leading slashes
path := strings.Trim(u.Path, "/")
// Remove v1 in front or back (e.g. they could have
@@ -270,10 +265,6 @@ func (c *Config) ReadEnvironment() error {
c.Token = v
}
if v := os.Getenv(EnvBoundaryScopeId); v != "" {
c.ScopeId = v
}
if v := os.Getenv(EnvBoundaryMaxRetries); v != "" {
maxRetries, err := strconv.ParseUint(v, 10, 32)
if err != nil {
@@ -439,23 +430,6 @@ func (c *Client) SetAddr(addr string) error {
return c.config.setAddr(addr)
}
// ScopeId fetches the scope ID the client will use by default
func (c *Client) ScopeId() string {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
return c.config.ScopeId
}
// Sets the scope ID to use when making calls. This will apply to all calls with
// this client unless overridden per request via WithScopeId.
func (c *Client) SetScopeId(scopeId string) {
c.modifyLock.Lock()
defer c.modifyLock.Unlock()
c.config.ScopeId = scopeId
}
// SetTLSConfig sets the TLS parameters to use and calls ConfigureTLS
func (c *Client) SetTLSConfig(conf *TLSConfig) error {
c.modifyLock.Lock()
@@ -564,7 +538,6 @@ func (c *Client) Clone() *Client {
CheckRetry: config.CheckRetry,
Limiter: config.Limiter,
SRVLookup: config.SRVLookup,
ScopeId: config.ScopeId,
}
if config.TLSConfig != nil {
newConfig.TLSConfig = new(TLSConfig)
@@ -632,7 +605,6 @@ func (c *Client) NewRequest(ctx context.Context, method, requestPath string, bod
c.modifyLock.RLock()
addr := c.config.Addr
scopeId := c.config.ScopeId
srvLookup := c.config.SRVLookup
token := c.config.Token
httpClient := c.config.HttpClient
@@ -677,46 +649,13 @@ func (c *Client) NewRequest(ctx context.Context, method, requestPath string, bod
}
}
opts := getOpts(opt...)
if opts.withScopeId != "" {
scopeId = opts.withScopeId
}
if scopeId == "" {
scopeId = "global"
}
var finalPath string
switch opts.withNewStyle {
case true:
// Do nothing. Eventually, remove the notion of a scoped client; calls
// to specific resources won't need it, and calls to collections can
// take care of it in the functions themselves as part of the api
// parameters.
finalPath = path.Join(u.Path, "/v1/", requestPath)
default:
scopedPath := strings.TrimPrefix(requestPath, "/")
switch requestPath {
case "scopes":
// This is a special case for creating or listing scopes; don't do
// anything
default:
// If their path already has 'scopes/' in it, use the given request path
// instead of building it from the client's scope information
if !strings.HasPrefix(scopedPath, "scopes/") {
scopedPath = path.Join("scopes", scopeId, scopedPath)
}
}
finalPath = path.Join(u.Path, "/v1", scopedPath)
}
req := &http.Request{
Method: method,
URL: &url.URL{
User: u.User,
Scheme: u.Scheme,
Host: host,
Path: finalPath,
Path: path.Join(u.Path, "/v1/", requestPath),
},
Host: u.Host,
}
+1 -1
View File
@@ -47,7 +47,7 @@ func TestConfigSetAddress(t *testing.T) {
},
{
"longer path project",
"http://127.0.0.1:9200/v1/scopes/orgid/auth-methods",
"http://127.0.0.1:9200/v1/auth-methods",
"http://127.0.0.1:9200",
"",
},
+26 -6
View File
@@ -27,24 +27,42 @@ type Group struct {
Members []*Member `json:"members,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
func (c *Client) Create(ctx context.Context, opt ...Option) (*Group, *api.Error, error) {
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Group, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts.postMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "POST", "groups", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -71,9 +89,8 @@ func (c *Client) Create(ctx context.Context, opt ...Option) (*Group, *api.Error,
func (c *Client) Read(ctx context.Context, groupId string, opt ...Option) (*Group, *api.Error, error) {
if groupId == "" {
return nil, nil, fmt.Errorf("empty groupId value passed into Read request")
return nil, nil, fmt.Errorf("empty groupId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -171,7 +188,6 @@ func (c *Client) Delete(ctx context.Context, groupId string, opt ...Option) (boo
if groupId == "" {
return false, nil, fmt.Errorf("empty groupId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -210,12 +226,16 @@ func (c *Client) Delete(ctx context.Context, groupId string, opt ...Option) (boo
return target.Existed, apiErr, nil
}
func (c *Client) List(ctx context.Context, opt ...Option) ([]*Group, *api.Error, error) {
func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Group, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "groups", nil, apiOpts...)
if err != nil {
+44 -65
View File
@@ -14,52 +14,45 @@ import (
"github.com/stretchr/testify/require"
)
func TestGroup_List(t *testing.T) {
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
cases := []struct {
name string
scopeClient *api.Client
name string
scopeId string
}{
{
name: "org",
scopeClient: client,
name: "org",
scopeId: org.GetPublicId(),
},
{
name: "proj",
scopeClient: projClient,
name: "proj",
scopeId: proj.GetPublicId(),
},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
grps := groups.NewClient(tt.scopeClient)
pl, apiErr, err := grps.List(tc.Context())
grps := groups.NewClient(client)
pl, apiErr, err := grps.List(tc.Context(), tt.scopeId)
assert.NoError(err)
assert.Nil(apiErr)
assert.Empty(pl)
expected := make([]*groups.Group, 10)
for i := 0; i < 10; i++ {
expected[i], apiErr, err = grps.Create(tc.Context(), groups.WithName(fmt.Sprint(i)))
expected[i], apiErr, err = grps.Create(tc.Context(), tt.scopeId, groups.WithName(fmt.Sprint(i)))
require.NoError(err)
assert.Nil(apiErr)
}
pl, apiErr, err = grps.List(tc.Context())
pl, apiErr, err = grps.List(tc.Context(), tt.scopeId)
require.NoError(err)
assert.Nil(apiErr)
require.NotNil(pl)
@@ -84,22 +77,15 @@ func comparableSlice(in []*groups.Group) []groups.Group {
return filtered
}
func TestGroup_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
checkGroup := func(step string, g *groups.Group, apiErr *api.Error, err error, wantedName string, wantedVersion uint32, expectedUserIds []string) {
require.NoError(err, step)
@@ -120,31 +106,31 @@ func TestGroup_Crud(t *testing.T) {
}
cases := []struct {
name string
scopeClient *api.Client
name string
scopeId string
}{
{
name: "org",
scopeClient: client,
name: "org",
scopeId: org.GetPublicId(),
},
{
name: "proj",
scopeClient: projClient,
name: "proj",
scopeId: proj.GetPublicId(),
},
}
user1, apiErr, err := users.NewClient(client).Create(tc.Context())
user1, apiErr, err := users.NewClient(client).Create(tc.Context(), org.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
user2, apiErr, err := users.NewClient(client).Create(tc.Context())
user2, apiErr, err := users.NewClient(client).Create(tc.Context(), org.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
groupsClient := groups.NewClient(tt.scopeClient)
g, apiErr, err := groupsClient.Create(tc.Context(), groups.WithName("foo"))
groupsClient := groups.NewClient(client)
g, apiErr, err := groupsClient.Create(tc.Context(), tt.scopeId, groups.WithName("foo"))
checkGroup("create", g, apiErr, err, "foo", 1, nil)
g, apiErr, err = groupsClient.Read(tc.Context(), g.Id)
@@ -177,48 +163,41 @@ func TestGroup_Crud(t *testing.T) {
}
}
func TestGroup_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
cases := []struct {
name string
scopeClient *api.Client
name string
scopeId string
}{
{
name: "org",
scopeClient: client,
name: "org",
scopeId: org.GetPublicId(),
},
{
name: "proj",
scopeClient: projClient,
name: "proj",
scopeId: proj.GetPublicId(),
},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
groupClient := groups.NewClient(tt.scopeClient)
groupClient := groups.NewClient(client)
g, apiErr, err := groupClient.Create(tc.Context(), groups.WithName("first"))
g, apiErr, err := groupClient.Create(tc.Context(), tt.scopeId, groups.WithName("first"))
require.NoError(err)
assert.Nil(apiErr)
assert.NotNil(g)
// Create another resource with the same name.
_, apiErr, err = groupClient.Create(tc.Context(), groups.WithName("first"))
_, apiErr, err = groupClient.Create(tc.Context(), tt.scopeId, groups.WithName("first"))
require.NoError(err)
assert.NotNil(apiErr)
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+26 -6
View File
@@ -27,16 +27,31 @@ type HostCatalog struct {
Attributes map[string]interface{} `json:"attributes,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
func (c *Client) Create(ctx context.Context, resourceType string, opt ...Option) (*HostCatalog, *api.Error, error) {
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, resourceType string, scopeId string, opt ...Option) (*HostCatalog, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -46,10 +61,13 @@ func (c *Client) Create(ctx context.Context, resourceType string, opt ...Option)
opts.postMap["type"] = resourceType
}
opts.postMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "POST", "host-catalogs", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -76,9 +94,8 @@ func (c *Client) Create(ctx context.Context, resourceType string, opt ...Option)
func (c *Client) Read(ctx context.Context, hostCatalogId string, opt ...Option) (*HostCatalog, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Read request")
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -176,7 +193,6 @@ func (c *Client) Delete(ctx context.Context, hostCatalogId string, opt ...Option
if hostCatalogId == "" {
return false, nil, fmt.Errorf("empty hostCatalogId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -215,12 +231,16 @@ func (c *Client) Delete(ctx context.Context, hostCatalogId string, opt ...Option
return target.Existed, apiErr, nil
}
func (c *Client) List(ctx context.Context, opt ...Option) ([]*HostCatalog, *api.Error, error) {
func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*HostCatalog, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "host-catalogs", nil, apiOpts...)
if err != nil {
+24 -41
View File
@@ -14,23 +14,18 @@ import (
"github.com/stretchr/testify/require"
)
func TestCatalog_List(t *testing.T) {
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
_, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
catalogClient := hostcatalogs.NewClient(client)
ul, apiErr, err := catalogClient.List(tc.Context())
ul, apiErr, err := catalogClient.List(tc.Context(), proj.GetPublicId())
assert.NoError(err)
assert.Nil(apiErr)
assert.Empty(ul)
@@ -40,21 +35,21 @@ func TestCatalog_List(t *testing.T) {
expected = append(expected, &hostcatalogs.HostCatalog{Name: fmt.Sprint(i)})
}
expected[0], apiErr, err = catalogClient.Create(tc.Context(), "static", hostcatalogs.WithName(expected[0].Name))
expected[0], apiErr, err = catalogClient.Create(tc.Context(), "static", proj.GetPublicId(), hostcatalogs.WithName(expected[0].Name))
assert.NoError(err)
assert.Nil(apiErr)
ul, apiErr, err = catalogClient.List(tc.Context())
ul, apiErr, err = catalogClient.List(tc.Context(), proj.GetPublicId())
assert.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableCatalogSlice(expected[:1]), comparableCatalogSlice(ul))
for i := 1; i < 10; i++ {
expected[i], apiErr, err = catalogClient.Create(tc.Context(), "static", hostcatalogs.WithName(expected[i].Name))
expected[i], apiErr, err = catalogClient.Create(tc.Context(), "static", proj.GetPublicId(), hostcatalogs.WithName(expected[i].Name))
assert.NoError(err)
assert.Nil(apiErr)
}
ul, apiErr, err = catalogClient.List(tc.Context())
ul, apiErr, err = catalogClient.List(tc.Context(), proj.GetPublicId())
require.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableCatalogSlice(expected), comparableCatalogSlice(ul))
@@ -75,22 +70,15 @@ func comparableCatalogSlice(in []*hostcatalogs.HostCatalog) []hostcatalogs.HostC
return filtered
}
func TestCatalogs_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
checkCatalog := func(step string, hc *hostcatalogs.HostCatalog, apiErr *api.Error, err error, wantedName string, wantVersion uint32) {
require.NoError(err, step)
@@ -106,9 +94,9 @@ func TestCatalogs_Crud(t *testing.T) {
assert.Equal(wantVersion, hc.Version)
}
hcClient := hostcatalogs.NewClient(projClient)
hcClient := hostcatalogs.NewClient(client)
hc, apiErr, err := hcClient.Create(tc.Context(), "static", hostcatalogs.WithName("foo"))
hc, apiErr, err := hcClient.Create(tc.Context(), "static", proj.GetPublicId(), hostcatalogs.WithName("foo"))
checkCatalog("create", hc, apiErr, err, "foo", 1)
hc, apiErr, err = hcClient.Read(tc.Context(), hc.Id)
@@ -131,28 +119,23 @@ func TestCatalogs_Crud(t *testing.T) {
}
// TODO: Get better coverage for expected errors and error formats.
func TestCatalogs_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
_, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
pc := hostcatalogs.NewClient(client)
hc, apiErr, err := pc.Create(tc.Context(), "static", hostcatalogs.WithName("foo"))
hc, apiErr, err := pc.Create(tc.Context(), "static", proj.GetPublicId(), hostcatalogs.WithName("foo"))
require.NoError(err)
assert.Nil(apiErr)
assert.NotNil(hc)
_, apiErr, err = pc.Create(tc.Context(), "static", hostcatalogs.WithName("foo"))
_, apiErr, err = pc.Create(tc.Context(), "static", proj.GetPublicId(), hostcatalogs.WithName("foo"))
require.NoError(err)
assert.NotNil(apiErr)
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+27 -25
View File
@@ -28,27 +28,42 @@ type Host struct {
Attributes map[string]interface{} `json:"attributes,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, hostCatalogId string, opt ...Option) (*Host, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("host-catalogs/%s/hosts", hostCatalogId), opts.postMap, apiOpts...)
opts.postMap["host_catalog_id"] = hostCatalogId
req, err := c.client.NewRequest(ctx, "POST", "hosts", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -73,22 +88,17 @@ func (c *Client) Create(ctx context.Context, hostCatalogId string, opt ...Option
return target, apiErr, nil
}
func (c *Client) Read(ctx context.Context, hostCatalogId string, hostId string, opt ...Option) (*Host, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Read request")
}
func (c *Client) Read(ctx context.Context, hostId string, opt ...Option) (*Host, *api.Error, error) {
if hostId == "" {
return nil, nil, fmt.Errorf("empty hostId value passed into Read request")
return nil, nil, fmt.Errorf("empty hostId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("host-catalogs/%s/hosts/%s", hostCatalogId, hostId), nil, apiOpts...)
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("hosts/%s", hostId), nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Read request: %w", err)
}
@@ -117,10 +127,7 @@ func (c *Client) Read(ctx context.Context, hostCatalogId string, hostId string,
return target, apiErr, nil
}
func (c *Client) Update(ctx context.Context, hostCatalogId string, hostId string, version uint32, opt ...Option) (*Host, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Update request")
}
func (c *Client) Update(ctx context.Context, hostId string, version uint32, opt ...Option) (*Host, *api.Error, error) {
if hostId == "" {
return nil, nil, fmt.Errorf("empty hostId value passed into Update request")
}
@@ -134,7 +141,7 @@ func (c *Client) Update(ctx context.Context, hostCatalogId string, hostId string
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostCatalogId, hostId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -149,7 +156,7 @@ func (c *Client) Update(ctx context.Context, hostCatalogId string, hostId string
opts.postMap["version"] = version
req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("host-catalogs/%s/hosts/%s", hostCatalogId, hostId), opts.postMap, apiOpts...)
req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("hosts/%s", hostId), opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Update request: %w", err)
}
@@ -178,22 +185,17 @@ func (c *Client) Update(ctx context.Context, hostCatalogId string, hostId string
return target, apiErr, nil
}
func (c *Client) Delete(ctx context.Context, hostCatalogId string, hostId string, opt ...Option) (bool, *api.Error, error) {
if hostCatalogId == "" {
return false, nil, fmt.Errorf("empty hostCatalogId value passed into Delete request")
}
func (c *Client) Delete(ctx context.Context, hostId string, opt ...Option) (bool, *api.Error, error) {
if hostId == "" {
return false, nil, fmt.Errorf("empty hostId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("host-catalogs/%s/hosts/%s", hostCatalogId, hostId), nil, apiOpts...)
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("hosts/%s", hostId), nil, apiOpts...)
if err != nil {
return false, nil, fmt.Errorf("error creating Delete request: %w", err)
}
@@ -229,14 +231,14 @@ func (c *Client) List(ctx context.Context, hostCatalogId string, opt ...Option)
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["host_catalog_id"] = hostCatalogId
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("host-catalogs/%s/hosts", hostCatalogId), nil, apiOpts...)
req, err := c.client.NewRequest(ctx, "GET", "hosts", nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating List request: %w", err)
}
+26 -43
View File
@@ -15,22 +15,17 @@ import (
"github.com/stretchr/testify/require"
)
func TestHost_List(t *testing.T) {
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
_, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static")
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
@@ -82,24 +77,17 @@ func comparableHostSlice(in []*hosts.Host) []hosts.Host {
return filtered
}
func TestHost_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
hc, apiErr, err := hostcatalogs.NewClient(projClient).Create(tc.Context(), "static")
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
@@ -118,47 +106,42 @@ func TestHost_Crud(t *testing.T) {
assert.Equal(wantVersion, h.Version)
}
hClient := hosts.NewClient(projClient)
hClient := hosts.NewClient(client)
h, apiErr, err := hClient.Create(tc.Context(), hc.Id, hosts.WithName("foo"), hosts.WithStaticHostAddress("someaddress"))
checkHost("create", h, apiErr, err, "foo", 1)
h, apiErr, err = hClient.Read(tc.Context(), hc.Id, h.Id)
h, apiErr, err = hClient.Read(tc.Context(), h.Id)
checkHost("read", h, apiErr, err, "foo", 1)
h, apiErr, err = hClient.Update(tc.Context(), hc.Id, h.Id, h.Version, hosts.WithName("bar"))
h, apiErr, err = hClient.Update(tc.Context(), h.Id, h.Version, hosts.WithName("bar"))
checkHost("update", h, apiErr, err, "bar", 2)
h, apiErr, err = hClient.Update(tc.Context(), hc.Id, h.Id, h.Version, hosts.DefaultName())
h, apiErr, err = hClient.Update(tc.Context(), h.Id, h.Version, hosts.DefaultName())
checkHost("update", h, apiErr, err, "", 3)
existed, apiErr, err := hClient.Delete(tc.Context(), hc.Id, h.Id)
existed, apiErr, err := hClient.Delete(tc.Context(), h.Id)
assert.NoError(err)
assert.True(existed, "Expected existing catalog when deleted, but it wasn't.")
existed, apiErr, err = hClient.Delete(tc.Context(), hc.Id, h.Id)
existed, apiErr, err = hClient.Delete(tc.Context(), h.Id)
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusForbidden, apiErr.Status)
}
// TODO: Get better coverage for expected errors and error formats.
func TestHost_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
_, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static")
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
@@ -174,12 +157,12 @@ func TestHost_Errors(t *testing.T) {
require.NoError(err)
assert.NotNil(apiErr)
_, apiErr, err = hClient.Read(tc.Context(), hc.Id, static.HostPrefix+"_doesntexis")
_, apiErr, err = hClient.Read(tc.Context(), static.HostPrefix+"_doesntexis")
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(apiErr.Status, http.StatusForbidden)
_, apiErr, err = hClient.Read(tc.Context(), hc.Id, "invalid id")
_, apiErr, err = hClient.Read(tc.Context(), "invalid id")
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusBadRequest, apiErr.Status)
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+22 -448
View File
@@ -28,252 +28,31 @@ type HostSet struct {
Attributes map[string]interface{} `json:"attributes,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, hostCatalogId string, opt ...Option) (*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("host-catalogs/%s/host-sets", hostCatalogId), opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err)
}
target := new(HostSet)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding Create response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
func (c *Client) Read(ctx context.Context, hostCatalogId string, hostSetId string, opt ...Option) (*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Read request")
}
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("host-catalogs/%s/host-sets/%s", hostCatalogId, hostSetId), nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Read request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err)
}
target := new(HostSet)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding Read response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
func (c *Client) Update(ctx context.Context, hostCatalogId string, hostSetId string, version uint32, opt ...Option) (*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Update request")
}
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into Update request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostCatalogId, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
if existingApiErr != nil {
return nil, nil, fmt.Errorf("error from controller when performing initial check-and-set read: %s", pretty.Sprint(existingApiErr))
}
if existingTarget == nil {
return nil, nil, errors.New("nil resource found when performing initial check-and-set read")
}
version = existingTarget.Version
}
opts.postMap["version"] = version
req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("host-catalogs/%s/host-sets/%s", hostCatalogId, hostSetId), opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Update request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err)
}
target := new(HostSet)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding Update response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
func (c *Client) Delete(ctx context.Context, hostCatalogId string, hostSetId string, opt ...Option) (bool, *api.Error, error) {
if hostCatalogId == "" {
return false, nil, fmt.Errorf("empty hostCatalogId value passed into Delete request")
}
if hostSetId == "" {
return false, nil, fmt.Errorf("empty hostSetId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("host-catalogs/%s/host-sets/%s", hostCatalogId, hostSetId), nil, apiOpts...)
if err != nil {
return false, nil, fmt.Errorf("error creating Delete request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err)
}
type deleteResponse struct {
Existed bool
}
target := &deleteResponse{}
apiErr, err := resp.Decode(target)
if err != nil {
return false, nil, fmt.Errorf("error decoding Delete response: %w", err)
}
if apiErr != nil {
return false, apiErr, nil
}
return target.Existed, apiErr, nil
}
func (c *Client) List(ctx context.Context, hostCatalogId string, opt ...Option) ([]*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("host-catalogs/%s/host-sets", hostCatalogId), nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating List request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during List call: %w", err)
}
type listResponse struct {
Items []*HostSet
}
target := &listResponse{}
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding List response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target.Items, apiErr, nil
}
func (c *Client) Create2(ctx context.Context, hostCatalogId string, opt ...Option) (*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -309,7 +88,7 @@ func (c *Client) Create2(ctx context.Context, hostCatalogId string, opt ...Optio
return target, apiErr, nil
}
func (c *Client) Read2(ctx context.Context, hostSetId string, opt ...Option) (*HostSet, *api.Error, error) {
func (c *Client) Read(ctx context.Context, hostSetId string, opt ...Option) (*HostSet, *api.Error, error) {
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into Read request")
}
@@ -318,7 +97,6 @@ func (c *Client) Read2(ctx context.Context, hostSetId string, opt ...Option) (*H
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("host-sets/%s", hostSetId), nil, apiOpts...)
if err != nil {
@@ -349,7 +127,7 @@ func (c *Client) Read2(ctx context.Context, hostSetId string, opt ...Option) (*H
return target, apiErr, nil
}
func (c *Client) Update2(ctx context.Context, hostSetId string, version uint32, opt ...Option) (*HostSet, *api.Error, error) {
func (c *Client) Update(ctx context.Context, hostSetId string, version uint32, opt ...Option) (*HostSet, *api.Error, error) {
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into Update request")
}
@@ -358,13 +136,12 @@ func (c *Client) Update2(ctx context.Context, hostSetId string, version uint32,
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read2(ctx, hostSetId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -408,7 +185,7 @@ func (c *Client) Update2(ctx context.Context, hostSetId string, version uint32,
return target, apiErr, nil
}
func (c *Client) Delete2(ctx context.Context, hostSetId string, opt ...Option) (bool, *api.Error, error) {
func (c *Client) Delete(ctx context.Context, hostSetId string, opt ...Option) (bool, *api.Error, error) {
if hostSetId == "" {
return false, nil, fmt.Errorf("empty hostSetId value passed into Delete request")
}
@@ -417,7 +194,6 @@ func (c *Client) Delete2(ctx context.Context, hostSetId string, opt ...Option) (
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("host-sets/%s", hostSetId), nil, apiOpts...)
if err != nil {
@@ -451,7 +227,7 @@ func (c *Client) Delete2(ctx context.Context, hostSetId string, opt ...Option) (
return target.Existed, apiErr, nil
}
func (c *Client) List2(ctx context.Context, hostCatalogId string, opt ...Option) ([]*HostSet, *api.Error, error) {
func (c *Client) List(ctx context.Context, hostCatalogId string, opt ...Option) ([]*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into List request")
}
@@ -460,7 +236,6 @@ func (c *Client) List2(ctx context.Context, hostCatalogId string, opt ...Option)
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
opts.queryMap["host_catalog_id"] = hostCatalogId
req, err := c.client.NewRequest(ctx, "GET", "host-sets", nil, apiOpts...)
@@ -495,10 +270,7 @@ func (c *Client) List2(ctx context.Context, hostCatalogId string, opt ...Option)
return target.Items, apiErr, nil
}
func (c *Client) AddHosts(ctx context.Context, hostCatalogId string, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into AddHosts request")
}
func (c *Client) AddHosts(ctx context.Context, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into AddHosts request")
}
@@ -512,203 +284,7 @@ func (c *Client) AddHosts(ctx context.Context, hostCatalogId string, hostSetId s
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into AddHosts request")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostCatalogId, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
if existingApiErr != nil {
return nil, nil, fmt.Errorf("error from controller when performing initial check-and-set read: %s", pretty.Sprint(existingApiErr))
}
if existingTarget == nil {
return nil, nil, errors.New("nil resource found when performing initial check-and-set read")
}
version = existingTarget.Version
}
opts.postMap["version"] = version
if len(hostIds) > 0 {
opts.postMap["host_ids"] = hostIds
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("host-catalogs/%s/host-sets/%s:add-hosts", hostCatalogId, hostSetId), opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating AddHosts request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during AddHosts call: %w", err)
}
target := new(HostSet)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding AddHosts response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
func (c *Client) SetHosts(ctx context.Context, hostCatalogId string, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into SetHosts request")
}
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into SetHosts request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into SetHosts request")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostCatalogId, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
if existingApiErr != nil {
return nil, nil, fmt.Errorf("error from controller when performing initial check-and-set read: %s", pretty.Sprint(existingApiErr))
}
if existingTarget == nil {
return nil, nil, errors.New("nil resource found when performing initial check-and-set read")
}
version = existingTarget.Version
}
opts.postMap["version"] = version
if len(hostIds) > 0 {
opts.postMap["host_ids"] = hostIds
} else if hostIds != nil {
// In this function, a non-nil but empty list means clear out
opts.postMap["host_ids"] = nil
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("host-catalogs/%s/host-sets/%s:set-hosts", hostCatalogId, hostSetId), opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating SetHosts request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during SetHosts call: %w", err)
}
target := new(HostSet)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding SetHosts response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
func (c *Client) RemoveHosts(ctx context.Context, hostCatalogId string, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
if hostCatalogId == "" {
return nil, nil, fmt.Errorf("empty hostCatalogId value passed into RemoveHosts request")
}
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into RemoveHosts request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into RemoveHosts request")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostCatalogId, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
if existingApiErr != nil {
return nil, nil, fmt.Errorf("error from controller when performing initial check-and-set read: %s", pretty.Sprint(existingApiErr))
}
if existingTarget == nil {
return nil, nil, errors.New("nil resource found when performing initial check-and-set read")
}
version = existingTarget.Version
}
opts.postMap["version"] = version
if len(hostIds) > 0 {
opts.postMap["host_ids"] = hostIds
}
req, err := c.client.NewRequest(ctx, "POST", fmt.Sprintf("host-catalogs/%s/host-sets/%s:remove-hosts", hostCatalogId, hostSetId), opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating RemoveHosts request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during RemoveHosts call: %w", err)
}
target := new(HostSet)
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding RemoveHosts response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
func (c *Client) AddHosts2(ctx context.Context, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into AddHosts request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into AddHosts request")
}
existingTarget, existingApiErr, existingErr := c.Read2(ctx, hostSetId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -756,7 +332,7 @@ func (c *Client) AddHosts2(ctx context.Context, hostSetId string, version uint32
return target, apiErr, nil
}
func (c *Client) SetHosts2(ctx context.Context, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
func (c *Client) SetHosts(ctx context.Context, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into SetHosts request")
}
@@ -765,13 +341,12 @@ func (c *Client) SetHosts2(ctx context.Context, hostSetId string, version uint32
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into SetHosts request")
}
existingTarget, existingApiErr, existingErr := c.Read2(ctx, hostSetId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -822,7 +397,7 @@ func (c *Client) SetHosts2(ctx context.Context, hostSetId string, version uint32
return target, apiErr, nil
}
func (c *Client) RemoveHosts2(ctx context.Context, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
func (c *Client) RemoveHosts(ctx context.Context, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) {
if hostSetId == "" {
return nil, nil, fmt.Errorf("empty hostSetId value passed into RemoveHosts request")
}
@@ -831,13 +406,12 @@ func (c *Client) RemoveHosts2(ctx context.Context, hostSetId string, version uin
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into RemoveHosts request")
}
existingTarget, existingApiErr, existingErr := c.Read2(ctx, hostSetId, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, hostSetId, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
+153 -236
View File
@@ -18,129 +18,95 @@ import (
)
func TestCustom(t *testing.T) {
for _, newStyle := range []bool{false, true} {
t.Run(fmt.Sprintf("custom_%t", newStyle), func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
token := tc.Token()
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
client := tc.Client().Clone()
client.SetScopeId(proj.GetPublicId())
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static")
require.NoError(err)
require.Nil(apiErr)
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
hClient := hosts.NewClient(client)
h1, apiErr, err := hClient.Create(tc.Context(), hc.Id, hosts.WithStaticHostAddress("someaddress"))
require.NoError(err)
require.Nil(apiErr)
h2, apiErr, err := hClient.Create(tc.Context(), hc.Id, hosts.WithStaticHostAddress("someaddress"))
require.NoError(err)
require.Nil(apiErr)
hClient := hosts.NewClient(client)
h1, apiErr, err := hClient.Create(tc.Context(), hc.Id, hosts.WithStaticHostAddress("someaddress"))
require.NoError(err)
require.Nil(apiErr)
h2, apiErr, err := hClient.Create(tc.Context(), hc.Id, hosts.WithStaticHostAddress("someaddress"))
require.NoError(err)
require.Nil(apiErr)
hSetClient := hostsets.NewClient(client)
var hSet *hostsets.HostSet
if newStyle {
hSet, apiErr, err = hSetClient.Create2(tc.Context(), hc.Id)
} else {
hSet, apiErr, err = hSetClient.Create(tc.Context(), hc.Id)
}
require.NoError(err)
require.Nil(apiErr)
hSetClient := hostsets.NewClient(client)
var hSet *hostsets.HostSet
hSet, apiErr, err = hSetClient.Create(tc.Context(), hc.Id)
require.NoError(err)
require.Nil(apiErr)
if newStyle {
hSet, apiErr, err = hSetClient.AddHosts2(tc.Context(), hSet.Id, hSet.Version, []string{h1.Id, h2.Id})
} else {
hSet, apiErr, err = hSetClient.AddHosts(tc.Context(), hc.Id, hSet.Id, hSet.Version, []string{h1.Id, h2.Id})
}
require.NoError(err)
require.Nil(apiErr)
assert.Contains(hSet.HostIds, h1.Id, h2.Id)
hSet, apiErr, err = hSetClient.AddHosts(tc.Context(), hSet.Id, hSet.Version, []string{h1.Id, h2.Id})
require.NoError(err)
require.Nil(apiErr)
assert.Contains(hSet.HostIds, h1.Id, h2.Id)
if newStyle {
hSet, apiErr, err = hSetClient.SetHosts2(tc.Context(), hSet.Id, hSet.Version, []string{h1.Id})
} else {
hSet, apiErr, err = hSetClient.SetHosts(tc.Context(), hc.Id, hSet.Id, hSet.Version, []string{h1.Id})
}
require.NoError(err)
require.Nil(apiErr, pretty.Sprint(apiErr))
assert.ElementsMatch([]string{h1.Id}, hSet.HostIds)
hSet, apiErr, err = hSetClient.SetHosts(tc.Context(), hSet.Id, hSet.Version, []string{h1.Id})
require.NoError(err)
require.Nil(apiErr, pretty.Sprint(apiErr))
assert.ElementsMatch([]string{h1.Id}, hSet.HostIds)
if newStyle {
hSet, apiErr, err = hSetClient.RemoveHosts2(tc.Context(), hSet.Id, hSet.Version, []string{h1.Id})
} else {
hSet, apiErr, err = hSetClient.RemoveHosts(tc.Context(), hc.Id, hSet.Id, hSet.Version, []string{h1.Id})
}
require.NoError(err)
require.Nil(apiErr)
assert.Empty(hSet.HostIds)
})
}
hSet, apiErr, err = hSetClient.RemoveHosts(tc.Context(), hSet.Id, hSet.Version, []string{h1.Id})
require.NoError(err)
require.Nil(apiErr)
assert.Empty(hSet.HostIds)
}
func TestSet_List(t *testing.T) {
for _, newStyle := range []bool{false, true} {
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
token := tc.Token()
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
client.SetScopeId(proj.GetPublicId())
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static")
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
hClient := hostsets.NewClient(client)
var ul []*hostsets.HostSet
hClient := hostsets.NewClient(client)
var ul []*hostsets.HostSet
if newStyle {
ul, apiErr, err = hClient.List2(tc.Context(), hc.Id)
} else {
ul, apiErr, err = hClient.List(tc.Context(), hc.Id)
}
require.NoError(err)
require.Nil(apiErr)
assert.Empty(ul)
ul, apiErr, err = hClient.List(tc.Context(), hc.Id)
require.NoError(err)
require.Nil(apiErr)
assert.Empty(ul)
var expected []*hostsets.HostSet
for i := 0; i < 10; i++ {
expected = append(expected, &hostsets.HostSet{Name: fmt.Sprint(i)})
}
expected[0], apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName(expected[0].Name))
require.NoError(err)
require.Nil(apiErr)
if newStyle {
ul, apiErr, err = hClient.List2(tc.Context(), hc.Id)
} else {
ul, apiErr, err = hClient.List(tc.Context(), hc.Id)
}
require.NoError(err)
require.Nil(apiErr)
assert.ElementsMatch(comparableSetSlice(expected[:1]), comparableSetSlice(ul))
for i := 1; i < 10; i++ {
expected[i], apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName(expected[i].Name))
require.NoError(err)
require.Nil(apiErr)
}
if newStyle {
ul, apiErr, err = hClient.List2(tc.Context(), hc.Id)
} else {
ul, apiErr, err = hClient.List(tc.Context(), hc.Id)
}
require.NoError(err)
require.Nil(apiErr)
assert.ElementsMatch(comparableSetSlice(expected), comparableSetSlice(ul))
var expected []*hostsets.HostSet
for i := 0; i < 10; i++ {
expected = append(expected, &hostsets.HostSet{Name: fmt.Sprint(i)})
}
expected[0], apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName(expected[0].Name))
require.NoError(err)
require.Nil(apiErr)
ul, apiErr, err = hClient.List(tc.Context(), hc.Id)
require.NoError(err)
require.Nil(apiErr)
assert.ElementsMatch(comparableSetSlice(expected[:1]), comparableSetSlice(ul))
for i := 1; i < 10; i++ {
expected[i], apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName(expected[i].Name))
require.NoError(err)
require.Nil(apiErr)
}
ul, apiErr, err = hClient.List(tc.Context(), hc.Id)
require.NoError(err)
require.Nil(apiErr)
assert.ElementsMatch(comparableSetSlice(expected), comparableSetSlice(ul))
}
func comparableSetSlice(in []*hostsets.HostSet) []hostsets.HostSet {
@@ -158,146 +124,97 @@ func comparableSetSlice(in []*hostsets.HostSet) []hostsets.HostSet {
return filtered
}
func TestSet_Crud(t *testing.T) {
for _, newStyle := range []bool{false, true} {
t.Run(fmt.Sprintf("crud_%t", newStyle), func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
token := tc.Token()
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
hc, apiErr, err := hostcatalogs.NewClient(projClient).Create(tc.Context(), "static")
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
checkHost := func(t *testing.T, step string, h *hostsets.HostSet, apiErr *api.Error, err error, wantedName string, wantVersion uint32) {
t.Helper()
require.NoError(err, step)
if !assert.Nil(apiErr, step) && apiErr.Message != "" {
t.Errorf("ApiError message: %q", apiErr.Message)
}
assert.NotNil(h, "returned no resource", step)
gotName := ""
if h.Name != "" {
gotName = h.Name
}
assert.Equal(wantedName, gotName, step)
assert.Equal(wantVersion, h.Version)
}
hClient := hostsets.NewClient(projClient)
var h *hostsets.HostSet
if newStyle {
h, apiErr, err = hClient.Create2(tc.Context(), hc.Id, hostsets.WithName("foo"))
} else {
h, apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName("foo"))
}
checkHost(t, "create", h, apiErr, err, "foo", 1)
if newStyle {
h, apiErr, err = hClient.Read2(tc.Context(), h.Id)
} else {
h, apiErr, err = hClient.Read(tc.Context(), hc.Id, h.Id)
}
checkHost(t, "read", h, apiErr, err, "foo", 1)
if newStyle {
h, apiErr, err = hClient.Update2(tc.Context(), h.Id, h.Version, hostsets.WithName("bar"))
} else {
h, apiErr, err = hClient.Update(tc.Context(), hc.Id, h.Id, h.Version, hostsets.WithName("bar"))
}
checkHost(t, "update", h, apiErr, err, "bar", 2)
if newStyle {
h, apiErr, err = hClient.Update2(tc.Context(), h.Id, h.Version, hostsets.DefaultName())
} else {
h, apiErr, err = hClient.Update(tc.Context(), hc.Id, h.Id, h.Version, hostsets.DefaultName())
}
checkHost(t, "update", h, apiErr, err, "", 3)
var existed bool
if newStyle {
existed, apiErr, err = hClient.Delete2(tc.Context(), h.Id)
} else {
existed, apiErr, err = hClient.Delete(tc.Context(), hc.Id, h.Id)
}
assert.NoError(err)
assert.True(existed, "Expected existing catalog when deleted, but it wasn't.")
if newStyle {
existed, apiErr, err = hClient.Delete2(tc.Context(), h.Id)
} else {
existed, apiErr, err = hClient.Delete(tc.Context(), hc.Id, h.Id)
}
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusForbidden, apiErr.Status)
})
checkHost := func(t *testing.T, step string, h *hostsets.HostSet, apiErr *api.Error, err error, wantedName string, wantVersion uint32) {
t.Helper()
require.NoError(err, step)
if !assert.Nil(apiErr, step) && apiErr.Message != "" {
t.Errorf("ApiError message: %q", apiErr.Message)
}
assert.NotNil(h, "returned no resource", step)
gotName := ""
if h.Name != "" {
gotName = h.Name
}
assert.Equal(wantedName, gotName, step)
assert.Equal(wantVersion, h.Version)
}
hClient := hostsets.NewClient(client)
var h *hostsets.HostSet
h, apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName("foo"))
checkHost(t, "create", h, apiErr, err, "foo", 1)
h, apiErr, err = hClient.Read(tc.Context(), h.Id)
checkHost(t, "read", h, apiErr, err, "foo", 1)
h, apiErr, err = hClient.Update(tc.Context(), h.Id, h.Version, hostsets.WithName("bar"))
checkHost(t, "update", h, apiErr, err, "bar", 2)
h, apiErr, err = hClient.Update(tc.Context(), h.Id, h.Version, hostsets.DefaultName())
checkHost(t, "update", h, apiErr, err, "", 3)
var existed bool
existed, apiErr, err = hClient.Delete(tc.Context(), h.Id)
assert.NoError(err)
assert.True(existed, "Expected existing catalog when deleted, but it wasn't.")
existed, apiErr, err = hClient.Delete(tc.Context(), h.Id)
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusForbidden, apiErr.Status)
}
// TODO: Get better coverage for expected errors and error formats.
func TestSet_Errors(t *testing.T) {
for _, newStyle := range []bool{false, true} {
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
token := tc.Token()
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
client.SetScopeId(proj.GetPublicId())
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static")
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hc)
hClient := hostsets.NewClient(client)
hClient := hostsets.NewClient(client)
var h *hostsets.HostSet
if newStyle {
h, apiErr, err = hClient.Create2(tc.Context(), hc.Id, hostsets.WithName("foo"))
} else {
h, apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName("foo"))
}
require.NoError(err)
require.Nil(apiErr)
assert.NotNil(h)
var h *hostsets.HostSet
h, apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName("foo"))
require.NoError(err)
require.Nil(apiErr)
assert.NotNil(h)
if newStyle {
h, apiErr, err = hClient.Create2(tc.Context(), hc.Id, hostsets.WithName("foo"))
} else {
h, apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName("foo"))
}
require.NoError(err)
assert.NotNil(apiErr)
assert.Nil(h)
h, apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName("foo"))
require.NoError(err)
assert.NotNil(apiErr)
assert.Nil(h)
if newStyle {
_, apiErr, err = hClient.Read2(tc.Context(), static.HostSetPrefix+"_doesntexis")
} else {
_, apiErr, err = hClient.Read(tc.Context(), hc.Id, static.HostSetPrefix+"_doesntexis")
}
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusForbidden, apiErr.Status)
_, apiErr, err = hClient.Read(tc.Context(), static.HostSetPrefix+"_doesntexis")
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusForbidden, apiErr.Status)
if newStyle {
_, apiErr, err = hClient.Read2(tc.Context(), "invalid id")
} else {
_, apiErr, err = hClient.Read(tc.Context(), hc.Id, "invalid id")
}
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusBadRequest, apiErr.Status)
}
_, apiErr, err = hClient.Read(tc.Context(), "invalid id")
require.NoError(err)
assert.NotNil(apiErr)
assert.EqualValues(http.StatusBadRequest, apiErr.Status)
}
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+17 -22
View File
@@ -47,6 +47,10 @@ type structInfo struct {
// the attributes map.
subtypeName string
// For non-top-level collections, this can be used to indicate the name of
// the argument that should be used
parentTypeName string
// mappings of names of resources and param names for sub slice types, e.g.
// role principals and group members
sliceSubTypes map[string]string
@@ -76,10 +80,6 @@ type structInfo struct {
// given type, e.g. arguments only valid for one call or purpose and not
// conveyed within the item itself
extraOptions []fieldInfo
useNewStyle bool
disableOldStyle bool
}
var inputStructs = []*structInfo{
@@ -231,7 +231,8 @@ var inputStructs = []*structInfo{
deleteTemplate,
listTemplate,
},
pathArgs: []string{"auth-method", "account"},
pathArgs: []string{"account"},
parentTypeName: "auth-method",
versionEnabled: true,
},
{
@@ -278,7 +279,8 @@ var inputStructs = []*structInfo{
deleteTemplate,
listTemplate,
},
pathArgs: []string{"host-catalog", "host"},
pathArgs: []string{"host"},
parentTypeName: "host-catalog",
versionEnabled: true,
},
{
@@ -296,18 +298,13 @@ var inputStructs = []*structInfo{
updateTemplate,
deleteTemplate,
listTemplate,
createTemplate2,
readTemplate2,
updateTemplate2,
deleteTemplate2,
listTemplate2,
},
pathArgs: []string{"host-catalog", "host-set"},
pathArgs: []string{"host-set"},
parentTypeName: "host-catalog",
sliceSubTypes: map[string]string{
"Hosts": "hostIds",
},
versionEnabled: true,
useNewStyle: true,
},
{
inProto: &targets.HostSet{},
@@ -318,19 +315,17 @@ var inputStructs = []*structInfo{
outFile: "targets/target.gen.go",
templates: []*template.Template{
clientTemplate,
createTemplate2,
readTemplate2,
updateTemplate2,
deleteTemplate2,
listTemplate2,
createTemplate,
readTemplate,
updateTemplate,
deleteTemplate,
listTemplate,
},
pathArgs: []string{"target"},
sliceSubTypes: map[string]string{
"HostSets": "hostSetIds",
},
versionEnabled: true,
typeOnCreate: true,
useNewStyle: true,
disableOldStyle: true,
versionEnabled: true,
typeOnCreate: true,
},
}
+69 -434
View File
@@ -39,32 +39,17 @@ func toPath(segments []string, action string) string {
return fmt.Sprintf("fmt.Sprintf(\"%s%s\", %s)", strings.Join(printfString, "/"), action, strings.Join(printfArg, ", "))
}
func getArgsAndPaths(in []string, action string) (colArgs, resArgs []string, colPath, resPath string) {
var argNames, pathSegment []string
for _, s := range in {
varName := fmt.Sprintf("%sId", strcase.ToLowerCamel(strings.ReplaceAll(s, "-", "_")))
collectionName := fmt.Sprintf("%ss", s)
argNames = append(argNames, varName)
pathSegment = append(pathSegment, collectionName, varName)
}
colArgs, resArgs, colPath, resPath = argNames[:len(argNames)-1], argNames, toPath(pathSegment[:len(pathSegment)-1], action), toPath(pathSegment, action)
// Scopes create and list operations always need scope ID
if colPath == `"scopes"` {
colArgs = append(colArgs, "scopeId")
}
return
}
func getArgsAndPathsNewStyle(in []string, action string) (colArg, resArg string, colPath, resPath string) {
func getArgsAndPaths(in []string, parentTypeName, action string) (colArg, resArg string, colPath, resPath string) {
resArg = fmt.Sprintf("%sId", strcase.ToLowerCamel(strings.ReplaceAll(in[len(in)-1], "-", "_")))
strToReplace := "scope"
if len(in) == 1 {
colArg = "scopeId"
if parentTypeName != "" {
strToReplace = parentTypeName
}
} else {
colArg = fmt.Sprintf("%sId", strcase.ToLowerCamel(strings.ReplaceAll(in[len(in)-2], "-", "_")))
strToReplace = in[len(in)-2]
}
colArg = fmt.Sprintf("%sId", strcase.ToLowerCamel(strings.ReplaceAll(strToReplace, "-", "_")))
colPath = fmt.Sprintf("%ss", in[len(in)-1])
if action != "" {
@@ -75,23 +60,19 @@ func getArgsAndPathsNewStyle(in []string, action string) (colArg, resArg string,
}
type templateInput struct {
Name string
Package string
Fields []fieldInfo
PathArgs []string
CollectionFunctionArgs []string
ResourceFunctionArgs []string
CollectionPath string
ResourcePath string
CollectionFunctionArg2 string
ResourceFunctionArg2 string
CollectionPath2 string
ResourcePath2 string
SliceSubTypes map[string]string
ExtraOptions []fieldInfo
VersionEnabled bool
TypeOnCreate bool
Two string
Name string
Package string
Fields []fieldInfo
PathArgs []string
CollectionFunctionArg string
ResourceFunctionArg string
CollectionPath string
ResourcePath string
ParentTypeName string
SliceSubTypes map[string]string
ExtraOptions []fieldInfo
VersionEnabled bool
TypeOnCreate bool
}
func fillTemplates() {
@@ -103,19 +84,14 @@ func fillTemplates() {
Package: in.generatedStructure.pkg,
Fields: in.generatedStructure.fields,
PathArgs: in.pathArgs,
ParentTypeName: in.parentTypeName,
ExtraOptions: in.extraOptions,
VersionEnabled: in.versionEnabled,
TypeOnCreate: in.typeOnCreate,
Two: "2",
}
if in.useNewStyle && in.disableOldStyle {
input.Two = ""
}
if len(in.pathArgs) > 0 {
input.CollectionFunctionArgs, input.ResourceFunctionArgs, input.CollectionPath, input.ResourcePath = getArgsAndPaths(in.pathArgs, "")
input.CollectionFunctionArg2, input.ResourceFunctionArg2, input.CollectionPath2, input.ResourcePath2 = getArgsAndPathsNewStyle(in.pathArgs, "")
input.CollectionFunctionArg, input.ResourceFunctionArg, input.CollectionPath, input.ResourcePath = getArgsAndPaths(in.pathArgs, in.parentTypeName, "")
}
if err := structTemplate.Execute(outBuf, input); err != nil {
@@ -125,12 +101,7 @@ func fillTemplates() {
if len(in.sliceSubTypes) > 0 {
input.SliceSubTypes = in.sliceSubTypes
if !in.disableOldStyle {
in.templates = append(in.templates, sliceSubTypeTemplate)
}
if in.useNewStyle {
in.templates = append(in.templates, sliceSubTypeTemplate2)
}
in.templates = append(in.templates, sliceSubTypeTemplate)
}
for _, t := range in.templates {
@@ -229,24 +200,23 @@ func fillTemplates() {
}
}
var listTemplate2 = template.Must(template.New("").Funcs(
var listTemplate = template.Must(template.New("").Funcs(
template.FuncMap{
"snakeCase": snakeCase,
},
).Parse(`
func (c *Client) List{{ .Two }}(ctx context.Context, {{ .CollectionFunctionArg2 }} string, opt... Option) ([]*{{ .Name }}, *api.Error, error) {
if {{ .CollectionFunctionArg2 }} == "" {
return nil, nil, fmt.Errorf("empty {{ .CollectionFunctionArg2 }} value passed into List request")
func (c *Client) List(ctx context.Context, {{ .CollectionFunctionArg }} string, opt... Option) ([]*{{ .Name }}, *api.Error, error) {
if {{ .CollectionFunctionArg }} == "" {
return nil, nil, fmt.Errorf("empty {{ .CollectionFunctionArg }} value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
opts.queryMap["{{ snakeCase .CollectionFunctionArg2 }}"] = {{ .CollectionFunctionArg2 }}
opts.queryMap["{{ snakeCase .CollectionFunctionArg }}"] = {{ .CollectionFunctionArg }}
req, err := c.client.NewRequest(ctx, "GET", "{{ .CollectionPath2 }}", nil, apiOpts...)
req, err := c.client.NewRequest(ctx, "GET", "{{ .CollectionPath }}", nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating List request: %w", err)
}
@@ -281,101 +251,11 @@ func (c *Client) List{{ .Two }}(ctx context.Context, {{ .CollectionFunctionArg2
}
`))
var listTemplate = template.Must(template.New("").Parse(`
func (c *Client) List(ctx context.Context, {{ range .CollectionFunctionArgs }} {{ . }} string, {{ end }}opt... Option) ([]*{{ .Name }}, *api.Error, error) { {{ range .CollectionFunctionArgs }}
if {{ . }} == "" {
return nil, nil, fmt.Errorf("empty {{ . }} value passed into List request")
}
{{ end }}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
req, err := c.client.NewRequest(ctx, "GET", {{ .CollectionPath }}, nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating List request: %w", err)
}
{{ if ( eq .CollectionPath "\"scopes\"" ) }}
opts.queryMap["scope_id"] = scopeId
{{ end }}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during List call: %w", err)
}
type listResponse struct {
Items []*{{ .Name }}
}
target := &listResponse{}
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding List response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target.Items, apiErr, nil
}
`))
var readTemplate2 = template.Must(template.New("").Parse(`
func (c *Client) Read{{ .Two }}(ctx context.Context, {{ .ResourceFunctionArg2 }} string, opt... Option) (*{{ .Name }}, *api.Error, error) {
if {{ .ResourceFunctionArg2 }} == "" {
return nil, nil, fmt.Errorf("empty {{ .ResourceFunctionArg2 }} value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
req, err := c.client.NewRequest(ctx, "GET", {{ .ResourcePath2 }}, nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Read request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err)
}
target := new({{ .Name }})
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding Read response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
`))
var readTemplate = template.Must(template.New("").Parse(`
func (c *Client) Read(ctx context.Context, {{ range .ResourceFunctionArgs }} {{ . }} string, {{ end }} opt... Option) (*{{ .Name }}, *api.Error, error) { {{ range .ResourceFunctionArgs }}
if {{ . }} == "" {
return nil, nil, fmt.Errorf("empty {{ . }} value passed into Read request")
func (c *Client) Read(ctx context.Context, {{ .ResourceFunctionArg }} string, opt... Option) (*{{ .Name }}, *api.Error, error) {
if {{ .ResourceFunctionArg }} == "" {
return nil, nil, fmt.Errorf("empty {{ .ResourceFunctionArg }} value passed into Read request")
}
{{ end }}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -412,57 +292,11 @@ func (c *Client) Read(ctx context.Context, {{ range .ResourceFunctionArgs }} {{
}
`))
var deleteTemplate2 = template.Must(template.New("").Parse(`
func (c *Client) Delete{{ .Two }}(ctx context.Context, {{ .ResourceFunctionArg2 }} string, opt... Option) (bool, *api.Error, error) {
if {{ .ResourceFunctionArg2 }} == "" {
return false, nil, fmt.Errorf("empty {{ .ResourceFunctionArg2 }} value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
req, err := c.client.NewRequest(ctx, "DELETE", {{ .ResourcePath2 }}, nil, apiOpts...)
if err != nil {
return false, nil, fmt.Errorf("error creating Delete request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err)
}
type deleteResponse struct {
Existed bool
}
target := &deleteResponse{}
apiErr, err := resp.Decode(target)
if err != nil {
return false, nil, fmt.Errorf("error decoding Delete response: %w", err)
}
if apiErr != nil {
return false, apiErr, nil
}
return target.Existed, apiErr, nil
}
`))
var deleteTemplate = template.Must(template.New("").Parse(`
func (c *Client) Delete(ctx context.Context, {{ range .ResourceFunctionArgs }} {{ . }} string, {{ end }} opt... Option) (bool, *api.Error, error) { {{ range .ResourceFunctionArgs }}
if {{ . }} == "" {
return false, nil, fmt.Errorf("empty {{ . }} value passed into Delete request")
func (c *Client) Delete(ctx context.Context, {{ .ResourceFunctionArg }} string, opt... Option) (bool, *api.Error, error) {
if {{ .ResourceFunctionArg }} == "" {
return false, nil, fmt.Errorf("empty {{ .ResourceFunctionArg }} value passed into Delete request")
}
{{ end }}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -502,17 +336,18 @@ func (c *Client) Delete(ctx context.Context, {{ range .ResourceFunctionArgs }} {
}
`))
var createTemplate2 = template.Must(template.New("").Funcs(
var createTemplate = template.Must(template.New("").Funcs(
template.FuncMap{
"snakeCase": snakeCase,
},
).Parse(`
func (c *Client) Create{{ .Two }} (ctx context.Context, {{ if .TypeOnCreate }} resourceType string, {{ end }} {{ .CollectionFunctionArg2 }} string, opt... Option) (*{{ .Name }}, *api.Error, error) {
if {{ .CollectionFunctionArg2 }} == "" {
return nil, nil, fmt.Errorf("empty {{ .CollectionFunctionArg2 }} value passed into Create request")
func (c *Client) Create (ctx context.Context, {{ if .TypeOnCreate }} resourceType string, {{ end }} {{ .CollectionFunctionArg }} string, opt... Option) (*{{ .Name }}, *api.Error, error) {
if {{ .CollectionFunctionArg }} == "" {
return nil, nil, fmt.Errorf("empty {{ .CollectionFunctionArg }} value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -522,9 +357,9 @@ func (c *Client) Create{{ .Two }} (ctx context.Context, {{ if .TypeOnCreate }} r
opts.postMap["type"] = resourceType
}{{ end }}
opts.postMap["{{ snakeCase .CollectionFunctionArg2 }}"] = {{ .CollectionFunctionArg2 }}
opts.postMap["{{ snakeCase .CollectionFunctionArg }}"] = {{ .CollectionFunctionArg }}
req, err := c.client.NewRequest(ctx, "POST", "{{ .CollectionPath2 }}", opts.postMap, apiOpts...)
req, err := c.client.NewRequest(ctx, "POST", "{{ .CollectionPath }}", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
@@ -556,121 +391,11 @@ func (c *Client) Create{{ .Two }} (ctx context.Context, {{ if .TypeOnCreate }} r
}
`))
var createTemplate = template.Must(template.New("").Parse(`
func (c *Client) Create(ctx context.Context, {{ if .TypeOnCreate }} resourceType string, {{ end }} {{ range .CollectionFunctionArgs }} {{ . }} string, {{ end }} opt... Option) (*{{ .Name }}, *api.Error, error) { {{ range .CollectionFunctionArgs }}
if {{ . }} == "" {
return nil, nil, fmt.Errorf("empty {{ . }} value passed into Create request")
}
{{ end }}opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
{{ if .TypeOnCreate }} if resourceType == "" {
return nil, nil, fmt.Errorf("empty resourceType value passed into Create request")
} else {
opts.postMap["type"] = resourceType
}{{ end }}
{{ if ( eq .CollectionPath "\"scopes\"" ) }}
opts.postMap["scope_id"] = scopeId
{{ end }}
req, err := c.client.NewRequest(ctx, "POST", {{ .CollectionPath }}, opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err)
}
target := new({{ .Name }})
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding Create response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
`))
var updateTemplate2 = template.Must(template.New("").Parse(`
func (c *Client) Update{{ .Two }}(ctx context.Context, {{ .ResourceFunctionArg2 }} string, version uint32, opt... Option) (*{{ .Name }}, *api.Error, error) {
if {{ .ResourceFunctionArg2 }} == "" {
return nil, nil, fmt.Errorf("empty {{ .ResourceFunctionArg2 }} value passed into Update request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
{{ if .VersionEnabled }}
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read{{ .Two }}(ctx, {{ .ResourceFunctionArg2 }}, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
if existingApiErr != nil {
return nil, nil, fmt.Errorf("error from controller when performing initial check-and-set read: %s", pretty.Sprint(existingApiErr))
}
if existingTarget == nil {
return nil, nil, errors.New("nil resource found when performing initial check-and-set read")
}
version = existingTarget.Version
}
{{ end }}
opts.postMap["version"] = version
req, err := c.client.NewRequest(ctx, "PATCH", {{ .ResourcePath2 }}, opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Update request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err)
}
target := new({{ .Name }})
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding Update response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
`))
var updateTemplate = template.Must(template.New("").Parse(`
func (c *Client) Update(ctx context.Context, {{ range .ResourceFunctionArgs }} {{ . }} string, {{ end }}version uint32, opt... Option) (*{{ .Name }}, *api.Error, error) { {{ range .ResourceFunctionArgs }}
if {{ . }} == "" {
return nil, nil, fmt.Errorf("empty {{ . }} value passed into Update request")
}{{ end }}
func (c *Client) Update(ctx context.Context, {{ .ResourceFunctionArg }} string, version uint32, opt... Option) (*{{ .Name }}, *api.Error, error) {
if {{ .ResourceFunctionArg }} == "" {
return nil, nil, fmt.Errorf("empty {{ .ResourceFunctionArg }} value passed into Update request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -682,7 +407,7 @@ func (c *Client) Update(ctx context.Context, {{ range .ResourceFunctionArgs }} {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, {{ range .ResourceFunctionArgs }} {{ . }}, {{ end }} opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, {{ .ResourceFunctionArg }}, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -741,11 +466,11 @@ var sliceSubTypeTemplate = template.Must(template.New("").Funcs(
{{ range $key, $value := $input.SliceSubTypes }}
{{ $fullName := print $op $key }}
{{ $actionName := kebabCase $fullName }}
{{ $resPath := getPathWithAction $input.PathArgs $actionName }}
func (c *Client) {{ $fullName }}(ctx context.Context, {{ range $input.ResourceFunctionArgs }} {{ . }} string, {{ end }}version uint32, {{ $value }} []string, opt... Option) (*{{ $input.Name }}, *api.Error, error) { {{ range $input.ResourceFunctionArgs }}
if {{ . }} == "" {
return nil, nil, fmt.Errorf("empty {{ . }} value passed into {{ $fullName }} request")
}{{ end }}
{{ $resPath := getPathWithAction $input.PathArgs $input.ParentTypeName $actionName }}
func (c *Client) {{ $fullName }}(ctx context.Context, {{ $input.ResourceFunctionArg }} string, version uint32, {{ $value }} []string, opt... Option) (*{{ $input.Name }}, *api.Error, error) {
if {{ $input.ResourceFunctionArg }} == "" {
return nil, nil, fmt.Errorf("empty {{ $input.ResourceFunctionArg }} value passed into {{ $fullName }} request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -757,92 +482,7 @@ func (c *Client) {{ $fullName }}(ctx context.Context, {{ range $input.ResourceFu
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into {{ $fullName }} request")
}
existingTarget, existingApiErr, existingErr := c.Read(ctx, {{ range $input.ResourceFunctionArgs }} {{ . }}, {{ end }} opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
if existingApiErr != nil {
return nil, nil, fmt.Errorf("error from controller when performing initial check-and-set read: %s", pretty.Sprint(existingApiErr))
}
if existingTarget == nil {
return nil, nil, errors.New("nil resource found when performing initial check-and-set read")
}
version = existingTarget.Version
}
{{ end }}
opts.postMap["version"] = version
if len({{ $value }}) > 0 {
opts.postMap["{{ snakeCase $value }}"] = {{ $value }}
}{{ if ( eq $op "Set" ) }} else if {{ $value }} != nil {
// In this function, a non-nil but empty list means clear out
opts.postMap["{{ snakeCase $value }}"] = nil
}
{{ end }}
req, err := c.client.NewRequest(ctx, "POST", {{ $resPath }}, opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating {{ $fullName }} request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := c.client.Do(req)
if err != nil {
return nil, nil, fmt.Errorf("error performing client request during {{ $fullName }} call: %w", err)
}
target := new({{ $input.Name }})
apiErr, err := resp.Decode(target)
if err != nil {
return nil, nil, fmt.Errorf("error decoding {{ $fullName }} response: %w", err)
}
if apiErr != nil {
return nil, apiErr, nil
}
return target, apiErr, nil
}
{{ end }}
{{ end }}
`))
var sliceSubTypeTemplate2 = template.Must(template.New("").Funcs(
template.FuncMap{
"makeSlice": makeSlice,
"snakeCase": snakeCase,
"kebabCase": kebabCase,
"getPathWithActionNewStyle": getPathWithActionNewStyle,
},
).Parse(`
{{ $input := . }}
{{ range $index, $op := makeSlice "Add" "Set" "Remove" }}
{{ range $key, $value := $input.SliceSubTypes }}
{{ $fullName := print $op $key }}
{{ $actionName := kebabCase $fullName }}
{{ $resPath := getPathWithActionNewStyle $input.PathArgs $actionName }}
func (c *Client) {{ $fullName }}{{ $input.Two }}(ctx context.Context, {{ $input.ResourceFunctionArg2 }} string, version uint32, {{ $value }} []string, opt... Option) (*{{ $input.Name }}, *api.Error, error) {
if {{ $input.ResourceFunctionArg2 }} == "" {
return nil, nil, fmt.Errorf("empty {{ $input.ResourceFunctionArg2 }} value passed into {{ $fullName }} request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
{{ if $input.VersionEnabled }}
if version == 0 {
if !opts.withAutomaticVersioning {
return nil, nil, errors.New("zero version number passed into {{ $fullName }} request")
}
existingTarget, existingApiErr, existingErr := c.Read{{ $input.Two }}(ctx, {{ $input.ResourceFunctionArg2 }}, opt...)
existingTarget, existingApiErr, existingErr := c.Read(ctx, {{ $input.ResourceFunctionArg }}, opt...)
if existingErr != nil {
return nil, nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
}
@@ -918,12 +558,22 @@ type {{ .Name }} struct { {{ range .Fields }}
`)))
var clientTemplate = template.Must(template.New("").Parse(`
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{ client: c }
return &Client{ client: c.Clone() }
}
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
`))
@@ -950,7 +600,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -967,25 +616,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
{{ range .Fields }}
@@ -1033,12 +673,7 @@ func kebabCase(in string) string {
return strcase.ToKebab(in)
}
func getPathWithAction(resArgs []string, action string) string {
_, _, _, resPath := getArgsAndPaths(resArgs, action)
return resPath
}
func getPathWithActionNewStyle(resArgs []string, action string) string {
_, _, _, resPath := getArgsAndPathsNewStyle(resArgs, action)
func getPathWithAction(resArgs []string, parentTypeName, action string) string {
_, _, _, resPath := getArgsAndPaths(resArgs, parentTypeName, action)
return resPath
}
+1 -17
View File
@@ -13,24 +13,8 @@ type Option func(*options)
// options = how options are represented
type options struct {
withScopeId string
withNewStyle bool
}
func getDefaultOptions() options {
return options{
withScopeId: "",
}
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
func WithNewStyle() Option {
return func(o *options) {
o.withNewStyle = true
}
return options{}
}
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+26 -6
View File
@@ -30,24 +30,42 @@ type Role struct {
Grants []*Grant `json:"grants,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
func (c *Client) Create(ctx context.Context, opt ...Option) (*Role, *api.Error, error) {
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Role, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts.postMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "POST", "roles", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -74,9 +92,8 @@ func (c *Client) Create(ctx context.Context, opt ...Option) (*Role, *api.Error,
func (c *Client) Read(ctx context.Context, roleId string, opt ...Option) (*Role, *api.Error, error) {
if roleId == "" {
return nil, nil, fmt.Errorf("empty roleId value passed into Read request")
return nil, nil, fmt.Errorf("empty roleId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -174,7 +191,6 @@ func (c *Client) Delete(ctx context.Context, roleId string, opt ...Option) (bool
if roleId == "" {
return false, nil, fmt.Errorf("empty roleId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -213,12 +229,16 @@ func (c *Client) Delete(ctx context.Context, roleId string, opt ...Option) (bool
return target.Existed, apiErr, nil
}
func (c *Client) List(ctx context.Context, opt ...Option) ([]*Role, *api.Error, error) {
func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Role, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "roles", nil, apiOpts...)
if err != nil {
+65 -91
View File
@@ -18,36 +18,29 @@ import (
func TestCustom(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
cases := []struct {
name string
scopeClient *api.Client
name string
scopeId string
}{
{
name: "org",
scopeClient: client,
name: "org",
scopeId: org.GetPublicId(),
},
{
name: "proj",
scopeClient: projClient,
name: "proj",
scopeId: proj.GetPublicId(),
},
}
user, apiErr, err := users.NewClient(client).Create(tc.Context())
user, apiErr, err := users.NewClient(client).Create(tc.Context(), org.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
@@ -69,15 +62,15 @@ func TestCustom(t *testing.T) {
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
g, apiErr, err := groups.NewClient(tt.scopeClient).Create(tc.Context())
g, apiErr, err := groups.NewClient(client).Create(tc.Context(), tt.scopeId)
require.NoError(err)
require.Nil(apiErr)
require.NotNil(g)
rc := roles.NewClient(tt.scopeClient)
rc := roles.NewClient(client)
var version uint32 = 1
r, apiErr, err := rc.Create(tc.Context(), roles.WithName("foo"))
r, apiErr, err := rc.Create(tc.Context(), tt.scopeId, roles.WithName("foo"))
require.NoError(err)
require.Nil(apiErr)
require.NotNil(r)
@@ -129,65 +122,60 @@ func TestCustom(t *testing.T) {
}
}
func TestRole_List(t *testing.T) {
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
cases := []struct {
name string
scopeClient *api.Client
name string
scopeId string
}{
{
name: "org",
scopeClient: client,
name: "org",
scopeId: org.GetPublicId(),
},
{
name: "proj",
scopeClient: projClient,
name: "proj",
scopeId: proj.GetPublicId(),
},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
roleClient := roles.NewClient(tt.scopeClient)
p1, apiErr, err := roleClient.List(tc.Context())
var expected []*roles.Role
roleClient := roles.NewClient(client)
p1, apiErr, err := roleClient.List(tc.Context(), tt.scopeId)
require.NoError(err)
assert.Nil(apiErr)
require.Len(p1, 0)
require.Len(p1, 1)
expected = append(expected, p1[0])
var expected []*roles.Role
for i := 0; i < 10; i++ {
for i := 1; i < 11; i++ {
expected = append(expected, &roles.Role{Name: fmt.Sprint(i)})
}
expected[0], apiErr, err = roleClient.Create(tc.Context(), roles.WithName(expected[0].Name))
expected[1], apiErr, err = roleClient.Create(tc.Context(), tt.scopeId, roles.WithName(expected[1].Name))
require.NoError(err)
assert.Nil(apiErr)
p2, apiErr, err := roleClient.List(tc.Context())
p2, apiErr, err := roleClient.List(tc.Context(), tt.scopeId)
assert.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableSlice(expected[:1]), comparableSlice(p2))
assert.ElementsMatch(comparableSlice(expected[0:2]), comparableSlice(p2))
for i := 1; i < 10; i++ {
expected[i], apiErr, err = roleClient.Create(tc.Context(), roles.WithName(expected[i].Name))
for i := 2; i < 11; i++ {
expected[i], apiErr, err = roleClient.Create(tc.Context(), tt.scopeId, roles.WithName(expected[i].Name))
assert.NoError(err)
assert.Nil(apiErr)
}
p3, apiErr, err := roleClient.List(tc.Context())
p3, apiErr, err := roleClient.List(tc.Context(), tt.scopeId)
require.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableSlice(expected), comparableSlice(p3))
@@ -210,34 +198,27 @@ func comparableSlice(in []*roles.Role) []roles.Role {
return filtered
}
func TestRole_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
cases := []struct {
name string
scopeClient *api.Client
name string
scopeId string
}{
{
name: "org",
scopeClient: client,
name: "org",
scopeId: org.GetPublicId(),
},
{
name: "proj",
scopeClient: projClient,
name: "proj",
scopeId: proj.GetPublicId(),
},
}
@@ -257,8 +238,8 @@ func TestRole_Crud(t *testing.T) {
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
roleClient := roles.NewClient(tt.scopeClient)
g, apiErr, err := roleClient.Create(tc.Context(), roles.WithName("foo"))
roleClient := roles.NewClient(client)
g, apiErr, err := roleClient.Create(tc.Context(), tt.scopeId, roles.WithName("foo"))
checkRole("create", g, apiErr, err, "foo", 1)
g, apiErr, err = roleClient.Read(tc.Context(), g.Id)
@@ -278,47 +259,40 @@ func TestRole_Crud(t *testing.T) {
}
}
func TestRole_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, proj := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
projClient := client.Clone()
projClient.SetScopeId(proj.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
cases := []struct {
name string
scopeClient *api.Client
name string
scopeId string
}{
{
name: "org",
scopeClient: client,
name: "org",
scopeId: org.GetPublicId(),
},
{
name: "proj",
scopeClient: projClient,
name: "proj",
scopeId: proj.GetPublicId(),
},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
roleClient := roles.NewClient(tt.scopeClient)
u, apiErr, err := roleClient.Create(tc.Context(), roles.WithName("first"))
roleClient := roles.NewClient(client)
u, apiErr, err := roleClient.Create(tc.Context(), tt.scopeId, roles.WithName("first"))
require.NoError(err)
assert.Nil(apiErr)
assert.NotNil(u)
// Create another resource with the same name.
_, apiErr, err = roleClient.Create(tc.Context(), roles.WithName("first"))
_, apiErr, err = roleClient.Create(tc.Context(), tt.scopeId, roles.WithName("first"))
require.NoError(err)
assert.NotNil(apiErr)
+2 -12
View File
@@ -18,7 +18,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -35,25 +34,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+15 -30
View File
@@ -13,20 +13,15 @@ import (
"github.com/stretchr/testify/require"
)
func TestProjects_List(t *testing.T) {
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org := iam.TestOrg(t, tc.IamRepo(), iam.WithUserId(token.UserId))
scps := scopes.NewClient(client)
@@ -63,20 +58,15 @@ func comparableSlice(in []*scopes.Scope) []scopes.Scope {
return filtered
}
func TestProjects_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, _ := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, _ := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
scps := scopes.NewClient(client)
@@ -116,20 +106,15 @@ func TestProjects_Crud(t *testing.T) {
}
// TODO: Get better coverage for expected errors and error formats.
func TestProject_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org, _ := iam.TestScopes(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org, _ := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
scps := scopes.NewClient(client)
+16 -7
View File
@@ -24,19 +24,31 @@ type Scope struct {
Version uint32 `json:"version,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Scope, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -47,6 +59,7 @@ func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Sc
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -73,9 +86,8 @@ func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Sc
func (c *Client) Read(ctx context.Context, scopeId string, opt ...Option) (*Scope, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Read request")
return nil, nil, fmt.Errorf("empty scopeId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -173,7 +185,6 @@ func (c *Client) Delete(ctx context.Context, scopeId string, opt ...Option) (boo
if scopeId == "" {
return false, nil, fmt.Errorf("empty scopeId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -216,20 +227,18 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Sc
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "scopes", nil, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating List request: %w", err)
}
opts.queryMap["scope_id"] = scopeId
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+13 -9
View File
@@ -29,20 +29,31 @@ type Target struct {
DefaultPort uint32 `json:"default_port,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, resourceType string, scopeId string, opt ...Option) (*Target, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -92,7 +103,6 @@ func (c *Client) Read(ctx context.Context, targetId string, opt ...Option) (*Tar
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("targets/%s", targetId), nil, apiOpts...)
if err != nil {
@@ -132,7 +142,6 @@ func (c *Client) Update(ctx context.Context, targetId string, version uint32, op
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
@@ -191,7 +200,6 @@ func (c *Client) Delete(ctx context.Context, targetId string, opt ...Option) (bo
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("targets/%s", targetId), nil, apiOpts...)
if err != nil {
@@ -234,7 +242,6 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Ta
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "targets", nil, apiOpts...)
@@ -278,7 +285,6 @@ func (c *Client) AddHostSets(ctx context.Context, targetId string, version uint3
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
@@ -341,7 +347,6 @@ func (c *Client) SetHostSets(ctx context.Context, targetId string, version uint3
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
@@ -407,7 +412,6 @@ func (c *Client) RemoveHostSets(ctx context.Context, targetId string, version ui
}
opts, apiOpts := getOpts(opt...)
apiOpts = append(apiOpts, api.WithNewStyle())
if version == 0 {
if !opts.withAutomaticVersioning {
+7 -5
View File
@@ -24,18 +24,18 @@ func TestCustom(t *testing.T) {
token := tc.Token()
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
client := tc.Client().Clone()
client.SetScopeId(proj.GetPublicId())
client.SetToken(token.Token)
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static")
hc, apiErr, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
require.NoError(err)
require.Nil(apiErr)
hSetClient := hostsets.NewClient(client)
hSet, apiErr, err := hSetClient.Create2(tc.Context(), hc.Id)
hSet, apiErr, err := hSetClient.Create(tc.Context(), hc.Id)
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hSet)
hSet2, apiErr, err := hSetClient.Create2(tc.Context(), hc.Id)
hSet2, apiErr, err := hSetClient.Create(tc.Context(), hc.Id)
require.NoError(err)
require.Nil(apiErr)
require.NotNil(hSet2)
@@ -73,8 +73,8 @@ func TestList(t *testing.T) {
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
client.SetScopeId(proj.GetPublicId())
tarClient := targets.NewClient(client)
ul, apiErr, err := tarClient.List(tc.Context(), proj.GetPublicId())
@@ -129,6 +129,7 @@ func TestCrud(t *testing.T) {
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
checkResource := func(t *testing.T, step string, h *targets.Target, apiErr *api.Error, err error, wantedName string, wantVersion uint32) {
@@ -175,6 +176,7 @@ func TestSet_Errors(t *testing.T) {
client := tc.Client()
token := tc.Token()
client.SetToken(token.Token)
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
tarClient := targets.NewClient(client)
+2 -12
View File
@@ -16,7 +16,6 @@ type Option func(*options)
type options struct {
postMap map[string]interface{}
queryMap map[string]string
withScopeId string
withAutomaticVersioning bool
}
@@ -33,25 +32,16 @@ func getOpts(opt ...Option) (options, []api.Option) {
o(&opts)
}
var apiOpts []api.Option
if opts.withScopeId != "" {
apiOpts = append(apiOpts, api.WithScopeId(opts.withScopeId))
}
return opts, apiOpts
}
func WithScopeId(id string) Option {
return func(o *options) {
o.withScopeId = id
}
}
// If set, and if the version is zero during an update, the API will perform a
// fetch to get the current version of the resource and populate it during the
// update call. This is convenient but opens up the possibility for subtle
// order-of-modification issues, so use carefully.
func WithAutomaticVersioning() Option {
func WithAutomaticVersioning(enable bool) Option {
return func(o *options) {
o.withAutomaticVersioning = true
o.withAutomaticVersioning = enable
}
}
+26 -6
View File
@@ -25,24 +25,42 @@ type User struct {
Version uint32 `json:"version,omitempty"`
}
// Client is a client for this collection
type Client struct {
client *api.Client
}
// Creates a new client for this collection. The submitted API client is cloned;
// modifications to it after generating this client will not have effect. If you
// need to make changes to the underlying API client, use ApiClient() to access
// it.
func NewClient(c *api.Client) *Client {
return &Client{client: c}
return &Client{client: c.Clone()}
}
func (c *Client) Create(ctx context.Context, opt ...Option) (*User, *api.Error, error) {
// ApiClient returns the underlying API client
func (c *Client) ApiClient() *api.Client {
return c.client
}
func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*User, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into Create request")
}
opts, apiOpts := getOpts(opt...)
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts.postMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "POST", "users", opts.postMap, apiOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating Create request: %w", err)
}
if len(opts.queryMap) > 0 {
q := url.Values{}
for k, v := range opts.queryMap {
@@ -69,9 +87,8 @@ func (c *Client) Create(ctx context.Context, opt ...Option) (*User, *api.Error,
func (c *Client) Read(ctx context.Context, userId string, opt ...Option) (*User, *api.Error, error) {
if userId == "" {
return nil, nil, fmt.Errorf("empty userId value passed into Read request")
return nil, nil, fmt.Errorf("empty userId value passed into Read request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
@@ -169,7 +186,6 @@ func (c *Client) Delete(ctx context.Context, userId string, opt ...Option) (bool
if userId == "" {
return false, nil, fmt.Errorf("empty userId value passed into Delete request")
}
if c.client == nil {
return false, nil, fmt.Errorf("nil client")
}
@@ -208,12 +224,16 @@ func (c *Client) Delete(ctx context.Context, userId string, opt ...Option) (bool
return target.Existed, apiErr, nil
}
func (c *Client) List(ctx context.Context, opt ...Option) ([]*User, *api.Error, error) {
func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*User, *api.Error, error) {
if scopeId == "" {
return nil, nil, fmt.Errorf("empty scopeId value passed into List request")
}
if c.client == nil {
return nil, nil, fmt.Errorf("nil client")
}
opts, apiOpts := getOpts(opt...)
opts.queryMap["scope_id"] = scopeId
req, err := c.client.NewRequest(ctx, "GET", "users", nil, apiOpts...)
if err != nil {
+23 -38
View File
@@ -13,23 +13,18 @@ import (
"github.com/stretchr/testify/require"
)
func TestUsers_List(t *testing.T) {
func TestList(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org := iam.TestOrg(t, tc.IamRepo(), iam.WithUserId(token.UserId))
userClient := users.NewClient(client)
ul, apiErr, err := userClient.List(tc.Context())
ul, apiErr, err := userClient.List(tc.Context(), org.GetPublicId())
assert.NoError(err)
assert.Nil(apiErr)
assert.Empty(ul)
@@ -39,21 +34,21 @@ func TestUsers_List(t *testing.T) {
expected = append(expected, &users.User{Name: fmt.Sprint(i)})
}
expected[0], apiErr, err = userClient.Create(tc.Context(), users.WithName(expected[0].Name))
expected[0], apiErr, err = userClient.Create(tc.Context(), org.GetPublicId(), users.WithName(expected[0].Name))
assert.NoError(err)
assert.Nil(apiErr)
ul, apiErr, err = userClient.List(tc.Context())
ul, apiErr, err = userClient.List(tc.Context(), org.GetPublicId())
assert.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableSlice(expected[:1]), comparableSlice(ul))
for i := 1; i < 10; i++ {
expected[i], apiErr, err = userClient.Create(tc.Context(), users.WithName(expected[i].Name))
expected[i], apiErr, err = userClient.Create(tc.Context(), org.GetPublicId(), users.WithName(expected[i].Name))
assert.NoError(err)
assert.Nil(apiErr)
}
ul, apiErr, err = userClient.List(tc.Context())
ul, apiErr, err = userClient.List(tc.Context(), org.GetPublicId())
require.NoError(err)
assert.Nil(apiErr)
assert.ElementsMatch(comparableSlice(expected), comparableSlice(ul))
@@ -74,20 +69,15 @@ func comparableSlice(in []*users.User) []users.User {
return filtered
}
func TestUser_Crud(t *testing.T) {
func TestCrud(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org := iam.TestOrg(t, tc.IamRepo(), iam.WithUserId(token.UserId))
userClient := users.NewClient(client)
checkUser := func(step string, u *users.User, apiErr *api.Error, err error, wantedName string, wantedVersion uint32) {
@@ -104,7 +94,7 @@ func TestUser_Crud(t *testing.T) {
assert.EqualValues(wantedVersion, u.Version)
}
u, apiErr, err := userClient.Create(tc.Context(), users.WithName("foo"))
u, apiErr, err := userClient.Create(tc.Context(), org.GetPublicId(), users.WithName("foo"))
checkUser("create", u, apiErr, err, "foo", 1)
u, apiErr, err = userClient.Read(tc.Context(), u.Id)
@@ -127,29 +117,24 @@ func TestUser_Crud(t *testing.T) {
assert.EqualValues(http.StatusForbidden, apiErr.Status)
}
func TestUser_Errors(t *testing.T) {
func TestErrors(t *testing.T) {
assert, require := assert.New(t), require.New(t)
amId := "ampw_1234567890"
tc := controller.NewTestController(t, &controller.TestControllerOpts{
DisableAuthorizationFailures: true,
DefaultAuthMethodId: amId,
DefaultLoginName: "user",
DefaultPassword: "passpass",
})
tc := controller.NewTestController(t, nil)
defer tc.Shutdown()
client := tc.Client()
org := iam.TestOrg(t, tc.IamRepo())
client.SetScopeId(org.GetPublicId())
token := tc.Token()
client.SetToken(token.Token)
org := iam.TestOrg(t, tc.IamRepo(), iam.WithUserId(token.UserId))
userClient := users.NewClient(client)
u, apiErr, err := userClient.Create(tc.Context(), users.WithName("first"))
u, apiErr, err := userClient.Create(tc.Context(), org.GetPublicId(), users.WithName("first"))
require.NoError(err)
assert.Nil(apiErr)
assert.NotNil(u)
// Create another resource with the same name.
_, apiErr, err = userClient.Create(tc.Context(), users.WithName("first"))
_, apiErr, err = userClient.Create(tc.Context(), org.GetPublicId(), users.WithName("first"))
require.NoError(err)
assert.NotNil(apiErr)
+6 -244
View File
@@ -16,7 +16,6 @@ import (
"github.com/hashicorp/boundary/internal/servers/controller/common"
"github.com/hashicorp/boundary/internal/servers/controller/handlers"
"github.com/hashicorp/boundary/internal/types/action"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/hashicorp/boundary/recovery"
"github.com/hashicorp/go-hclog"
@@ -149,26 +148,12 @@ func Verify(ctx context.Context, opt ...Option) (ret VerifyResults) {
return
}
// check if it's new style
if opts.withAction != action.Unknown {
v.act = opts.withAction
v.res = &perms.Resource{
ScopeId: opts.withScopeId,
Id: opts.withId,
Pin: opts.withPin,
Type: opts.withType,
}
} else {
// This remains for legacy
v.requestInfo.scopeId = opts.withScopeId
if err := v.parseAuthParams(); err != nil {
v.logger.Trace("error reading auth parameters from URL", "url", v.requestInfo.Path, "method", v.requestInfo.Method, "error", err)
return
}
}
if v.res == nil {
v.logger.Trace("got nil resource information after decorating auth parameters")
return
v.act = opts.withAction
v.res = &perms.Resource{
ScopeId: opts.withScopeId,
Id: opts.withId,
Pin: opts.withPin,
Type: opts.withType,
}
var authResults *perms.ACLResults
@@ -192,229 +177,6 @@ func Verify(ctx context.Context, opt ...Option) (ret VerifyResults) {
return
}
func (v *verifier) parseAuthParams() error {
// Remove trailing and leading slashes
trimmedPath := strings.Trim(v.requestInfo.Path, "/")
// Remove `v1/`
splitPath := strings.Split(strings.TrimPrefix(trimmedPath, "v1/"), "/")
splitLen := len(splitPath)
// It must be at least length 1. If so, figure out new vs. legacy parsing
if len(splitPath) == 0 {
return fmt.Errorf("parse auth params: invalid path")
}
for i := 1; i < splitLen; i++ {
if splitPath[i] == "" {
return fmt.Errorf("parse auth params: empty segment found")
}
}
// The first segment must be "scopes"
if splitPath[0] != "scopes" {
return fmt.Errorf("parse auth params: invalid first segment %q", splitPath[0])
}
v.act = action.Unknown
v.res = &perms.Resource{
// Start out with scope, and replace when we walk backwards if it's
// actually something else
Type: resource.Scope,
}
// Handle non-custom types. We'll deal with custom types, including list,
// after parsing the path.
switch v.requestInfo.Method {
case "GET":
v.act = action.Read
case "POST":
v.act = action.Create
case "PATCH":
v.act = action.Update
case "DELETE":
v.act = action.Delete
default:
return fmt.Errorf("parse auth params: unknown method %q", v.requestInfo.Method)
}
// Look for a custom action
colonSplit := strings.Split(splitPath[splitLen-1], ":")
switch len(colonSplit) {
case 1:
// No custom action specified
case 2:
// Parse and validate the action, then elide it
actStr := colonSplit[len(colonSplit)-1]
v.act = action.Map[actStr]
if v.act == action.Unknown || v.act == action.All {
return fmt.Errorf("parse auth params: unknown action %q", actStr)
}
// Keep going with the logic without the custom action
splitPath[splitLen-1] = colonSplit[0]
default:
return fmt.Errorf("parse auth params: unexpected number of colons in last segment %q", colonSplit[len(colonSplit)-1])
}
// Get scope information and handle it in a special case; that is, for
// operating on scopes, scope from the request ID, not the path scope
switch splitLen {
case 1:
// We've already validated that this is "scopes"
if v.act == action.Read {
v.act = action.List
}
if v.requestInfo.scopeId == "" {
return errors.New("parse auth params: missing scope ID information for scopes collection operation")
}
v.res.ScopeId = v.requestInfo.scopeId
return nil
case 2:
id := splitPath[1]
// The next segment should be the scope ID, but it takes place not in
// its own scope but in the parent scope. Rather than require the user
// to provide it, look up the parent.
switch {
case id == "global", strings.HasPrefix(id, scope.Org.Prefix()):
// Org scope parent is always global. Set scope for global
// operations to global as well (it's basically acting as its own
// parent scope). We want this so that users can e.g. modify the
// name or description of the global scope if they have permissions
// in the scope.
v.res.ScopeId = "global"
default:
// Project case
iamRepo, err := v.iamRepoFn()
if err != nil {
return fmt.Errorf("perform auth check: failed to get iam repo: %w", err)
}
scp, err := iamRepo.LookupScope(v.ctx, id)
if err != nil {
return fmt.Errorf("perform auth check: failed to lookup scope: %w", err)
}
if scp == nil {
return fmt.Errorf("perform auth check: non-existent scope %q", id)
}
v.res.ScopeId = scp.GetParentId()
}
v.res.Id = id
return nil
case 3:
// If a custom action was being performed within a scope, it will have
// been elided above. If the last path segment is now empty, address
// this scenario. In this case the action took place _in_ the scope so
// it should be bound accordingly. (This is for actions like
// /scopes/o_abc/:deauthenticate where the action is _in_ the scope, not
// on the scope.)
if splitPath[2] == "" {
v.res.ScopeId = splitPath[1]
v.res.Id = splitPath[1]
return nil
}
fallthrough
default:
// In all other cases the scope ID is the next segment
v.res.ScopeId = splitPath[1]
}
// Walk backwards. As we walk backwards we look for a pin and figure out if
// we're operating on a resource or a collection. The rules for the pin are
// as follows:
//
// * If the last segment is a collection, the pin is the immediately
// preceding ID. This does not include scopes since those are permission
// boundaries.
//
// * If the last segment is an ID, the pin is the immediately preceding ID
// not including the last segment
//
// * If at the end of the logic the pin is the id of a scope then there is
// no pin. The scopes are already enclosing so a pin is redundant.
nextIdIsPin := true
// Use an empty string so we can detect if we found anything in this loop.
var foundId string
var typStr string
// We stop at [2] because we've already dealt with the first two segments
// (scopes/<scope_id> above.
for i := splitLen - 1; i >= 2; i-- {
segment := splitPath[i]
if segment == "" {
return fmt.Errorf("parse auth parameters: unexpected empty segment")
}
// If the segment contains whitespace, it's not valid
if fields := strings.Fields(segment); len(fields) != 1 || fields[0] != segment {
return fmt.Errorf("parse auth params: segment %q contains whitespace", segment)
}
// Collections don't contain underscores; every resource ID does.
segmentIsCollection := !strings.Contains(segment, "_")
// If we see an ID, ensure that it's not the right-most ID; if not, it's
// the pin
if !segmentIsCollection && i != splitLen-1 && nextIdIsPin {
v.res.Pin = segment
// By definition this is the last thing we'd be looking for as
// scopes were found above, so we can now break out
break
}
if typStr == "" {
// The resource check takes place inside the type check because if
// we've identified the type we have either already identified the
// right-most resource ID or we're operating on a collection, so
// this prevents us from finding a different ID earlier in the path.
// We still work backwards to identify a pin.
if foundId == "" && !segmentIsCollection {
foundId = segment
} else {
// Every collection is the plural of the resource type so drop
// the last 's'
if !strings.HasSuffix(segment, "s") {
return fmt.Errorf("parse auth params: invalid collection syntax for %q", segment)
}
typStr = strings.TrimSuffix(segment, "s")
}
}
}
if foundId != "" {
v.res.Id = foundId
}
if typStr != "" {
v.res.Type = resource.Map[typStr]
if v.res.Type == resource.Unknown {
return fmt.Errorf("parse auth params: unknown resource type %q", typStr)
}
} else {
// If we found no other type information, we walked backwards all the
// way to the scope boundary, so the type is scope
v.res.Type = resource.Scope
}
// If we're operating on a collection (that is, the ID is blank) and it's a
// GET, it's actually a list
if v.res.Id == "" && v.act == action.Read {
v.act = action.List
}
// If the pin ended up being a scope, nil it out
if v.res.Pin != "" && v.res.Pin == v.res.ScopeId {
v.res.Pin = ""
}
return nil
}
func (v verifier) performAuthCheck() (aclResults *perms.ACLResults, userId string, scopeInfo *scopes.ScopeInfo, retErr error) {
// Ensure we return an error by default if we forget to set this somewhere
retErr = errors.New("unknown")
-252
View File
@@ -13,263 +13,11 @@ import (
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/servers"
"github.com/hashicorp/boundary/internal/servers/controller/handlers"
"github.com/hashicorp/boundary/internal/types/action"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/go-hclog"
"github.com/kr/pretty"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestHandler_AuthDecoration(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
wrapper := db.TestWrapper(t)
iamRepo := iam.TestRepo(t, conn, wrapper)
iamRepoFn := func() (*iam.Repository, error) {
return iamRepo, nil
}
org, proj := iam.TestScopes(t, iamRepo)
cases := []struct {
name string
path string
method string
action action.Type
scope string
resource resource.Type
id string
pin string
wantErrContains string
}{
{
name: "global scope, read, with id",
path: "/v1/scopes/global/users/u_anon",
method: "GET",
action: action.Read,
scope: "global",
resource: resource.User,
id: "u_anon",
},
{
name: "global scope, update, with id",
path: "/v1/scopes/global/auth-methods/am_1234",
method: "PATCH",
action: action.Update,
scope: "global",
resource: resource.AuthMethod,
id: "am_1234",
},
{
name: "global scope, delete org",
path: "/v1/scopes/o_1234",
method: "DELETE",
action: action.Delete,
scope: "global",
resource: resource.Scope,
id: "o_1234",
},
{
name: "org scope, delete project",
path: fmt.Sprintf("/v1/scopes/%s", proj.GetPublicId()),
method: "DELETE",
action: action.Delete,
scope: org.GetPublicId(),
resource: resource.Scope,
id: proj.GetPublicId(),
},
{
name: "empty segments",
path: "/v1/scopes/o_abc1234/auth-methods//am_1234",
wantErrContains: "empty segment found",
},
{
name: "global scope, create",
path: "/v1/scopes/global/roles",
method: "POST",
action: action.Create,
scope: "global",
resource: resource.Role,
},
{
name: "global, invalid collection syntax",
path: "/v1/scope",
wantErrContains: `parse auth params: invalid first segment "scope"`,
},
{
name: "invalid scopes segment with id",
path: "/v1/scope/o_abc",
wantErrContains: `parse auth params: invalid first segment "scope"`,
},
{
name: "org, custom action",
path: "/v1/scopes/o_123/auth-methods/am_1234:authenticate",
method: "POST",
action: action.Authenticate,
scope: "o_123",
resource: resource.AuthMethod,
id: "am_1234",
},
{
name: "unknown action in first segment",
path: "/v1/:authentifake",
wantErrContains: `parse auth params: invalid first segment ":authentifake"`,
},
{
name: "root, unknown action",
path: "/v1/scopes/o_abc/:authentifake",
wantErrContains: `parse auth params: unknown action "authentifake"`,
},
{
name: "root, unknown empty action",
path: "/v1/:",
wantErrContains: `parse auth params: invalid first segment ":"`,
},
{
name: "root, invalid method",
path: "/v1/scopes/o_abc/:authenticate",
method: "FOOBAR",
wantErrContains: `unknown method "FOOBAR"`,
},
{
name: "root, wrong number of colons",
path: "/v1/scopes/o_abc/:auth:enticate",
wantErrContains: "unexpected number of colons",
},
{
name: "root, action on global",
path: "/v1/scopes/global",
method: "GET",
action: action.Read,
scope: "global",
resource: resource.Scope,
id: "global",
},
{
name: "org scope, valid",
path: "/v1/scopes/o_abc123/auth-methods",
method: "POST",
action: action.Create,
scope: "o_abc123",
resource: resource.AuthMethod,
},
{
name: "project scope, valid",
path: "/v1/scopes/p_1234/host-catalogs",
method: "POST",
action: action.Create,
scope: "p_1234",
resource: resource.HostCatalog,
},
{
name: "project scope, action on project",
path: "/v1/scopes/p_1234/:deauthenticate",
method: "POST",
action: action.Deauthenticate,
scope: "p_1234",
resource: resource.Scope,
id: "p_1234",
},
{
name: "global scope, action on org, token scope",
path: "/v1/scopes/o_1234:set-principals",
method: "POST",
action: action.SetPrincipals,
scope: "global",
resource: resource.Scope,
id: "o_1234",
},
{
name: "global action, valid",
path: "/v1/scopes/global/:read",
action: action.Read,
scope: "global",
resource: resource.Scope,
id: "global",
},
{
name: "top level, invalid",
path: "/v1/",
wantErrContains: `invalid first segment "v1"`,
},
{
name: "non-api path",
path: "/",
wantErrContains: `parse auth params: invalid first segment ""`,
},
{
name: "project scope, pinning collection",
path: "/v1/scopes/p_1234/host-catalogs/hc_1234/host-sets",
action: action.List,
scope: "p_1234",
pin: "hc_1234",
resource: resource.HostSet,
},
{
name: "project scope, pinning collection, custom action",
path: "/v1/scopes/p_1234/host-catalogs/hc_1234/host-sets:create",
action: action.Create,
scope: "p_1234",
pin: "hc_1234",
resource: resource.HostSet,
},
{
name: "project scope, pinning id",
path: "/v1/scopes/p_1234/host-catalogs/hc_1234/host-sets/hs_abc",
action: action.Read,
id: "hs_abc",
scope: "p_1234",
pin: "hc_1234",
resource: resource.HostSet,
},
{
name: "project scope, pinning id, custom action",
path: "/v1/scopes/p_1234/host-catalogs/hc_1234/host-sets/hs_abc:update",
action: action.Update,
id: "hs_abc",
scope: "p_1234",
pin: "hc_1234",
resource: resource.HostSet,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
require, assert := require.New(t), assert.New(t)
if tc.method == "" {
tc.method = "GET"
}
req, err := http.NewRequest(tc.method, fmt.Sprintf("http://127.0.0.1:9200:%s", tc.path), nil)
require.NoError(err)
v := &verifier{
requestInfo: RequestInfo{
Path: req.URL.Path,
Method: tc.method,
},
iamRepoFn: iamRepoFn,
}
err = v.parseAuthParams()
if tc.wantErrContains != "" {
require.Error(err)
assert.Contains(err.Error(), tc.wantErrContains, err.Error())
return
}
require.NoError(err, pretty.Sprint(v))
if tc.path == "/" {
return
}
require.NotNil(v.res)
require.NotEqual(action.Unknown, v.act)
assert.Equal(tc.scope, v.res.ScopeId, "scope "+pretty.Sprint(v))
assert.Equal(tc.action, v.act, "action "+pretty.Sprint(v))
assert.Equal(tc.resource, v.res.Type, "type "+pretty.Sprint(v))
assert.Equal(tc.id, v.res.Id, "id "+pretty.Sprint(v))
assert.Equal(tc.pin, v.res.Pin, "pin "+pretty.Sprint(v))
})
}
}
func TestAuthTokenAuthenticator(t *testing.T) {
conn, _ := db.TestSetup(t, "postgres")
rw := db.New(conn)
@@ -288,7 +288,7 @@ func TestRepository_ChangePassword(t *testing.T) {
wantIsErr: db.ErrInvalidParameter,
},
{
name: "invalid-no-old-password",
name: "invalid-no-current-password",
args: args{
acctId: acct.PublicId,
old: "",
@@ -325,7 +325,7 @@ func TestRepository_ChangePassword(t *testing.T) {
wantIsErr: db.ErrRecordNotFound,
},
{
name: "auth-failure-wrong-old-password",
name: "auth-failure-wrong-current-password",
args: args{
acctId: acct.PublicId,
old: "wrong-password",
@@ -455,13 +455,13 @@ func TestRepository_SetPassword(t *testing.T) {
createAcct func(string) *Account
}{
{
name: "valid-new-password-no-old-password",
name: "valid-new-password-no-current-password",
createAcct: createAccount("validnewpwnoold"),
oldPw: "",
newPw: "abcdefghijk",
},
{
name: "valid-new-password-delete-old-password",
name: "valid-new-password-delete-current-password",
createAcct: createAccount("validnewpwyesold"),
oldPw: origPasswd,
newPw: "abcdefghijk",
+1 -37
View File
@@ -53,7 +53,6 @@ type Command struct {
flagsOnce sync.Once
flagAddr string
flagScope string
flagVerbose bool
flagTLSCACert string
@@ -69,6 +68,7 @@ type Command struct {
FlagRecoveryConfig string
flagOutputCurlString bool
FlagScopeId string
FlagId string
FlagName string
FlagDescription string
@@ -233,39 +233,12 @@ func (c *Command) Client(opt ...Option) (*api.Client, error) {
c.UI.Error(fmt.Sprintf("Error unmarshaling stored token information after reading from system credential store: %s", err))
} else {
c.client.SetToken(authToken.Token)
if !opts.withNoTokenScope {
c.client.SetScopeId(authToken.Scope.Id)
}
}
}
}
}
}
// We do this here so we override the stored token info if it's set above
if c.flagScope != NotSetValue {
c.client.SetScopeId(c.flagScope)
if c.flagFormat == "table" && c.flagVerbose {
if c.flagScope == os.Getenv("BOUNDARY_TOKEN") {
c.UI.Info(fmt.Sprintf("Scope of %q set from BOUNDARY_TOKEN env var", c.flagScope))
} else {
c.UI.Info(fmt.Sprintf("Scope of %q set from -scope command flag", c.flagScope))
}
}
} else if c.client.ScopeId() != "" && !opts.withNoTokenScope {
// If it didn't come from env or a flag but isn't empty, it must have come from the token
if c.flagFormat == "table" && c.flagVerbose {
c.UI.Info(fmt.Sprintf("Scope of %q set from saved token with name %q", c.client.ScopeId(), tokenName))
}
}
// At this point if we haven't figured out the scope, default to "global"
if c.client.ScopeId() == "" {
c.client.SetScopeId("global")
if c.flagFormat == "table" && c.flagVerbose {
c.UI.Info(`Scope of "global" set by default`)
}
}
if opts.withNoTokenValue {
c.client.SetToken("")
}
@@ -300,15 +273,6 @@ func (c *Command) FlagSet(bit FlagSetBit) *FlagSets {
Usage: "Addr of the Boundary controller, as a complete URL (e.g. https://boundary.example.com:9200).",
})
f.StringVar(&StringVar{
Name: FlagNameScope,
Target: &c.flagScope,
Default: NotSetValue,
EnvVar: api.EnvBoundaryScopeId,
Completion: complete.PredictAnything,
Usage: `Scope in which to make the request. If not specified, will default to the scope of a saved token (if found), otherwise will default to "global".`,
})
f.StringVar(&StringVar{
Name: FlagNameCACert,
Target: &c.flagTLSCACert,
-3
View File
@@ -4,9 +4,6 @@ const (
// FlagNameAddr is the flag used in the base command to read in the
// address of the Boundary server.
FlagNameAddr = "addr"
// FlagNameScope is the flag used in the base command to read in the scope
// in which to make a request.
FlagNameScope = "scope"
// FlagnameCACert is the flag used in the base command to read in the CA
// cert.
FlagNameCACert = "ca-cert"
+1 -1
View File
@@ -51,7 +51,7 @@ func WrapSlice(prefixSpaces int, input []string) string {
for _, v := range input {
ret = append(ret, fmt.Sprintf("%s%s",
strings.Repeat(" ", prefixSpaces),
fmt.Sprintf("%s: ", v),
v,
))
}
+172 -2
View File
@@ -6,6 +6,7 @@ import (
"syscall"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/commands/accounts"
"github.com/hashicorp/boundary/internal/cmd/commands/authenticate"
"github.com/hashicorp/boundary/internal/cmd/commands/authmethods"
"github.com/hashicorp/boundary/internal/cmd/commands/authtokens"
@@ -19,6 +20,7 @@ import (
"github.com/hashicorp/boundary/internal/cmd/commands/proxy"
"github.com/hashicorp/boundary/internal/cmd/commands/roles"
"github.com/hashicorp/boundary/internal/cmd/commands/scopes"
"github.com/hashicorp/boundary/internal/cmd/commands/targets"
"github.com/hashicorp/boundary/internal/cmd/commands/users"
"github.com/hashicorp/boundary/internal/cmd/commands/worker"
@@ -77,6 +79,66 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
}, nil
},
"accounts": func() (cli.Command, error) {
return &accounts.Command{
Command: base.NewCommand(ui),
}, nil
},
"accounts read": func() (cli.Command, error) {
return &accounts.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"accounts delete": func() (cli.Command, error) {
return &accounts.Command{
Command: base.NewCommand(ui),
Func: "delete",
}, nil
},
"accounts list": func() (cli.Command, error) {
return &accounts.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
},
"accounts set-password": func() (cli.Command, error) {
return &accounts.Command{
Command: base.NewCommand(ui),
Func: "set-password",
}, nil
},
"accounts change-password": func() (cli.Command, error) {
return &accounts.Command{
Command: base.NewCommand(ui),
Func: "change-password",
}, nil
},
"accounts create": func() (cli.Command, error) {
return &accounts.Command{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"accounts create password": func() (cli.Command, error) {
return &accounts.PasswordCommand{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"accounts update": func() (cli.Command, error) {
return &accounts.Command{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"accounts update password": func() (cli.Command, error) {
return &accounts.PasswordCommand{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"auth-methods": func() (cli.Command, error) {
return &authmethods.Command{
Command: base.NewCommand(ui),
@@ -335,11 +397,53 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
}, nil
},
"hosts create": func() (cli.Command, error) {
return &hosts.CreateCommand{
"hosts": func() (cli.Command, error) {
return &hosts.Command{
Command: base.NewCommand(ui),
}, nil
},
"hosts read": func() (cli.Command, error) {
return &hosts.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"hosts delete": func() (cli.Command, error) {
return &hosts.Command{
Command: base.NewCommand(ui),
Func: "delete",
}, nil
},
"hosts list": func() (cli.Command, error) {
return &hosts.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
},
"hosts create": func() (cli.Command, error) {
return &hosts.Command{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"hosts create static": func() (cli.Command, error) {
return &hosts.StaticCommand{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"hosts update": func() (cli.Command, error) {
return &hosts.Command{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"hosts update static": func() (cli.Command, error) {
return &hosts.StaticCommand{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"roles": func() (cli.Command, error) {
return &roles.Command{
@@ -449,6 +553,72 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
}, nil
},
"targets": func() (cli.Command, error) {
return &targets.Command{
Command: base.NewCommand(ui),
}, nil
},
"targets read": func() (cli.Command, error) {
return &targets.Command{
Command: base.NewCommand(ui),
Func: "read",
}, nil
},
"targets delete": func() (cli.Command, error) {
return &targets.Command{
Command: base.NewCommand(ui),
Func: "delete",
}, nil
},
"targets list": func() (cli.Command, error) {
return &targets.Command{
Command: base.NewCommand(ui),
Func: "list",
}, nil
},
"targets create": func() (cli.Command, error) {
return &targets.Command{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"targets create tcp": func() (cli.Command, error) {
return &targets.TcpCommand{
Command: base.NewCommand(ui),
Func: "create",
}, nil
},
"targets update": func() (cli.Command, error) {
return &targets.Command{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"targets update tcp": func() (cli.Command, error) {
return &targets.TcpCommand{
Command: base.NewCommand(ui),
Func: "update",
}, nil
},
"targets add-host-sets": func() (cli.Command, error) {
return &targets.Command{
Command: base.NewCommand(ui),
Func: "add-host-sets",
}, nil
},
"targets remove-host-sets": func() (cli.Command, error) {
return &targets.Command{
Command: base.NewCommand(ui),
Func: "remove-host-sets",
}, nil
},
"targets set-host-sets": func() (cli.Command, error) {
return &targets.Command{
Command: base.NewCommand(ui),
Func: "set-host-sets",
}, nil
},
"users": func() (cli.Command, error) {
return &users.Command{
Command: base.NewCommand(ui),
+375
View File
@@ -0,0 +1,375 @@
package accounts
import (
"fmt"
"os"
"strings"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/accounts"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/vault/sdk/helper/password"
"github.com/hashicorp/vault/sdk/helper/strutil"
"github.com/kr/pretty"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var _ cli.Command = (*Command)(nil)
var _ cli.CommandAutocomplete = (*Command)(nil)
type Command struct {
*base.Command
Func string
flagAuthMethodId string
flagPassword string
flagCurrentPassword string
flagNewPassword string
}
func (c *Command) Synopsis() string {
switch c.Func {
case "create":
return "Create account resources within Boundary"
case "update":
return "Update account resources within Boundary"
default:
return common.SynopsisFunc(c.Func, "account")
}
}
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"auth-method-id"},
"set-password": {"id", "password", "version"},
"change-password": {"id", "current-password", "new-password", "version"},
}
func (c *Command) Help() string {
helpMap := common.HelpMap("account")
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary accounts [sub command] [options] [args]",
"",
" This command allows operations on Boundary account resources. Example:",
"",
" Read a account:",
"",
` $ boundary accounts read -id apw_1234567890`,
"",
" Please see the accounts subcommand help for detailed usage information.",
})
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary accounts create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary account resources. Example:",
"",
" Create a password-type account:",
"",
` $ boundary accounts create password -name prodops -description "For ProdOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary accounts update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary account resources. Example:",
"",
" Update a password-type account:",
"",
` $ boundary accounts update password -id apw_1234567890 -name devops -description "For DevOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "set-password":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary accounts set-password [sub command] [options] [args]",
"",
" This command allows setting the password on account-type resources, if the types match and the operation is allowed by the given account type. Example:",
"",
" Set the password on a password-type account:",
"",
` $ boundary accounts set-password -id apw_1234567890 -password <empty, to be read by stdin>`,
})
case "change-password":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary accounts change-password [sub command] [options] [args]",
"",
" This command allows changing the password (with verification of the current password) on account-type resources, if the types match and the operation is allowed by the given account type. Example:",
"",
" Change the password on a password-type account:",
"",
` $ boundary accounts change-password -id apw_1234567890 -current-password <empty, to be read by stdin> -new-password <empty, to be read by stdin>`,
})
default:
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
func (c *Command) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
if len(flagsMap[c.Func]) > 0 {
common.PopulateCommonFlags(c.Command, f, resource.Account.String(), flagsMap[c.Func])
}
for _, name := range flagsMap[c.Func] {
switch name {
case "auth-method-id":
f.StringVar(&base.StringVar{
Name: "auth-method-id",
Target: &c.flagAuthMethodId,
Usage: "The auth-method resource in which to create or update the account resource",
})
case "password":
f.StringVar(&base.StringVar{
Name: "password",
Target: &c.flagPassword,
Usage: "The password for the account. If not specified, the command will prompt for the password to be entered in a non-echoing way.",
})
case "current-password":
f.StringVar(&base.StringVar{
Name: "current-password",
Target: &c.flagCurrentPassword,
Usage: "The current password for the account. If not specified, the command will prompt for the password to be entered in a non-echoing way.",
})
case "new-password":
f.StringVar(&base.StringVar{
Name: "new-password",
Target: &c.flagNewPassword,
Usage: "The new password for the account. If not specified, the command will prompt for the password to be entered in a non-echoing way.",
})
}
}
return set
}
func (c *Command) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *Command) Run(args []string) int {
switch c.Func {
case "", "create", "update":
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "auth-method-id") && c.flagAuthMethodId == "" {
c.UI.Error("Auth Method ID must be passed in via -auth-method-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []accounts.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, accounts.DefaultName())
default:
opts = append(opts, accounts.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, accounts.DefaultDescription())
default:
opts = append(opts, accounts.WithDescription(c.FlagDescription))
}
if strutil.StrListContains(flagsMap[c.Func], "password") && c.flagPassword == "" {
fmt.Print("Password is not set as flag, please enter it now (will be hidden): ")
value, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
c.flagPassword = strings.TrimSpace(value)
}
if strutil.StrListContains(flagsMap[c.Func], "current-password") && c.flagCurrentPassword == "" {
fmt.Print("Current password is not set as flag, please enter it now (will be hidden): ")
value, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
c.flagCurrentPassword = strings.TrimSpace(value)
}
if strutil.StrListContains(flagsMap[c.Func], "new-password") && c.flagNewPassword == "" {
fmt.Print("New password is not set as flag, please enter it now (will be hidden): ")
value, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
c.flagNewPassword = strings.TrimSpace(value)
}
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "create":
// These don't update so don't need the existing version
default:
switch c.FlagVersion {
case 0:
opts = append(opts, accounts.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
accountClient := accounts.NewClient(client)
var existed bool
var account *accounts.Account
var listedAccounts []*accounts.Account
var apiErr *api.Error
switch c.Func {
case "read":
account, apiErr, err = accountClient.Read(c.Context, c.FlagId, opts...)
case "delete":
existed, apiErr, err = accountClient.Delete(c.Context, c.FlagId, opts...)
case "list":
listedAccounts, apiErr, err = accountClient.List(c.Context, c.flagAuthMethodId, opts...)
case "set-password":
account, apiErr, err = accountClient.SetPassword(c.Context, c.FlagId, c.flagPassword, version, opts...)
case "change-password":
account, apiErr, err = accountClient.ChangePassword(c.Context, c.FlagId, c.flagCurrentPassword, c.flagNewPassword, version, opts...)
}
plural := "account"
if c.Func == "list" {
plural = "accounts"
}
if err != nil {
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
if apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, pretty.Sprint(apiErr)))
return 1
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output("null")
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
switch base.Format(c.UI) {
case "json":
if len(listedAccounts) == 0 {
c.UI.Output("null")
return 0
}
b, err := base.JsonFormatter{}.Format(listedAccounts)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
case "table":
if len(listedAccounts) == 0 {
c.UI.Output("No accounts found")
return 0
}
var output []string
output = []string{
"",
"Account information:",
}
for i, m := range listedAccounts {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", m.Id),
fmt.Sprintf(" Version: %d", m.Version),
fmt.Sprintf(" Type: %s", m.Type),
)
}
if m.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", m.Name),
)
}
if m.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", m.Description),
)
}
}
c.UI.Output(base.WrapForHelpText(output))
}
return 0
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateAccountTableOutput(account))
case "json":
b, err := base.JsonFormatter{}.Format(account)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
+74
View File
@@ -0,0 +1,74 @@
package accounts
import (
"fmt"
"time"
"github.com/hashicorp/boundary/api/accounts"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func generateAccountTableOutput(in *accounts.Account) string {
var ret []string
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Scope ID": in.Scope.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC3339),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC3339),
"Auth Method ID": in.AuthMethodId,
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := 0
for k := range nonAttributeMap {
if len(k) > maxLength {
maxLength = len(k)
}
}
if len(in.Attributes) > 0 {
for k, v := range in.Attributes {
if attributeMap[k] != "" {
in.Attributes[attributeMap[k]] = v
delete(in.Attributes, k)
}
}
for k := range in.Attributes {
if len(k) > maxLength {
maxLength = len(k)
}
}
}
ret = append(ret, "", "Account information:")
ret = append(ret,
// We do +2 because there is another +2 offset for attributes below
base.WrapMap(2, maxLength+2, nonAttributeMap),
)
if len(in.Attributes) > 0 {
if true {
ret = append(ret,
fmt.Sprintf(" Attributes: %s", ""),
)
}
ret = append(ret,
base.WrapMap(4, maxLength, in.Attributes),
)
}
return base.WrapForHelpText(ret)
}
var attributeMap = map[string]string{
"login_name": "Login Name",
}
+242
View File
@@ -0,0 +1,242 @@
package accounts
import (
"fmt"
"net/textproto"
"os"
"strings"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/accounts"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/vault/sdk/helper/password"
"github.com/hashicorp/vault/sdk/helper/strutil"
"github.com/kr/pretty"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var _ cli.Command = (*PasswordCommand)(nil)
var _ cli.CommandAutocomplete = (*PasswordCommand)(nil)
type PasswordCommand struct {
*base.Command
Func string
flagAuthMethodId string
flagLoginName string
flagPassword string
}
func (c *PasswordCommand) Synopsis() string {
return fmt.Sprintf("%s a password-type account within Boundary", textproto.CanonicalMIMEHeaderKey(c.Func))
}
var passwordFlagsMap = map[string][]string{
"create": {"auth-method-id", "name", "description", "login-name", "password"},
"update": {"id", "name", "description", "version"},
}
func (c *PasswordCommand) Help() string {
var info string
switch c.Func {
case "create":
info = base.WrapForHelpText([]string{
"Usage: boundary accounts password create [options] [args]",
"",
" Create a password-type account. Example:",
"",
` $ boundary accounts password create -name prodops -description "Password account for ProdOps" -address "127.0.0.1"`,
"",
"",
})
case "update":
info = base.WrapForHelpText([]string{
"Usage: boundary accounts password update [options] [args]",
"",
" Update a password-type account given its ID. Example:",
"",
` $ boundary accounts password update -id hst_1234567890 -name "devops" -description "Password account for DevOps" -address "10.20.30.40"`,
"",
"",
})
}
return info + c.Flags().Help()
}
func (c *PasswordCommand) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
if len(passwordFlagsMap[c.Func]) > 0 {
common.PopulateCommonFlags(c.Command, f, "password-type account", passwordFlagsMap[c.Func])
}
for _, name := range passwordFlagsMap[c.Func] {
switch name {
case "auth-method-id":
f.StringVar(&base.StringVar{
Name: "auth-method-id",
Target: &c.flagAuthMethodId,
Usage: "The auth-method resource in which to create or update the account resource",
})
}
}
f = set.NewFlagSet("Password Account Options")
for _, name := range passwordFlagsMap[c.Func] {
switch name {
case "login-name":
f.StringVar(&base.StringVar{
Name: "login-name",
Target: &c.flagLoginName,
Usage: "The login name for the account",
})
case "password":
f.StringVar(&base.StringVar{
Name: "password",
Target: &c.flagPassword,
Usage: "The password for the account. If not specified, the command will prompt for the password to be entered in a non-echoing way.",
})
}
}
return set
}
func (c *PasswordCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *PasswordCommand) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *PasswordCommand) Run(args []string) int {
if c.Func == "" {
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(passwordFlagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(passwordFlagsMap[c.Func], "auth-method-id") && c.flagAuthMethodId == "" {
c.UI.Error("Auth Method ID must be passed in via -auth-method-id")
return 1
}
if c.Func == "create" && c.flagLoginName == "" {
c.UI.Error("Login Name must be passed in via -login-name")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []accounts.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, accounts.DefaultName())
default:
opts = append(opts, accounts.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, accounts.DefaultDescription())
default:
opts = append(opts, accounts.WithDescription(c.FlagDescription))
}
switch c.flagLoginName {
case "":
case "null":
opts = append(opts, accounts.DefaultPasswordAccountLoginName())
default:
opts = append(opts, accounts.WithPasswordAccountLoginName(c.flagLoginName))
}
if strutil.StrListContains(passwordFlagsMap[c.Func], "password") {
switch c.flagPassword {
case "":
fmt.Print("Password is not set as flag, please enter it now (will be hidden): ")
value, err := password.Read(os.Stdin)
fmt.Print("\n")
if err != nil {
c.UI.Error(fmt.Sprintf("An error occurred attempting to read the password. The raw error message is shown below but usually this is because you attempted to pipe a value into the command or you are executing outside of a terminal (TTY). The raw error was:\n\n%s", err.Error()))
return 2
}
opts = append(opts, accounts.WithPasswordAccountPassword(strings.TrimSpace(value)))
default:
opts = append(opts, accounts.WithPasswordAccountPassword(c.flagPassword))
}
}
accountClient := accounts.NewClient(client)
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "create":
// These don't update so don't need the existing version
default:
switch c.FlagVersion {
case 0:
opts = append(opts, accounts.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
var account *accounts.Account
var apiErr *api.Error
switch c.Func {
case "create":
account, apiErr, err = accountClient.Create(c.Context, c.flagAuthMethodId, opts...)
case "update":
account, apiErr, err = accountClient.Update(c.Context, c.FlagId, version, opts...)
}
plural := "password-type account"
if err != nil {
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
if apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, pretty.Sprint(apiErr)))
return 1
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateAccountTableOutput(account))
case "json":
b, err := base.JsonFormatter{}.Format(account)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
@@ -56,14 +56,14 @@ func (c *PasswordCommand) Flags() *base.FlagSets {
Name: "login-name",
Target: &c.flagLoginName,
EnvVar: envLoginName,
Usage: "Login name",
Usage: "The login name corresponding to an account within the given auth method",
})
f.StringVar(&base.StringVar{
Name: "password",
Target: &c.flagPassword,
EnvVar: envPassword,
Usage: "Password",
Usage: "The password associated with the login name",
})
f.StringVar(&base.StringVar{
@@ -121,7 +121,11 @@ func (c *PasswordCommand) Run(args []string) int {
// note: Authenticate() calls SetToken() under the hood to set the
// auth bearer on the client so we do not need to do anything with the
// returned token after this call, so we ignore it
result, apiErr, err := authmethods.NewClient(client).Authenticate(c.Context, c.flagAuthMethodId, c.flagLoginName, c.flagPassword)
result, apiErr, err := authmethods.NewClient(client).Authenticate(c.Context, c.flagAuthMethodId,
map[string]interface{}{
"login_name": c.flagLoginName,
"password": c.flagPassword,
})
if err != nil {
c.UI.Error(fmt.Sprintf("Error trying to perform authentication: %s", err.Error()))
return 2
@@ -37,10 +37,12 @@ func (c *Command) Synopsis() string {
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"scope-id"},
}
func (c *Command) Help() string {
helpMap := common.HelpMap("auth-method")
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
@@ -55,7 +57,7 @@ func (c *Command) Help() string {
" Please see the auth-methods subcommand help for detailed usage information.",
})
case "create":
return base.WrapForHelpText([]string{
helpStr = base.WrapForHelpText([]string{
"Usage: boundary auth-methods create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary auth-method resources. Example:",
@@ -67,7 +69,7 @@ func (c *Command) Help() string {
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
return base.WrapForHelpText([]string{
helpStr = base.WrapForHelpText([]string{
"Usage: boundary auth-methods update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary auth-method resources. Example:",
@@ -79,8 +81,9 @@ func (c *Command) Help() string {
" Please see the typed subcommand help for detailed usage information.",
})
default:
return helpMap[c.Func]() + c.Flags().Help()
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
func (c *Command) Flags() *base.FlagSets {
@@ -119,6 +122,10 @@ func (c *Command) Run(args []string) int {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
@@ -157,7 +164,7 @@ func (c *Command) Run(args []string) int {
case "delete":
existed, apiErr, err = authmethodClient.Delete(c.Context, c.FlagId, opts...)
case "list":
listedMethods, apiErr, err = authmethodClient.List(c.Context, opts...)
listedMethods, apiErr, err = authmethodClient.List(c.Context, c.FlagScopeId, opts...)
}
plural := "auth method"
@@ -26,6 +26,7 @@ func generateAuthMethodTableOutput(in *authmethods.AuthMethod) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Scope ID": in.Scope.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC3339),
@@ -32,7 +32,7 @@ func (c *PasswordCommand) Synopsis() string {
}
var passwordFlagsMap = map[string][]string{
"create": {"name", "description"},
"create": {"scope-id", "name", "description"},
"update": {"id", "name", "description", "version"},
}
@@ -102,6 +102,10 @@ func (c *PasswordCommand) Run(args []string) int {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(passwordFlagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
@@ -174,7 +178,7 @@ func (c *PasswordCommand) Run(args []string) int {
default:
switch c.FlagVersion {
case 0:
opts = append(opts, authmethods.WithAutomaticVersioning())
opts = append(opts, authmethods.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
@@ -185,7 +189,7 @@ func (c *PasswordCommand) Run(args []string) int {
switch c.Func {
case "create":
method, apiErr, err = authmethodClient.Create(c.Context, "password", opts...)
method, apiErr, err = authmethodClient.Create(c.Context, "password", c.FlagScopeId, opts...)
case "update":
method, apiErr, err = authmethodClient.Update(c.Context, c.FlagId, version, opts...)
}
@@ -31,6 +31,7 @@ func (c *Command) Synopsis() string {
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"scope-id"},
}
func (c *Command) Help() string {
@@ -76,6 +77,10 @@ func (c *Command) Run(args []string) int {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
@@ -96,7 +101,7 @@ func (c *Command) Run(args []string) int {
case "delete":
existed, apiErr, err = authtokenClient.Delete(c.Context, c.FlagId)
case "list":
listedTokens, apiErr, err = authtokenClient.List(c.Context)
listedTokens, apiErr, err = authtokenClient.List(c.Context, c.FlagScopeId)
}
plural := "auth token"
+1
View File
@@ -75,6 +75,7 @@ func generateGroupTableOutput(in *groups.Group) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Scope ID": in.Scope.Id,
"Version": in.Version,
"Created Time": in.CreatedTime.Local().Format(time.RFC3339),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC3339),
+9 -4
View File
@@ -43,10 +43,11 @@ var helpMap = func() map[string]func() string {
}
var flagsMap = map[string][]string{
"create": {"name", "description"},
"create": {"scope-id", "name", "description"},
"update": {"id", "name", "description", "version"},
"read": {"id"},
"delete": {"id"},
"list": {"scope-id"},
"add-members": {"id", "member", "version"},
"set-members": {"id", "member", "version"},
"remove-members": {"id", "member", "version"},
@@ -95,6 +96,10 @@ func (c *Command) Run(args []string) int {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
@@ -151,7 +156,7 @@ func (c *Command) Run(args []string) int {
default:
switch c.FlagVersion {
case 0:
opts = append(opts, groups.WithAutomaticVersioning())
opts = append(opts, groups.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
@@ -164,7 +169,7 @@ func (c *Command) Run(args []string) int {
switch c.Func {
case "create":
group, apiErr, err = groupClient.Create(c.Context, opts...)
group, apiErr, err = groupClient.Create(c.Context, c.FlagScopeId, opts...)
case "update":
group, apiErr, err = groupClient.Update(c.Context, c.FlagId, version, opts...)
case "read":
@@ -172,7 +177,7 @@ func (c *Command) Run(args []string) int {
case "delete":
existed, apiErr, err = groupClient.Delete(c.Context, c.FlagId, opts...)
case "list":
listedGroups, apiErr, err = groupClient.List(c.Context, opts...)
listedGroups, apiErr, err = groupClient.List(c.Context, c.FlagScopeId, opts...)
case "add-members":
group, apiErr, err = groupClient.AddMembers(c.Context, c.FlagId, version, members, opts...)
case "set-members":
+5 -6
View File
@@ -13,6 +13,7 @@ func generateHostCatalogTableOutput(in *hostcatalogs.HostCatalog) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Scope ID": in.Scope.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC3339),
@@ -54,12 +55,8 @@ func generateHostCatalogTableOutput(in *hostcatalogs.HostCatalog) string {
)
if len(in.Attributes) > 0 {
if true {
ret = append(ret,
fmt.Sprintf(" Attributes: %s", ""),
)
}
ret = append(ret,
fmt.Sprintf(" Attributes: %s", ""),
base.WrapMap(4, maxLength, in.Attributes),
)
}
@@ -67,4 +64,6 @@ func generateHostCatalogTableOutput(in *hostcatalogs.HostCatalog) string {
return base.WrapForHelpText(ret)
}
var attributeMap = map[string]string{}
var attributeMap = map[string]string{
"address": "Address",
}
@@ -26,7 +26,7 @@ type Command struct {
func (c *Command) Synopsis() string {
switch c.Func {
case "create":
return "Create host-catalolg resources within Boundary"
return "Create host-catalog resources within Boundary"
case "update":
return "Update host-catalog resources within Boundary"
default:
@@ -37,10 +37,12 @@ func (c *Command) Synopsis() string {
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"scope-id"},
}
func (c *Command) Help() string {
helpMap := common.HelpMap("host-catalog")
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
@@ -55,7 +57,7 @@ func (c *Command) Help() string {
" Please see the host-catalogs subcommand help for detailed usage information.",
})
case "create":
return base.WrapForHelpText([]string{
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-catalogs create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary host-catalog resources. Example:",
@@ -67,7 +69,7 @@ func (c *Command) Help() string {
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
return base.WrapForHelpText([]string{
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-catalogs update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary host-catalog resources. Example:",
@@ -79,8 +81,9 @@ func (c *Command) Help() string {
" Please see the typed subcommand help for detailed usage information.",
})
default:
return helpMap[c.Func]() + c.Flags().Help()
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
func (c *Command) Flags() *base.FlagSets {
@@ -119,6 +122,10 @@ func (c *Command) Run(args []string) int {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
@@ -157,7 +164,7 @@ func (c *Command) Run(args []string) int {
case "delete":
existed, apiErr, err = hostcatalogClient.Delete(c.Context, c.FlagId, opts...)
case "list":
listedCatalogs, apiErr, err = hostcatalogClient.List(c.Context, opts...)
listedCatalogs, apiErr, err = hostcatalogClient.List(c.Context, c.FlagScopeId, opts...)
}
plural := "host catalog"
+7 -3
View File
@@ -28,7 +28,7 @@ func (c *StaticCommand) Synopsis() string {
}
var staticFlagsMap = map[string][]string{
"create": {"name", "description"},
"create": {"scope-id", "name", "description"},
"update": {"id", "name", "description", "version"},
}
@@ -95,6 +95,10 @@ func (c *StaticCommand) Run(args []string) int {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(staticFlagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
@@ -130,7 +134,7 @@ func (c *StaticCommand) Run(args []string) int {
default:
switch c.FlagVersion {
case 0:
opts = append(opts, hostcatalogs.WithAutomaticVersioning())
opts = append(opts, hostcatalogs.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
@@ -141,7 +145,7 @@ func (c *StaticCommand) Run(args []string) int {
switch c.Func {
case "create":
catalog, apiErr, err = hostcatalogClient.Create(c.Context, "static", opts...)
catalog, apiErr, err = hostcatalogClient.Create(c.Context, "static", c.FlagScopeId, opts...)
case "update":
catalog, apiErr, err = hostcatalogClient.Update(c.Context, c.FlagId, version, opts...)
}
+75
View File
@@ -0,0 +1,75 @@
package hosts
import (
"fmt"
"time"
"github.com/hashicorp/boundary/api/hosts"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func generateHostTableOutput(in *hosts.Host) string {
var ret []string
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Scope ID": in.Scope.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC3339),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC3339),
"Host Catalog ID": in.HostCatalogId,
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := 0
for k := range nonAttributeMap {
if len(k) > maxLength {
maxLength = len(k)
}
}
if len(in.Attributes) > 0 {
for k, v := range in.Attributes {
if attributeMap[k] != "" {
in.Attributes[attributeMap[k]] = v
delete(in.Attributes, k)
}
}
for k := range in.Attributes {
if len(k) > maxLength {
maxLength = len(k)
}
}
}
ret = append(ret, "", "Host information:")
ret = append(ret,
// We do +2 because there is another +2 offset for attributes below
base.WrapMap(2, maxLength+2, nonAttributeMap),
)
if len(in.HostSetIds) > 0 {
ret = append(ret,
" Host Set IDs:",
base.WrapSlice(4, in.HostSetIds),
)
}
if len(in.Attributes) > 0 {
ret = append(ret,
fmt.Sprintf(" Attributes: %s", ""),
base.WrapMap(4, maxLength, in.Attributes),
)
}
return base.WrapForHelpText(ret)
}
var attributeMap = map[string]string{}
+278
View File
@@ -0,0 +1,278 @@
package hosts
import (
"fmt"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hosts"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/vault/sdk/helper/strutil"
"github.com/kr/pretty"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var _ cli.Command = (*Command)(nil)
var _ cli.CommandAutocomplete = (*Command)(nil)
type Command struct {
*base.Command
Func string
flagHostCatalogId string
}
func (c *Command) Synopsis() string {
switch c.Func {
case "create":
return "Create host resources within Boundary"
case "update":
return "Update host resources within Boundary"
default:
return common.SynopsisFunc(c.Func, "host")
}
}
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"host-catalog-id"},
}
func (c *Command) Help() string {
helpMap := common.HelpMap("host")
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary hosts [sub command] [options] [args]",
"",
" This command allows operations on Boundary host resources. Example:",
"",
" Read a host:",
"",
` $ boundary hosts read -id hst_1234567890`,
"",
" Please see the hosts subcommand help for detailed usage information.",
})
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary hosts create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary host resources. Example:",
"",
" Create a static-type host:",
"",
` $ boundary hosts create static -name prodops -description "For ProdOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary hosts update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary host resources. Example:",
"",
" Update a static-type host:",
"",
` $ boundary hosts update static -id hst_1234567890 -name devops -description "For DevOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
default:
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
func (c *Command) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
if len(flagsMap[c.Func]) > 0 {
common.PopulateCommonFlags(c.Command, f, resource.Host.String(), flagsMap[c.Func])
}
for _, name := range flagsMap[c.Func] {
switch name {
case "host-catalog-id":
f.StringVar(&base.StringVar{
Name: "host-catalog-id",
Target: &c.flagHostCatalogId,
Usage: "The host-catalog resource in which to create or update the host resource",
})
}
}
return set
}
func (c *Command) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *Command) Run(args []string) int {
switch c.Func {
case "", "create", "update":
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "host-catalog-id") && c.flagHostCatalogId == "" {
c.UI.Error("Host Catalog ID must be passed in via -host-catalog-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []hosts.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, hosts.DefaultName())
default:
opts = append(opts, hosts.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, hosts.DefaultDescription())
default:
opts = append(opts, hosts.WithDescription(c.FlagDescription))
}
hostClient := hosts.NewClient(client)
var existed bool
var host *hosts.Host
var listedHosts []*hosts.Host
var apiErr *api.Error
switch c.Func {
case "read":
host, apiErr, err = hostClient.Read(c.Context, c.FlagId, opts...)
case "delete":
existed, apiErr, err = hostClient.Delete(c.Context, c.FlagId, opts...)
case "list":
listedHosts, apiErr, err = hostClient.List(c.Context, c.flagHostCatalogId, opts...)
}
plural := "host"
if c.Func == "list" {
plural = "hosts"
}
if err != nil {
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
if apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, pretty.Sprint(apiErr)))
return 1
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output("null")
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
switch base.Format(c.UI) {
case "json":
if len(listedHosts) == 0 {
c.UI.Output("null")
return 0
}
b, err := base.JsonFormatter{}.Format(listedHosts)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
case "table":
if len(listedHosts) == 0 {
c.UI.Output("No hosts found")
return 0
}
var output []string
output = []string{
"",
"Host information:",
}
for i, m := range listedHosts {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", m.Id),
fmt.Sprintf(" Version: %d", m.Version),
fmt.Sprintf(" Type: %s", m.Type),
)
}
if m.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", m.Name),
)
}
if m.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", m.Description),
)
}
}
c.UI.Output(base.WrapForHelpText(output))
}
return 0
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateHostTableOutput(host))
case "json":
b, err := base.JsonFormatter{}.Format(host)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
-131
View File
@@ -1,131 +0,0 @@
package hosts
import (
"fmt"
"strings"
"github.com/hashicorp/boundary/api/hosts"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/kr/pretty"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var _ cli.Command = (*CreateCommand)(nil)
var _ cli.CommandAutocomplete = (*CreateCommand)(nil)
type CreateCommand struct {
*base.Command
flagAddress string
flagName string
flagCatalogId string
flagDescription string
}
func (c *CreateCommand) Synopsis() string {
return "Creates a host in the given host catalog"
}
func (c *CreateCommand) Help() string {
helpText := `
Usage: boundary hosts create
Creates a host in the given host catalog. This command will result in an
error for any catalog that does not support manual host creation.
Example:
$ boundary hosts create -catalog-id=<id> -address=<addr> -name=<name>
` + c.Flags().Help()
return strings.TrimSpace(helpText)
}
func (c *CreateCommand) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
f.StringVar(&base.StringVar{
Name: "address",
Target: &c.flagAddress,
Completion: complete.PredictAnything,
Usage: "The host's address; can be an IP address or DNS name",
})
f.StringVar(&base.StringVar{
Name: "name",
Target: &c.flagName,
Completion: complete.PredictAnything,
Usage: "An optional name assigned to the host for display purposes",
})
f.StringVar(&base.StringVar{
Name: "catalog-id",
Target: &c.flagCatalogId,
Completion: complete.PredictAnything,
Usage: "The ID of the host catalog in which the host should be created",
})
f.StringVar(&base.StringVar{
Name: "description",
Target: &c.flagDescription,
Completion: complete.PredictNothing,
Usage: "An optional description assigned to the host for display purposes",
})
return set
}
func (c *CreateCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *CreateCommand) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *CreateCommand) Run(args []string) int {
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
switch {
case c.flagCatalogId == "":
c.UI.Error("Catalog ID must be provided via -catalog-id")
return 1
case c.flagAddress == "":
c.UI.Error("Host address must be provided via -address")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(err.Error())
return 2
}
host, apiErr, err := hosts.NewClient(client).Create(c.Context,
c.flagCatalogId,
hosts.WithStaticHostAddress(c.flagAddress),
hosts.WithName(c.flagName),
hosts.WithDescription(c.flagDescription))
switch {
case err != nil:
c.UI.Error(fmt.Errorf("error creating host: %w", err).Error())
return 2
case apiErr != nil:
c.UI.Error(pretty.Sprint(apiErr))
return 2
default:
c.UI.Info(pretty.Sprint(host))
}
return 0
}
+216
View File
@@ -0,0 +1,216 @@
package hosts
import (
"fmt"
"net/textproto"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/hosts"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/vault/sdk/helper/strutil"
"github.com/kr/pretty"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var _ cli.Command = (*StaticCommand)(nil)
var _ cli.CommandAutocomplete = (*StaticCommand)(nil)
type StaticCommand struct {
*base.Command
Func string
flagHostCatalogId string
flagAddress string
}
func (c *StaticCommand) Synopsis() string {
return fmt.Sprintf("%s a static-type host within Boundary", textproto.CanonicalMIMEHeaderKey(c.Func))
}
var staticFlagsMap = map[string][]string{
"create": {"host-catalog-id", "name", "description", "address"},
"update": {"id", "name", "description", "version", "address"},
}
func (c *StaticCommand) Help() string {
var info string
switch c.Func {
case "create":
info = base.WrapForHelpText([]string{
"Usage: boundary hosts static create [options] [args]",
"",
" Create a static-type host. Example:",
"",
` $ boundary hosts static create -name prodops -description "Static host for ProdOps" -address "127.0.0.1"`,
"",
"",
})
case "update":
info = base.WrapForHelpText([]string{
"Usage: boundary hosts static update [options] [args]",
"",
" Update a static-type host given its ID. Example:",
"",
` $ boundary hosts static update -id hst_1234567890 -name "devops" -description "Static host for DevOps" -address "10.20.30.40"`,
"",
"",
})
}
return info + c.Flags().Help()
}
func (c *StaticCommand) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
if len(staticFlagsMap[c.Func]) > 0 {
common.PopulateCommonFlags(c.Command, f, "static-type host", staticFlagsMap[c.Func])
}
for _, name := range staticFlagsMap[c.Func] {
switch name {
case "host-catalog-id":
f.StringVar(&base.StringVar{
Name: "host-catalog-id",
Target: &c.flagHostCatalogId,
Usage: "The host-catalog resource in which to create or update the host resource",
})
}
}
f = set.NewFlagSet("Static Host Options")
for _, name := range staticFlagsMap[c.Func] {
switch name {
case "address":
f.StringVar(&base.StringVar{
Name: "address",
Target: &c.flagAddress,
Usage: "The address of the host",
})
}
}
return set
}
func (c *StaticCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *StaticCommand) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *StaticCommand) Run(args []string) int {
if c.Func == "" {
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(staticFlagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(staticFlagsMap[c.Func], "host-catalog-id") && c.flagHostCatalogId == "" {
c.UI.Error("Host Catalog ID must be passed in via -host-catalog-id")
return 1
}
if c.Func == "create" && c.flagAddress == "" {
c.UI.Error("Address must be passed in via -address")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []hosts.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, hosts.DefaultName())
default:
opts = append(opts, hosts.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, hosts.DefaultDescription())
default:
opts = append(opts, hosts.WithDescription(c.FlagDescription))
}
switch c.flagAddress {
case "":
case "null":
opts = append(opts, hosts.DefaultStaticHostAddress())
default:
opts = append(opts, hosts.WithStaticHostAddress(c.flagAddress))
}
hostClient := hosts.NewClient(client)
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "create":
// These don't update so don't need the existing version
default:
switch c.FlagVersion {
case 0:
opts = append(opts, hosts.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
var host *hosts.Host
var apiErr *api.Error
switch c.Func {
case "create":
host, apiErr, err = hostClient.Create(c.Context, c.flagHostCatalogId, opts...)
case "update":
host, apiErr, err = hostClient.Update(c.Context, c.FlagId, version, opts...)
}
plural := "static-type host"
if err != nil {
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
if apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, pretty.Sprint(apiErr)))
return 1
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateHostTableOutput(host))
case "json":
b, err := base.JsonFormatter{}.Format(host)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
+3 -10
View File
@@ -13,6 +13,7 @@ func generateHostSetTableOutput(in *hostsets.HostSet) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Scope ID": in.Scope.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC3339),
@@ -55,23 +56,15 @@ func generateHostSetTableOutput(in *hostsets.HostSet) string {
)
if len(in.HostIds) > 0 {
if true {
ret = append(ret,
fmt.Sprintf(" Host IDs:"),
)
}
ret = append(ret,
" Host IDs:",
base.WrapSlice(4, in.HostIds),
)
}
if len(in.Attributes) > 0 {
if true {
ret = append(ret,
fmt.Sprintf(" Attributes: %s", ""),
)
}
ret = append(ret,
fmt.Sprintf(" Attributes: %s", ""),
base.WrapMap(4, maxLength, in.Attributes),
)
}
+25 -19
View File
@@ -46,6 +46,7 @@ func (c *Command) Synopsis() string {
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"host-catalog-id"},
"add-hosts": {"id", "host", "version"},
"set-hosts": {"id", "host", "version"},
"remove-hosts": {"id", "host", "version"},
@@ -53,6 +54,7 @@ var flagsMap = map[string][]string{
func (c *Command) Help() string {
helpMap := common.HelpMap("host-set")
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
@@ -67,7 +69,7 @@ func (c *Command) Help() string {
" Please see the host-sets subcommand help for detailed usage information.",
})
case "create":
return base.WrapForHelpText([]string{
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary host-set resources. Example:",
@@ -79,7 +81,7 @@ func (c *Command) Help() string {
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
return base.WrapForHelpText([]string{
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary host-set resources. Example:",
@@ -91,7 +93,7 @@ func (c *Command) Help() string {
" Please see the typed subcommand help for detailed usage information.",
})
case "add-hosts":
return base.WrapForHelpText([]string{
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets add-hosts [sub command] [options] [args]",
"",
" This command allows adding hosts to host-set resources, if the types match and the operation is allowed by the given host-set type. Example:",
@@ -101,7 +103,7 @@ func (c *Command) Help() string {
` $ boundary host-sets add-hosts -id hsst_1234567890 -host hst_1234567890 -host hst_0987654321`,
})
case "remove-hosts":
return base.WrapForHelpText([]string{
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets remove-hosts [sub command] [options] [args]",
"",
" This command allows removing hosts from host-set resources, if the types match and the operation is allowed by the given host-set type. Example:",
@@ -111,7 +113,7 @@ func (c *Command) Help() string {
` $ boundary host-sets remove-hosts -id hsst_1234567890 -host hst_0987654321`,
})
case "set-hosts":
return base.WrapForHelpText([]string{
helpStr = base.WrapForHelpText([]string{
"Usage: boundary host-sets set-hosts [sub command] [options] [args]",
"",
" This command allows setting the complete set of hosts on host-set resources, if the types match and the operation is allowed by the given host-set type. Example:",
@@ -121,8 +123,9 @@ func (c *Command) Help() string {
` $ boundary host-sets remove-hosts -id hsst_1234567890 -host hst_1234567890`,
})
default:
return helpMap[c.Func]() + c.Flags().Help()
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
func (c *Command) Flags() *base.FlagSets {
@@ -134,14 +137,14 @@ func (c *Command) Flags() *base.FlagSets {
common.PopulateCommonFlags(c.Command, f, resource.HostSet.String(), flagsMap[c.Func])
}
f.StringVar(&base.StringVar{
Name: "host-catalog-id",
Target: &c.flagHostCatalogId,
Usage: "The host-catalog resource in which to create or update the host-set resource",
})
for _, name := range flagsMap[c.Func] {
switch name {
case "host-catalog-id":
f.StringVar(&base.StringVar{
Name: "host-catalog-id",
Target: &c.flagHostCatalogId,
Usage: "The host-catalog resource in which to create or update the host-set resource",
})
case "host":
f.StringSliceVar(&base.StringSliceVar{
Name: "host",
@@ -174,11 +177,14 @@ func (c *Command) Run(args []string) int {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "host-catalog-id") && c.flagHostCatalogId == "" {
c.UI.Error("Host Catalog ID must be passed in via -host-catalog-id")
return 1
}
client, err := c.Client()
if err != nil {
@@ -232,7 +238,7 @@ func (c *Command) Run(args []string) int {
case "add-hosts", "remove-hosts", "set-hosts":
switch c.FlagVersion {
case 0:
opts = append(opts, hostsets.WithAutomaticVersioning())
opts = append(opts, hostsets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
@@ -250,17 +256,17 @@ func (c *Command) Run(args []string) int {
switch c.Func {
case "read":
set, apiErr, err = hostsetClient.Read(c.Context, c.flagHostCatalogId, c.FlagId, opts...)
set, apiErr, err = hostsetClient.Read(c.Context, c.FlagId, opts...)
case "delete":
existed, apiErr, err = hostsetClient.Delete(c.Context, c.flagHostCatalogId, c.FlagId, opts...)
existed, apiErr, err = hostsetClient.Delete(c.Context, c.FlagId, opts...)
case "list":
listedSets, apiErr, err = hostsetClient.List(c.Context, c.flagHostCatalogId, opts...)
case "add-hosts":
set, apiErr, err = hostsetClient.AddHosts(c.Context, c.flagHostCatalogId, c.FlagId, version, c.flagHosts, opts...)
set, apiErr, err = hostsetClient.AddHosts(c.Context, c.FlagId, version, c.flagHosts, opts...)
case "remove-hosts":
set, apiErr, err = hostsetClient.RemoveHosts(c.Context, c.flagHostCatalogId, c.FlagId, version, c.flagHosts, opts...)
set, apiErr, err = hostsetClient.RemoveHosts(c.Context, c.FlagId, version, c.flagHosts, opts...)
case "set-hosts":
set, apiErr, err = hostsetClient.SetHosts(c.Context, c.flagHostCatalogId, c.FlagId, version, c.flagHosts, opts...)
set, apiErr, err = hostsetClient.SetHosts(c.Context, c.FlagId, version, c.flagHosts, opts...)
}
plural := "host set"
+14 -10
View File
@@ -30,7 +30,7 @@ func (c *StaticCommand) Synopsis() string {
}
var staticFlagsMap = map[string][]string{
"create": {"name", "description"},
"create": {"host-catalog-id", "name", "description"},
"update": {"id", "name", "description", "version"},
}
@@ -71,11 +71,16 @@ func (c *StaticCommand) Flags() *base.FlagSets {
common.PopulateCommonFlags(c.Command, f, "static-type host-set", staticFlagsMap[c.Func])
}
f.StringVar(&base.StringVar{
Name: "host-catalog-id",
Target: &c.flagHostCatalogId,
Usage: "The host-catalog resource in which to create or update the host-set resource",
})
for _, name := range staticFlagsMap[c.Func] {
switch name {
case "host-catalog-id":
f.StringVar(&base.StringVar{
Name: "host-catalog-id",
Target: &c.flagHostCatalogId,
Usage: "The host-catalog resource in which to create or update the host-set resource",
})
}
}
return set
}
@@ -104,8 +109,7 @@ func (c *StaticCommand) Run(args []string) int {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if c.flagHostCatalogId == "" {
if strutil.StrListContains(staticFlagsMap[c.Func], "host-catalog-id") && c.flagHostCatalogId == "" {
c.UI.Error("Host Catalog ID must be passed in via -host-catalog-id")
return 1
}
@@ -144,7 +148,7 @@ func (c *StaticCommand) Run(args []string) int {
default:
switch c.FlagVersion {
case 0:
opts = append(opts, hostsets.WithAutomaticVersioning())
opts = append(opts, hostsets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
@@ -157,7 +161,7 @@ func (c *StaticCommand) Run(args []string) int {
case "create":
set, apiErr, err = hostsetClient.Create(c.Context, c.flagHostCatalogId, opts...)
case "update":
set, apiErr, err = hostsetClient.Update(c.Context, c.flagHostCatalogId, c.FlagId, version, opts...)
set, apiErr, err = hostsetClient.Update(c.Context, c.FlagId, version, opts...)
}
plural := "static-type host-set"
+1
View File
@@ -91,6 +91,7 @@ func generateRoleTableOutput(in *roles.Role) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Scope ID": in.Scope.Id,
"Version": in.Version,
"Created Time": in.CreatedTime.Local().Format(time.RFC3339),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC3339),
+10 -4
View File
@@ -22,6 +22,7 @@ type Command struct {
Func string
flagScope string
flagGrantScopeId string
flagPrincipals []string
flagGrants []string
@@ -51,10 +52,11 @@ var helpMap = func() map[string]func() string {
}
var flagsMap = map[string][]string{
"create": {"name", "description", "grantscopeid"},
"create": {"scope-id", "name", "description", "grantscopeid"},
"update": {"id", "name", "description", "grantscopeid", "version"},
"read": {"id"},
"delete": {"id"},
"list": {"scope-id"},
"add-principals": {"id", "principal", "version"},
"set-principals": {"id", "principal", "version"},
"remove-principals": {"id", "principal", "version"},
@@ -105,6 +107,10 @@ func (c *Command) Run(args []string) int {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
@@ -198,7 +204,7 @@ func (c *Command) Run(args []string) int {
default:
switch c.FlagVersion {
case 0:
opts = append(opts, roles.WithAutomaticVersioning())
opts = append(opts, roles.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
@@ -211,7 +217,7 @@ func (c *Command) Run(args []string) int {
switch c.Func {
case "create":
role, apiErr, err = roleClient.Create(c.Context, opts...)
role, apiErr, err = roleClient.Create(c.Context, c.FlagScopeId, opts...)
case "update":
role, apiErr, err = roleClient.Update(c.Context, c.FlagId, version, opts...)
case "read":
@@ -219,7 +225,7 @@ func (c *Command) Run(args []string) int {
case "delete":
existed, apiErr, err = roleClient.Delete(c.Context, c.FlagId, opts...)
case "list":
listedRoles, apiErr, err = roleClient.List(c.Context, opts...)
listedRoles, apiErr, err = roleClient.List(c.Context, c.FlagScopeId, opts...)
case "add-principals":
role, apiErr, err = roleClient.AddPrincipals(c.Context, c.FlagId, version, principals, opts...)
case "set-principals":
+1
View File
@@ -12,6 +12,7 @@ func generateScopeTableOutput(in *scopes.Scope) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Scope ID": in.Scope.Id,
"Version": in.Version,
"Created Time": in.CreatedTime.Local().Format(time.RFC3339),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC3339),
+9 -4
View File
@@ -30,10 +30,11 @@ func (c *Command) Synopsis() string {
}
var flagsMap = map[string][]string{
"create": {"name", "description", "skip-role-creation"},
"create": {"scope-id", "name", "description", "skip-role-creation"},
"update": {"id", "name", "description", "version"},
"read": {"id"},
"delete": {"id"},
"list": {"scope-id"},
}
func (c *Command) Help() string {
@@ -86,6 +87,10 @@ func (c *Command) Run(args []string) int {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
@@ -123,7 +128,7 @@ func (c *Command) Run(args []string) int {
default:
switch c.FlagVersion {
case 0:
opts = append(opts, scopes.WithAutomaticVersioning())
opts = append(opts, scopes.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
@@ -136,7 +141,7 @@ func (c *Command) Run(args []string) int {
switch c.Func {
case "create":
scope, apiErr, err = scopeClient.Create(c.Context, client.ScopeId(), opts...)
scope, apiErr, err = scopeClient.Create(c.Context, c.FlagScopeId, opts...)
case "update":
scope, apiErr, err = scopeClient.Update(c.Context, c.FlagId, version, opts...)
case "read":
@@ -144,7 +149,7 @@ func (c *Command) Run(args []string) int {
case "delete":
existed, apiErr, err = scopeClient.Delete(c.Context, c.FlagId, opts...)
case "list":
listedScopes, apiErr, err = scopeClient.List(c.Context, client.ScopeId(), opts...)
listedScopes, apiErr, err = scopeClient.List(c.Context, c.FlagScopeId, opts...)
}
plural := "scope"
+101
View File
@@ -0,0 +1,101 @@
package targets
import (
"fmt"
"time"
"github.com/hashicorp/boundary/api/scopes"
"github.com/hashicorp/boundary/api/targets"
"github.com/hashicorp/boundary/internal/cmd/base"
)
func generateTargetTableOutput(in *targets.Target) string {
var ret []string
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Scope ID": in.Scope.Id,
"Version": in.Version,
"Type": in.Type,
"Created Time": in.CreatedTime.Local().Format(time.RFC3339),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC3339),
"Default Port": in.DefaultPort,
}
if in.Name != "" {
nonAttributeMap["Name"] = in.Name
}
if in.Description != "" {
nonAttributeMap["Description"] = in.Description
}
maxLength := 0
for k := range nonAttributeMap {
if len(k) > maxLength {
maxLength = len(k)
}
}
var hostSetMaps []map[string]interface{}
if len(in.HostSets) > 0 {
for _, set := range in.HostSets {
m := map[string]interface{}{
"ID": set.Id,
"Host Catalog ID": set.HostCatalogId,
}
hostSetMaps = append(hostSetMaps, m)
}
if l := len("Host Catalog ID"); l > maxLength {
maxLength = l
}
}
ret = append(ret, "", "Target information:")
ret = append(ret,
// We do +2 because there is another +2 offset for host sets below
base.WrapMap(2, maxLength+2, nonAttributeMap),
)
if len(in.HostSets) > 0 {
ret = append(ret,
fmt.Sprintf(" Host Sets: %s", ""),
)
for _, m := range hostSetMaps {
ret = append(ret,
base.WrapMap(4, maxLength, m),
"",
)
}
}
return base.WrapForHelpText(ret)
}
func exampleOutput() string {
in := &targets.Target{
Id: "ttcp_1234567890",
ScopeId: "global",
Scope: &scopes.ScopeInfo{
Id: "global",
},
Name: "foo",
Description: "The bar of foos",
CreatedTime: time.Now().Add(-5 * time.Minute),
UpdatedTime: time.Now(),
Version: 3,
Type: "tcp",
HostSetIds: []string{"hsst_1234567890", "hsst_0987654321"},
HostSets: []*targets.HostSet{
{
Id: "hsst_1234567890",
HostCatalogId: "hcst_1234567890",
},
{
Id: "hsst_0987654321",
HostCatalogId: "hcst_1234567890",
},
},
DefaultPort: 22,
}
return generateTargetTableOutput(in)
}
+360
View File
@@ -0,0 +1,360 @@
package targets
import (
"fmt"
"os"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/targets"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/hashicorp/vault/sdk/helper/strutil"
"github.com/kr/pretty"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var _ cli.Command = (*Command)(nil)
var _ cli.CommandAutocomplete = (*Command)(nil)
type Command struct {
*base.Command
Func string
flagHostSets []string
}
func (c *Command) Synopsis() string {
switch c.Func {
case "create":
return "Create target resources within Boundary"
case "update":
return "Update target resources within Boundary"
default:
return common.SynopsisFunc(c.Func, "target")
}
}
var flagsMap = map[string][]string{
"read": {"id"},
"delete": {"id"},
"list": {"scope-id"},
"add-host-sets": {"id", "host-set", "version"},
"remove-host-sets": {"id", "host-set", "version"},
"set-host-sets": {"id", "host-set", "version"},
}
func (c *Command) Help() string {
helpMap := common.HelpMap("target")
var helpStr string
switch c.Func {
case "":
return base.WrapForHelpText([]string{
"Usage: boundary targets [sub command] [options] [args]",
"",
" This command allows operations on Boundary target resources. Example:",
"",
" Read a target:",
"",
` $ boundary targets read -id ttcp_1234567890`,
"",
" Please see the targets subcommand help for detailed usage information.",
})
case "create":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary targets create [type] [sub command] [options] [args]",
"",
" This command allows create operations on Boundary target resources. Example:",
"",
" Create a tcp-type target:",
"",
` $ boundary targets create tcp -name prodops -description "For ProdOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "update":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary targets update [type] [sub command] [options] [args]",
"",
" This command allows update operations on Boundary target resources. Example:",
"",
" Update a tcp-type target:",
"",
` $ boundary targets update tcp -id ttcp_1234567890 -name devops -description "For DevOps usage"`,
"",
" Please see the typed subcommand help for detailed usage information.",
})
case "add-host-sets":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary target add-host-sets [sub command] [options] [args]",
"",
" This command allows adding host-set resources to target resources. Example:",
"",
" Add host-set resources to a tcp-type target:",
"",
` $ boundary targets add-host-sets -id ttcp_1234567890 -host-set hsst_1234567890 -host-set hsst_0987654321`,
})
case "remove-host-sets":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary target remove-host-sets [sub command] [options] [args]",
"",
" This command allows removing host-set resources from target resources. Example:",
"",
" Remove host-set resources from a tcp-type target:",
"",
` $ boundary targets add-host-sets -id ttcp_1234567890 -host hsst_1234567890 -host-set hsst_0987654321`,
})
case "set-host-sets":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary target set-host-sets [sub command] [options] [args]",
"",
" This command allows setting the complete set of host-set resources on a target resource. Example:",
"",
" Set host-set resources on a tcp-type target:",
"",
` $ boundary targets set-host-sets -id ttcp_1234567890 -host-set hsst_1234567890`,
})
default:
helpStr = helpMap[c.Func]()
}
return helpStr + c.Flags().Help()
}
func (c *Command) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
f := set.NewFlagSet("Command Options")
if len(flagsMap[c.Func]) > 0 {
common.PopulateCommonFlags(c.Command, f, resource.Target.String(), flagsMap[c.Func])
}
for _, name := range flagsMap[c.Func] {
switch name {
case "host-set":
f.StringSliceVar(&base.StringSliceVar{
Name: "host-set",
Target: &c.flagHostSets,
Usage: "The host-set resources to add, remove, or set. May be specified multiple times.",
})
}
}
return set
}
func (c *Command) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *Command) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *Command) Run(args []string) int {
if os.Getenv("BOUNDARY_EXAMPLE_CLI_OUTPUT") != "" {
c.UI.Output(exampleOutput())
return 0
}
switch c.Func {
case "", "create", "update":
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []targets.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, targets.DefaultName())
default:
opts = append(opts, targets.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, targets.DefaultDescription())
default:
opts = append(opts, targets.WithDescription(c.FlagDescription))
}
hostSets := c.flagHostSets
switch c.Func {
case "add-host-sets", "remove-host-sets":
if len(c.flagHostSets) == 0 {
c.UI.Error("No host-sets supplied via -host-set")
return 1
}
case "set-host-sets":
switch len(c.flagHostSets) {
case 0:
case 1:
if c.flagHostSets[0] == "null" {
hostSets = []string{}
}
}
if hostSets == nil {
c.UI.Error("No host-sets supplied via -host-set")
return 1
}
}
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "add-host-sets", "remove-host-sets", "set-host-sets":
switch c.FlagVersion {
case 0:
opts = append(opts, targets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
default:
// The only other one that needs it is update, handled by the static
// file
}
targetClient := targets.NewClient(client)
var existed bool
var target *targets.Target
var listedCatalogs []*targets.Target
var apiErr *api.Error
switch c.Func {
case "read":
target, apiErr, err = targetClient.Read(c.Context, c.FlagId, opts...)
case "delete":
existed, apiErr, err = targetClient.Delete(c.Context, c.FlagId, opts...)
case "list":
listedCatalogs, apiErr, err = targetClient.List(c.Context, c.FlagScopeId, opts...)
case "add-host-sets":
target, apiErr, err = targetClient.AddHostSets(c.Context, c.FlagId, version, c.flagHostSets, opts...)
case "remove-host-sets":
target, apiErr, err = targetClient.RemoveHostSets(c.Context, c.FlagId, version, c.flagHostSets, opts...)
case "set-host-sets":
target, apiErr, err = targetClient.SetHostSets(c.Context, c.FlagId, version, c.flagHostSets, opts...)
}
plural := "target"
if c.Func == "list" {
plural = "targets"
}
if err != nil {
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
if apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, pretty.Sprint(apiErr)))
return 1
}
switch c.Func {
case "delete":
switch base.Format(c.UI) {
case "json":
c.UI.Output("null")
case "table":
output := "The delete operation completed successfully"
switch existed {
case true:
output += "."
default:
output += ", however the resource did not exist at the time."
}
c.UI.Output(output)
}
return 0
case "list":
switch base.Format(c.UI) {
case "json":
if len(listedCatalogs) == 0 {
c.UI.Output("null")
return 0
}
b, err := base.JsonFormatter{}.Format(listedCatalogs)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
case "table":
if len(listedCatalogs) == 0 {
c.UI.Output("No targets found")
return 0
}
var output []string
output = []string{
"",
"Target information:",
}
for i, m := range listedCatalogs {
if i > 0 {
output = append(output, "")
}
if true {
output = append(output,
fmt.Sprintf(" ID: %s", m.Id),
fmt.Sprintf(" Version: %d", m.Version),
fmt.Sprintf(" Type: %s", m.Type),
)
}
if m.Name != "" {
output = append(output,
fmt.Sprintf(" Name: %s", m.Name),
)
}
if m.Description != "" {
output = append(output,
fmt.Sprintf(" Description: %s", m.Description),
)
}
}
c.UI.Output(base.WrapForHelpText(output))
}
return 0
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateTargetTableOutput(target))
case "json":
b, err := base.JsonFormatter{}.Format(target)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
+176
View File
@@ -0,0 +1,176 @@
package targets
import (
"fmt"
"net/textproto"
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/targets"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
"github.com/hashicorp/vault/sdk/helper/strutil"
"github.com/kr/pretty"
"github.com/mitchellh/cli"
"github.com/posener/complete"
)
var _ cli.Command = (*TcpCommand)(nil)
var _ cli.CommandAutocomplete = (*TcpCommand)(nil)
type TcpCommand struct {
*base.Command
Func string
}
func (c *TcpCommand) Synopsis() string {
return fmt.Sprintf("%s a tcp-type target within Boundary", textproto.CanonicalMIMEHeaderKey(c.Func))
}
var tcpFlagsMap = map[string][]string{
"create": {"scope-id", "name", "description"},
"update": {"id", "name", "description", "version"},
}
func (c *TcpCommand) Help() string {
var info string
switch c.Func {
case "create":
info = base.WrapForHelpText([]string{
"Usage: boundary targets tcp create [options] [args]",
"",
" Create a tcp-type target. Example:",
"",
` $ boundary targets tcp create -name prodops -description "Tcp target for ProdOps"`,
"",
"",
})
case "update":
info = base.WrapForHelpText([]string{
"Usage: boundary targets tcp update [options] [args]",
"",
" Update a tcp-type target given its ID. Example:",
"",
` $ boundary targets tcp update -id ttcp_1234567890 -name "devops" -description "Tcp target for DevOps"`,
"",
"",
})
}
return info + c.Flags().Help()
}
func (c *TcpCommand) Flags() *base.FlagSets {
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
if len(tcpFlagsMap[c.Func]) > 0 {
f := set.NewFlagSet("Command Options")
common.PopulateCommonFlags(c.Command, f, "tcp-type target", tcpFlagsMap[c.Func])
}
return set
}
func (c *TcpCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}
func (c *TcpCommand) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
func (c *TcpCommand) Run(args []string) int {
if c.Func == "" {
return cli.RunResultHelp
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
if strutil.StrListContains(tcpFlagsMap[c.Func], "id") && c.FlagId == "" {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(tcpFlagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating API client: %s", err.Error()))
return 2
}
var opts []targets.Option
switch c.FlagName {
case "":
case "null":
opts = append(opts, targets.DefaultName())
default:
opts = append(opts, targets.WithName(c.FlagName))
}
switch c.FlagDescription {
case "":
case "null":
opts = append(opts, targets.DefaultDescription())
default:
opts = append(opts, targets.WithDescription(c.FlagDescription))
}
targetClient := targets.NewClient(client)
// Perform check-and-set when needed
var version uint32
switch c.Func {
case "create":
// These don't update so don't need the existing version
default:
switch c.FlagVersion {
case 0:
opts = append(opts, targets.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
var catalog *targets.Target
var apiErr *api.Error
switch c.Func {
case "create":
catalog, apiErr, err = targetClient.Create(c.Context, "tcp", c.FlagScopeId, opts...)
case "update":
catalog, apiErr, err = targetClient.Update(c.Context, c.FlagId, version, opts...)
}
plural := "tcp-type target"
if err != nil {
c.UI.Error(fmt.Sprintf("Error trying to %s %s: %s", c.Func, plural, err.Error()))
return 2
}
if apiErr != nil {
c.UI.Error(fmt.Sprintf("Error from controller when performing %s on %s: %s", c.Func, plural, pretty.Sprint(apiErr)))
return 1
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateTargetTableOutput(catalog))
case "json":
b, err := base.JsonFormatter{}.Format(catalog)
if err != nil {
c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error())
return 1
}
c.UI.Output(string(b))
}
return 0
}
+1
View File
@@ -12,6 +12,7 @@ func generateUserTableOutput(in *users.User) string {
nonAttributeMap := map[string]interface{}{
"ID": in.Id,
"Scope ID": in.Scope.Id,
"Version": in.Version,
"Created Time": in.CreatedTime.Local().Format(time.RFC3339),
"Updated Time": in.UpdatedTime.Local().Format(time.RFC3339),
+9 -4
View File
@@ -28,10 +28,11 @@ func (c *Command) Synopsis() string {
}
var flagsMap = map[string][]string{
"create": {"name", "description"},
"create": {"scope-id", "name", "description"},
"update": {"id", "name", "description", "version"},
"read": {"id"},
"delete": {"id"},
"list": {"scope-id"},
}
func (c *Command) Help() string {
@@ -77,6 +78,10 @@ func (c *Command) Run(args []string) int {
c.UI.Error("ID is required but not passed in via -id")
return 1
}
if strutil.StrListContains(flagsMap[c.Func], "scope-id") && c.FlagScopeId == "" {
c.UI.Error("Scope ID must be passed in via -scope-id")
return 1
}
client, err := c.Client()
if err != nil {
@@ -112,7 +117,7 @@ func (c *Command) Run(args []string) int {
default:
switch c.FlagVersion {
case 0:
opts = append(opts, users.WithAutomaticVersioning())
opts = append(opts, users.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
@@ -125,7 +130,7 @@ func (c *Command) Run(args []string) int {
switch c.Func {
case "create":
user, apiErr, err = userClient.Create(c.Context, opts...)
user, apiErr, err = userClient.Create(c.Context, c.FlagScopeId, opts...)
case "update":
user, apiErr, err = userClient.Update(c.Context, c.FlagId, version, opts...)
case "read":
@@ -133,7 +138,7 @@ func (c *Command) Run(args []string) int {
case "delete":
existed, apiErr, err = userClient.Delete(c.Context, c.FlagId, opts...)
case "list":
listedUsers, apiErr, err = userClient.List(c.Context, opts...)
listedUsers, apiErr, err = userClient.List(c.Context, c.FlagScopeId, opts...)
}
plural := "user"
+9
View File
@@ -4,11 +4,20 @@ import (
"fmt"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/posener/complete"
)
func PopulateCommonFlags(c *base.Command, f *base.FlagSet, resourceType string, flagNames []string) {
for _, name := range flagNames {
switch name {
case "scope-id":
f.StringVar(&base.StringVar{
Name: "scope-id",
Target: &c.FlagScopeId,
Default: "global",
Completion: complete.PredictAnything,
Usage: `Scope in which to make the request. Defaults to "global".`,
})
case "id":
f.StringVar(&base.StringVar{
Name: "id",
+36 -2
View File
@@ -289,6 +289,40 @@
]
}
},
"/v1/auth-methods/{auth_method_id}:authenticate": {
"post": {
"summary": "Authenticate a user to an scope and retrieve an authentication token.",
"operationId": "AuthenticationService_Authenticate",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/controller.api.resources.authtokens.v1.AuthToken"
}
}
},
"parameters": [
{
"name": "auth_method_id",
"description": "The id to the authmethod in the system being used for authentication. The auth method must be in the scope\nbeing logged in to.",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/controller.api.services.v1.AuthenticateRequest"
}
}
],
"tags": [
"controller.api.services.v1.AuthenticationService"
]
}
},
"/v1/auth-methods/{id}": {
"get": {
"summary": "Gets a single AuthMethod",
@@ -1881,7 +1915,7 @@
"/v1/scopes/*/auth-methods/{auth_method_id}:authenticate": {
"post": {
"summary": "Authenticate a user to an scope and retrieve an authentication token.",
"operationId": "AuthenticationService_Authenticate",
"operationId": "AuthenticationService_Authenticate2",
"responses": {
"200": {
"description": "",
@@ -4984,7 +5018,7 @@
"type": "integer",
"format": "int64"
},
"old_password": {
"current_password": {
"type": "string"
},
"new_password": {
@@ -659,10 +659,10 @@ type ChangePasswordRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"`
OldPassword string `protobuf:"bytes,3,opt,name=old_password,proto3" json:"old_password,omitempty"`
NewPassword string `protobuf:"bytes,4,opt,name=new_password,proto3" json:"new_password,omitempty"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"`
CurrentPassword string `protobuf:"bytes,3,opt,name=current_password,proto3" json:"current_password,omitempty"`
NewPassword string `protobuf:"bytes,4,opt,name=new_password,proto3" json:"new_password,omitempty"`
}
func (x *ChangePasswordRequest) Reset() {
@@ -711,9 +711,9 @@ func (x *ChangePasswordRequest) GetVersion() uint32 {
return 0
}
func (x *ChangePasswordRequest) GetOldPassword() string {
func (x *ChangePasswordRequest) GetCurrentPassword() string {
if x != nil {
return x.OldPassword
return x.CurrentPassword
}
return ""
}
@@ -858,138 +858,139 @@ var file_controller_api_services_v1_account_service_proto_rawDesc = []byte{
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65,
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73,
0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x04, 0x69, 0x74, 0x65,
0x6d, 0x22, 0x89, 0x01, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73,
0x6d, 0x22, 0x91, 0x01, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73,
0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x6f, 0x6c, 0x64, 0x5f, 0x70, 0x61, 0x73,
0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x6c, 0x64,
0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6e, 0x65, 0x77,
0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0c, 0x6e, 0x65, 0x77, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x5b, 0x0a,
0x16, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73,
0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x32, 0xfc, 0x0d, 0x0a, 0x0e, 0x41,
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xd9, 0x01,
0x0a, 0x0a, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2d, 0x2e, 0x63,
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f,
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f,
0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6c, 0x82, 0xd3, 0xe4,
0x93, 0x02, 0x4c, 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x5a, 0x31, 0x12, 0x29, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63,
0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68,
0x6f, 0x64, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b,
0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92,
0x41, 0x17, 0x12, 0x15, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c,
0x65, 0x20, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0xf0, 0x01, 0x0a, 0x0c, 0x4c, 0x69,
0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x6e,
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f,
0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f,
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x7d, 0x82,
0xd3, 0xe4, 0x93, 0x02, 0x45, 0x12, 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x73, 0x5a, 0x35, 0x12, 0x33, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65,
0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73,
0x2f, 0x7b, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x69, 0x64,
0x7d, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x92, 0x41, 0x2f, 0x12, 0x2d, 0x4c,
0x69, 0x73, 0x74, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x73, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20,
0x61, 0x75, 0x74, 0x68, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x12, 0x99, 0x02, 0x0a,
0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30,
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61,
0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72,
0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0xa2, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x62, 0x22, 0x0c, 0x2f, 0x76,
0x31, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d,
0x5a, 0x46, 0x22, 0x38, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a,
0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x7b, 0x69,
0x74, 0x65, 0x6d, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f,
0x69, 0x64, 0x7d, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x3a, 0x04, 0x69, 0x74,
0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41,
0x37, 0x12, 0x35, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e,
0x67, 0x6c, 0x65, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x74,
0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x61, 0x75, 0x74, 0x68,
0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x12, 0xec, 0x01, 0x0a, 0x0d, 0x55, 0x70, 0x64,
0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e,
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63,
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x76, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x58, 0x32, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d,
0x5a, 0x37, 0x32, 0x29, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a,
0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x2a, 0x2f,
0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x04, 0x69,
0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92,
0x41, 0x15, 0x12, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x61,
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x12, 0xd4, 0x01, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f,
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41,
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5e,
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x40, 0x2a, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63, 0x6f,
0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x5a, 0x2b, 0x2a, 0x29, 0x2f, 0x76, 0x31,
0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d,
0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x92, 0x41, 0x15, 0x12, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x12, 0x93,
0x02, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x2e,
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x50,
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f,
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x50,
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0xa2, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x6c, 0x22, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x73, 0x65, 0x74, 0x2d,
0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x3a, 0x01, 0x2a, 0x5a, 0x41, 0x22, 0x36, 0x2f,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74,
0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x10, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6e, 0x65, 0x77, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6e, 0x65, 0x77, 0x5f, 0x70, 0x61, 0x73,
0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x5b, 0x0a, 0x16, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50,
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x41, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e,
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72,
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x04, 0x69, 0x74,
0x65, 0x6d, 0x32, 0xfc, 0x0d, 0x0a, 0x0e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xd9, 0x01, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76,
0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31,
0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x6c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4c, 0x12, 0x11, 0x2f, 0x76, 0x31,
0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x5a, 0x31,
0x12, 0x29, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x61,
0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, 0x74, 0x65,
0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x17, 0x12, 0x15, 0x47, 0x65, 0x74, 0x73,
0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x12, 0xf0, 0x01, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x73, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e,
0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31,
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x7d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x45, 0x12, 0x0c, 0x2f,
0x76, 0x31, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x5a, 0x35, 0x12, 0x33, 0x2f,
0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x75, 0x74, 0x68,
0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x73, 0x65, 0x74, 0x2d, 0x70, 0x61, 0x73,
0x73, 0x77, 0x6f, 0x72, 0x64, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04,
0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x2d, 0x12, 0x2b, 0x53, 0x65, 0x74, 0x73, 0x20, 0x74, 0x68,
0x65, 0x20, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74,
0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x61, 0x63, 0x63, 0x6f,
0x75, 0x6e, 0x74, 0x2e, 0x12, 0xa2, 0x02, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50,
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77,
0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x6f, 0x6e,
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61,
0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xa8,
0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x72, 0x22, 0x21, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x63, 0x68, 0x61, 0x6e, 0x67,
0x65, 0x2d, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x3a, 0x01, 0x2a, 0x5a, 0x44, 0x22,
0x39, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x75,
0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x63, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x63, 0x68, 0x61, 0x6e, 0x67,
0x65, 0x2d, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69,
0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x2d, 0x12, 0x2b, 0x53, 0x65,
0x74, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x20,
0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64,
0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x42, 0x4d, 0x5a, 0x4b, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72,
0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72,
0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x7b, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d,
0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x73, 0x92, 0x41, 0x2f, 0x12, 0x2d, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x61, 0x6c, 0x6c,
0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x73,
0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x61, 0x75, 0x74, 0x68, 0x20, 0x6d, 0x65, 0x74,
0x68, 0x6f, 0x64, 0x2e, 0x12, 0x99, 0x02, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41,
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f,
0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xa2, 0x01, 0x82, 0xd3,
0xe4, 0x93, 0x02, 0x62, 0x22, 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x73, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x5a, 0x46, 0x22, 0x38, 0x2f, 0x76, 0x31, 0x2f,
0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65,
0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x7b, 0x69, 0x74, 0x65, 0x6d, 0x2e, 0x61, 0x75, 0x74, 0x68,
0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x61, 0x63, 0x63, 0x6f,
0x75, 0x6e, 0x74, 0x73, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d,
0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x37, 0x12, 0x35, 0x43, 0x72, 0x65, 0x61, 0x74,
0x65, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x61, 0x63, 0x63, 0x6f,
0x75, 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69,
0x64, 0x65, 0x64, 0x20, 0x61, 0x75, 0x74, 0x68, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e,
0x12, 0xec, 0x01, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e,
0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76,
0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x76, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x58, 0x32,
0x11, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69,
0x64, 0x7d, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x5a, 0x37, 0x32, 0x29, 0x2f, 0x76, 0x31, 0x2f,
0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65,
0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73,
0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65,
0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x15, 0x12, 0x13, 0x55, 0x70, 0x64, 0x61,
0x74, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x12,
0xd4, 0x01, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31,
0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x40, 0x2a, 0x11,
0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64,
0x7d, 0x5a, 0x2b, 0x2a, 0x29, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f,
0x2a, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x2a,
0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x92, 0x41,
0x15, 0x12, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x12, 0x93, 0x02, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x50, 0x61,
0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xa2, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x6c,
0x22, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b,
0x69, 0x64, 0x7d, 0x3a, 0x73, 0x65, 0x74, 0x2d, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
0x3a, 0x01, 0x2a, 0x5a, 0x41, 0x22, 0x36, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65,
0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73,
0x2f, 0x2a, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d,
0x3a, 0x73, 0x65, 0x74, 0x2d, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x3a, 0x01, 0x2a,
0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x2d, 0x12,
0x2b, 0x53, 0x65, 0x74, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69,
0x64, 0x65, 0x64, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x12, 0xa2, 0x02, 0x0a,
0x0e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12,
0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69,
0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61,
0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e,
0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xa8, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x72, 0x22,
0x21, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69,
0x64, 0x7d, 0x3a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2d, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x3a, 0x01, 0x2a, 0x5a, 0x44, 0x22, 0x39, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f,
0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f,
0x64, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x69,
0x64, 0x7d, 0x3a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2d, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65,
0x6d, 0x92, 0x41, 0x2d, 0x12, 0x2b, 0x53, 0x65, 0x74, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70,
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20,
0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x2e, 0x42, 0x4d, 0x5a, 0x4b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61,
0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f,
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -334,8 +334,8 @@ var file_controller_api_services_v1_authenticate_service_proto_rawDesc = []byte{
0x17, 0x0a, 0x15, 0x44, 0x65, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74,
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x18, 0x0a, 0x16, 0x44, 0x65, 0x61, 0x75,
0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x32, 0xa0, 0x02, 0x0a, 0x15, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x86, 0x02, 0x0a,
0x73, 0x65, 0x32, 0xdb, 0x02, 0x0a, 0x15, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xc1, 0x02, 0x0a,
0x0c, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x2f, 0x2e,
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65,
@@ -343,21 +343,25 @@ var file_controller_api_services_v1_authenticate_service_proto_rawDesc = []byte{
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68,
0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x92, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x42, 0x22, 0x37, 0x2f, 0x76, 0x31, 0x2f, 0x73,
0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74,
0x68, 0x6f, 0x64, 0x73, 0x2f, 0x7b, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f,
0x64, 0x5f, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61,
0x74, 0x65, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x47, 0x12, 0x45,
0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x75,
0x73, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x6e, 0x20, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x20,
0x61, 0x6e, 0x64, 0x20, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x20, 0x61, 0x6e, 0x20,
0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74,
0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x42, 0x4d, 0x5a, 0x4b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,
0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61,
0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x22, 0xcd, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x7d, 0x22, 0x2e, 0x2f, 0x76, 0x31, 0x2f, 0x61,
0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x7b, 0x61, 0x75, 0x74,
0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x75, 0x74,
0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x5a, 0x42, 0x22, 0x37,
0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x61, 0x75, 0x74,
0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x7b, 0x61, 0x75, 0x74, 0x68, 0x5f,
0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x75, 0x74, 0x68, 0x65,
0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d,
0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x47, 0x12, 0x45, 0x41, 0x75, 0x74, 0x68, 0x65,
0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x74,
0x6f, 0x20, 0x61, 0x6e, 0x20, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x72,
0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x75, 0x74, 0x68, 0x65,
0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e,
0x42, 0x4d, 0x5a, 0x4b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68,
0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72,
0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63,
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -97,6 +97,74 @@ func local_request_AuthenticationService_Authenticate_0(ctx context.Context, mar
}
func request_AuthenticationService_Authenticate_1(ctx context.Context, marshaler runtime.Marshaler, client AuthenticationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AuthenticateRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["auth_method_id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "auth_method_id")
}
protoReq.AuthMethodId, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "auth_method_id", err)
}
msg, err := client.Authenticate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_AuthenticationService_Authenticate_1(ctx context.Context, marshaler runtime.Marshaler, server AuthenticationServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AuthenticateRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["auth_method_id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "auth_method_id")
}
protoReq.AuthMethodId, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "auth_method_id", err)
}
msg, err := server.Authenticate(ctx, &protoReq)
return msg, metadata, err
}
// RegisterAuthenticationServiceHandlerServer registers the http handlers for service AuthenticationService to "mux".
// UnaryRPC :call AuthenticationServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
@@ -123,6 +191,26 @@ func RegisterAuthenticationServiceHandlerServer(ctx context.Context, mux *runtim
})
mux.Handle("POST", pattern_AuthenticationService_Authenticate_1, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/controller.api.services.v1.AuthenticationService/Authenticate")
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_AuthenticationService_Authenticate_1(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthenticationService_Authenticate_1(ctx, mux, outboundMarshaler, w, req, response_AuthenticationService_Authenticate_1{resp}, mux.GetForwardResponseOptions()...)
})
return nil
}
@@ -184,6 +272,26 @@ func RegisterAuthenticationServiceHandlerClient(ctx context.Context, mux *runtim
})
mux.Handle("POST", pattern_AuthenticationService_Authenticate_1, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/controller.api.services.v1.AuthenticationService/Authenticate")
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_AuthenticationService_Authenticate_1(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_AuthenticationService_Authenticate_1(ctx, mux, outboundMarshaler, w, req, response_AuthenticationService_Authenticate_1{resp}, mux.GetForwardResponseOptions()...)
})
return nil
}
@@ -196,10 +304,23 @@ func (m response_AuthenticationService_Authenticate_0) XXX_ResponseBody() interf
return response.Item
}
type response_AuthenticationService_Authenticate_1 struct {
proto.Message
}
func (m response_AuthenticationService_Authenticate_1) XXX_ResponseBody() interface{} {
response := m.Message.(*AuthenticateResponse)
return response.Item
}
var (
pattern_AuthenticationService_Authenticate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "scopes", "auth-methods", "auth_method_id"}, "authenticate"))
pattern_AuthenticationService_Authenticate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "auth-methods", "auth_method_id"}, "authenticate"))
pattern_AuthenticationService_Authenticate_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "scopes", "auth-methods", "auth_method_id"}, "authenticate"))
)
var (
forward_AuthenticationService_Authenticate_0 = runtime.ForwardResponseMessage
forward_AuthenticationService_Authenticate_1 = runtime.ForwardResponseMessage
)
@@ -178,16 +178,16 @@ func TestRepository_AddSetMembers_Combinations(t *testing.T) {
// second call - add new set of hosts - should succeed
set.Version = set.Version + 1
hosts2 := TestHosts(t, conn, c.PublicId, 5)
Hosts := TestHosts(t, conn, c.PublicId, 5)
var hostIds2 []string
for _, h := range hosts2 {
for _, h := range Hosts {
hostIds2 = append(hostIds2, h.PublicId)
}
got2, err2 := repo.AddSetMembers(context.Background(), prj.PublicId, set.PublicId, set.Version, hostIds2)
require.NoError(err2)
require.NotNil(got2)
hosts = append(hosts, hosts2...)
hosts = append(hosts, Hosts...)
assert.Len(got2, len(hosts))
assert.Empty(cmp.Diff(hosts, got2, opts...))
assert.NoError(db.TestVerifyOplog(t, rw, set.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_CREATE), db.WithCreateNotBefore(10*time.Second)))
@@ -391,9 +391,9 @@ func TestRepository_DeleteSetMembers_Combinations(t *testing.T) {
assert.NoError(db.TestVerifyOplog(t, rw, set.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_DELETE), db.WithCreateNotBefore(10*time.Second)))
// verify no members remain
members2, err := getHosts(context.Background(), repo.reader, set.PublicId, unlimited)
Members, err := getHosts(context.Background(), repo.reader, set.PublicId, unlimited)
require.NoError(err)
require.Empty(members2)
require.Empty(Members)
}
func TestRepository_SetSetMembers_Parameters(t *testing.T) {
@@ -539,14 +539,14 @@ func TestRepository_UpdateSet(t *testing.T) {
assert.Empty(gotHosts1)
sB.Name = name
got2, gotHosts2, gotCount2, err := repo.UpdateSet(context.Background(), prj.GetPublicId(), sB, 1, []string{"name"})
got2, gotHosts, gotCount2, err := repo.UpdateSet(context.Background(), prj.GetPublicId(), sB, 1, []string{"name"})
assert.Truef(errors.Is(err, db.ErrNotUnique), "want err: %v got: %v", db.ErrNotUnique, err)
assert.Nil(got2)
assert.Equal(db.NoRowsAffected, gotCount2, "row count")
err = db.TestVerifyOplog(t, rw, sB.PublicId, db.WithOperation(oplog.OpType_OP_TYPE_UPDATE), db.WithCreateNotBefore(10*time.Second))
assert.Error(err)
assert.True(errors.Is(db.ErrRecordNotFound, err))
assert.Empty(gotHosts2)
assert.Empty(gotHosts)
})
t.Run("valid-duplicate-names-diff-Catalogs", func(t *testing.T) {
+4 -4
View File
@@ -46,16 +46,16 @@ func TestScopes(t *testing.T, repo *Repository, opt ...Option) (org *Scope, prj
opts := getOpts(opt...)
org, err := NewOrg()
org, err := NewOrg(opt...)
require.NoError(err)
org, err = repo.CreateScope(context.Background(), org, opts.withUserId)
org, err = repo.CreateScope(context.Background(), org, opts.withUserId, opt...)
require.NoError(err)
require.NotNil(org)
require.NotEmpty(org.GetPublicId())
prj, err = NewProject(org.GetPublicId())
prj, err = NewProject(org.GetPublicId(), opt...)
require.NoError(err)
prj, err = repo.CreateScope(context.Background(), prj, opts.withUserId)
prj, err = repo.CreateScope(context.Background(), prj, opts.withUserId, opt...)
require.NoError(err)
require.NotNil(prj)
require.NotEmpty(prj.GetPublicId())
@@ -205,7 +205,7 @@ message SetPasswordResponse {
message ChangePasswordRequest {
string id = 1;
uint32 version = 2;
string old_password = 3 [json_name="old_password"];
string current_password = 3 [json_name="current_password"];
string new_password = 4 [json_name="new_password"];
}
@@ -13,9 +13,14 @@ service AuthenticationService {
// Authenticate validates credentials provided and returns an auth token.
rpc Authenticate(AuthenticateRequest) returns (AuthenticateResponse) {
option (google.api.http) = {
post: "/v1/scopes/*/auth-methods/{auth_method_id}:authenticate"
post: "/v1/auth-methods/{auth_method_id}:authenticate"
body: "*"
response_body: "item"
additional_bindings: {
post: "/v1/scopes/*/auth-methods/{auth_method_id}:authenticate"
body: "*"
response_body: "item"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Authenticate a user to an scope and retrieve an authentication token."
@@ -141,7 +141,7 @@ func (s Service) ChangePassword(ctx context.Context, req *pbs.ChangePasswordRequ
if authResults.Error != nil {
return nil, authResults.Error
}
u, err := s.changePasswordInRepo(ctx, authResults.Scope.GetId(), req.GetId(), req.GetVersion(), req.GetOldPassword(), req.GetNewPassword())
u, err := s.changePasswordInRepo(ctx, authResults.Scope.GetId(), req.GetId(), req.GetVersion(), req.GetCurrentPassword(), req.GetNewPassword())
if err != nil {
return nil, err
}
@@ -295,12 +295,12 @@ func (s Service) listFromRepo(ctx context.Context, authMethodId string) ([]*pb.A
return outUl, nil
}
func (s Service) changePasswordInRepo(ctx context.Context, scopeId, id string, version uint32, oldPassword, newPassword string) (*pb.Account, error) {
func (s Service) changePasswordInRepo(ctx context.Context, scopeId, id string, version uint32, currentPassword, newPassword string) (*pb.Account, error) {
repo, err := s.repoFn()
if err != nil {
return nil, err
}
out, err := repo.ChangePassword(ctx, scopeId, id, oldPassword, newPassword, version)
out, err := repo.ChangePassword(ctx, scopeId, id, currentPassword, newPassword, version)
if err != nil {
return nil, status.Errorf(codes.Internal, "Unable to change password: %v.", err)
}
@@ -448,8 +448,8 @@ func validateChangePasswordRequest(req *pbs.ChangePasswordRequest) error {
if req.GetNewPassword() == "" {
badFields["new_password"] = "This is a required field."
}
if req.GetOldPassword() == "" {
badFields["old_password"] = "This is a required field."
if req.GetCurrentPassword() == "" {
badFields["current_password"] = "This is a required field."
}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Improperly formatted identifier.", badFields)
@@ -950,10 +950,10 @@ func TestChangePassword(t *testing.T) {
acct := createAccount(t, "originalpassword")
changeResp, err := tested.ChangePassword(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())), &pbs.ChangePasswordRequest{
Id: acct.GetId(),
Version: acct.GetVersion(),
OldPassword: "originalpassword",
NewPassword: "a different password",
Id: acct.GetId(),
Version: acct.GetVersion(),
CurrentPassword: "originalpassword",
NewPassword: "a different password",
})
require.NoError(err)
assert.Equal(acct.GetVersion()+1, changeResp.GetItem().GetVersion())
@@ -969,10 +969,10 @@ func TestChangePassword(t *testing.T) {
acct := createAccount(t, "originalpassword")
changeResp, err := tested.ChangePassword(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())), &pbs.ChangePasswordRequest{
Id: acct.GetId(),
Version: acct.GetVersion(),
OldPassword: "thewrongpassword",
NewPassword: "a different password",
Id: acct.GetId(),
Version: acct.GetVersion(),
CurrentPassword: "thewrongpassword",
NewPassword: "a different password",
})
assert.Error(err)
assert.Nil(changeResp)
@@ -1042,10 +1042,10 @@ func TestChangePassword(t *testing.T) {
assert := assert.New(t)
changeResp, err := tested.ChangePassword(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())), &pbs.ChangePasswordRequest{
Id: tt.accountId,
Version: tt.version,
OldPassword: tt.oldPW,
NewPassword: tt.newPW,
Id: tt.accountId,
Version: tt.version,
CurrentPassword: tt.oldPW,
NewPassword: tt.newPW,
})
assert.Error(err)
assert.Nil(changeResp)
@@ -199,7 +199,7 @@ func validateAuthenticateRequest(req *pbs.AuthenticateRequest) error {
}
tType := strings.ToLower(strings.TrimSpace(req.GetTokenType()))
if tType != "" && tType != "token" && tType != "cookie" {
badFields["token_type"] = "The only accepted type is 'token'."
badFields["token_type"] = `The only accepted types are "token" and "cookie".`
}
if len(badFields) > 0 {
return handlers.InvalidArgumentErrorf("Invalid fields provided in request.", badFields)
+2 -4
View File
@@ -36,14 +36,14 @@ func TestAuthenticationMulti(t *testing.T) {
defer c2.Shutdown()
auth := authmethods.NewClient(c1.Client())
token1, apiErr, err := auth.Authenticate(c1.Context(), amId, user, password)
token1, apiErr, err := auth.Authenticate(c1.Context(), amId, map[string]interface{}{"login_name": user, "password": password})
require.Nil(err)
require.Nil(apiErr)
require.NotNil(token1)
time.Sleep(5 * time.Second)
auth = authmethods.NewClient(c2.Client())
token2, apiErr, err := auth.Authenticate(c2.Context(), amId, user, password)
token2, apiErr, err := auth.Authenticate(c2.Context(), amId, map[string]interface{}{"login_name": user, "password": password})
require.Nil(err)
require.Nil(apiErr)
require.NotNil(token2)
@@ -51,9 +51,7 @@ func TestAuthenticationMulti(t *testing.T) {
assert.NotEqual(token1.Token, token2.Token)
c1.Client().SetToken(token1.Token)
c1.Client().SetScopeId(scope.Global.String())
c2.Client().SetToken(token1.Token) // Same token, as it should work on both
c2.Client().SetScopeId(scope.Global.String())
// Create a project, read from the other
org, apiErr, err := scopes.NewClient(c1.Client()).Create(c1.Context(), scope.Global.String())
+4 -2
View File
@@ -103,8 +103,10 @@ func (tc *TestController) Token() *authtokens.AuthToken {
token, apiErr, err := authmethods.NewClient(tc.Client()).Authenticate(
tc.Context(),
tc.b.DevAuthMethodId,
tc.b.DevLoginName,
tc.b.DevPassword,
map[string]interface{}{
"login_name": tc.b.DevLoginName,
"password": tc.b.DevPassword,
},
)
if err != nil {
tc.t.Error(fmt.Errorf("error logging in: %w", err))
+7 -6
View File
@@ -8,6 +8,7 @@ import (
"github.com/hashicorp/boundary/globals"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/servers/controller"
"github.com/hashicorp/boundary/internal/types/scope"
"github.com/hashicorp/boundary/recovery"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -40,7 +41,7 @@ func TestRecoveryNonces(t *testing.T) {
// Token 1, try 1
client.SetToken(token1)
roleClient := roles.NewClient(client)
_, apiErr, err := roleClient.Create(tc.Context())
_, apiErr, err := roleClient.Create(tc.Context(), scope.Global.String())
require.NoError(err)
assert.Nil(apiErr)
nonces, err := repo.ListNonces(tc.Context())
@@ -48,7 +49,7 @@ func TestRecoveryNonces(t *testing.T) {
assert.Len(nonces, 1)
// Token 1, try 2
_, apiErr, err = roleClient.Create(tc.Context())
_, apiErr, err = roleClient.Create(tc.Context(), scope.Global.String())
require.NoError(err)
assert.NotNil(apiErr)
nonces, err = repo.ListNonces(tc.Context())
@@ -56,8 +57,8 @@ func TestRecoveryNonces(t *testing.T) {
assert.Len(nonces, 1)
// Token 2
client.SetToken(token2)
_, apiErr, err = roleClient.Create(tc.Context())
roleClient.ApiClient().SetToken(token2)
_, apiErr, err = roleClient.Create(tc.Context(), scope.Global.String())
require.NoError(err)
assert.Nil(apiErr)
nonces, err = repo.ListNonces(tc.Context())
@@ -72,8 +73,8 @@ func TestRecoveryNonces(t *testing.T) {
// And finally, make sure they still can't be used
for _, token := range []string{token1, token2} {
client.SetToken(token)
_, apiErr, err = roleClient.Create(tc.Context())
roleClient.ApiClient().SetToken(token)
_, apiErr, err = roleClient.Create(tc.Context(), scope.Global.String())
require.NoError(err)
assert.NotNil(apiErr)
nonces, err = repo.ListNonces(tc.Context())