From a00ee7a948eb1c24ea03f3e1a661b77f20bcd43f Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Tue, 15 Sep 2020 01:08:21 -0400 Subject: [PATCH] Add Result types to Go SDK and properly populate body/map fields (#358) --- api/accounts/account.gen.go | 134 ++++++++--- api/accounts/account_test.go | 68 +++--- api/accounts/changepassword.go | 9 +- .../password_account_attributes.gen.go | 13 -- api/accounts/setpassword.go | 9 +- api/authmethods/authenticate.go | 7 +- api/authmethods/authenticate_test.go | 2 +- api/authmethods/authmethods.gen.go | 134 ++++++++--- .../password_auth_method_attributes.gen.go | 13 -- api/authtokens/authtoken_test.go | 27 ++- api/authtokens/authtokens.gen.go | 111 ++++++--- api/error.gen.go | 12 +- api/error_details.gen.go | 13 -- api/field_error.gen.go | 13 -- api/groups/group.gen.go | 176 ++++++++++---- api/groups/group_test.go | 49 ++-- api/groups/member.gen.go | 13 -- api/hostcatalogs/host_catalog.gen.go | 134 ++++++++--- api/hostcatalogs/host_catalog_test.go | 54 ++--- api/hosts/host.gen.go | 134 ++++++++--- api/hosts/host_test.go | 50 ++-- api/hosts/static_host_attributes.gen.go | 13 -- api/hostsets/host_set.gen.go | 176 ++++++++++---- api/hostsets/host_set_test.go | 71 +++--- api/internal/genapi/input.go | 60 +++-- api/internal/genapi/templates.go | 172 ++++++++++---- api/response.go | 3 + api/roles/grant.gen.go | 13 -- api/roles/grant_json.gen.go | 13 -- api/roles/principal.gen.go | 13 -- api/roles/role.gen.go | 218 +++++++++++++----- api/roles/role_test.go | 79 +++---- api/scopes/scope.gen.go | 134 ++++++++--- api/scopes/scope_info.gen.go | 13 -- api/scopes/{project_test.go => scope_test.go} | 30 +-- api/targets/host_set.gen.go | 13 -- api/targets/target.gen.go | 176 ++++++++++---- api/targets/target_test.go | 52 +++-- api/users/user.gen.go | 134 ++++++++--- api/users/user_test.go | 37 +-- api/util.go | 50 ++-- internal/cmd/commands/accounts/account.go | 31 ++- internal/cmd/commands/accounts/password.go | 7 +- .../cmd/commands/authenticate/password.go | 7 +- .../cmd/commands/authmethods/authmethod.go | 19 +- internal/cmd/commands/authmethods/password.go | 7 +- .../cmd/commands/authtokens/authtokens.go | 19 +- internal/cmd/commands/groups/group.go | 29 ++- .../cmd/commands/hostcatalogs/hostcatalog.go | 19 +- internal/cmd/commands/hostcatalogs/static.go | 7 +- internal/cmd/commands/hosts/host.go | 19 +- internal/cmd/commands/hosts/static.go | 7 +- internal/cmd/commands/hostsets/hostset.go | 25 +- internal/cmd/commands/hostsets/static.go | 7 +- internal/cmd/commands/roles/role.go | 35 +-- internal/cmd/commands/scopes/scope.go | 23 +- internal/cmd/commands/targets/target.go | 33 +-- internal/cmd/commands/targets/tcp.go | 11 +- internal/cmd/commands/users/user.go | 23 +- internal/servers/controller/multi_test.go | 12 +- internal/servers/controller/testing.go | 2 +- 61 files changed, 1888 insertions(+), 1099 deletions(-) rename api/scopes/{project_test.go => scope_test.go} (79%) diff --git a/api/accounts/account.gen.go b/api/accounts/account.gen.go index b3fa2abff..9e91c1de1 100644 --- a/api/accounts/account.gen.go +++ b/api/accounts/account.gen.go @@ -6,7 +6,6 @@ import ( "context" "errors" "fmt" - "net/http" "net/url" "time" @@ -28,16 +27,68 @@ type Account struct { AuthMethodId string `json:"auth_method_id,omitempty"` Attributes map[string]interface{} `json:"attributes,omitempty"` - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} + responseBody *bytes.Buffer + responseMap map[string]interface{} } -func (n Account) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody +func (n Account) ResponseBody() *bytes.Buffer { + return n.responseBody } -func (n Account) LastResponseMap() map[string]interface{} { - return n.lastResponseMap +func (n Account) ResponseMap() map[string]interface{} { + return n.responseMap +} + +type AccountReadResult struct { + Item *Account + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n AccountReadResult) GetItem() interface{} { + return n.Item +} + +func (n AccountReadResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n AccountReadResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type AccountCreateResult = AccountReadResult +type AccountUpdateResult = AccountReadResult + +type AccountDeleteResult struct { + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n AccountDeleteResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n AccountDeleteResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type AccountListResult struct { + Items []*Account + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n AccountListResult) GetItems() interface{} { + return n.Items +} + +func (n AccountListResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n AccountListResult) GetResponseMap() map[string]interface{} { + return n.responseMap } // Client is a client for this collection @@ -58,7 +109,7 @@ func (c *Client) ApiClient() *api.Client { return c.client } -func (c *Client) Create(ctx context.Context, authMethodId string, opt ...Option) (*Account, *api.Error, error) { +func (c *Client) Create(ctx context.Context, authMethodId string, opt ...Option) (*AccountCreateResult, *api.Error, error) { if authMethodId == "" { return nil, nil, fmt.Errorf("empty authMethodId value passed into Create request") } @@ -89,18 +140,21 @@ func (c *Client) Create(ctx context.Context, authMethodId string, opt ...Option) return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err) } - target := new(Account) - apiErr, err := resp.Decode(target) + target := new(AccountCreateResult) + target.Item = new(Account) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Create response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Read(ctx context.Context, accountId string, opt ...Option) (*Account, *api.Error, error) { +func (c *Client) Read(ctx context.Context, accountId string, opt ...Option) (*AccountReadResult, *api.Error, error) { if accountId == "" { return nil, nil, fmt.Errorf("empty accountId value passed into Read request") } @@ -128,18 +182,21 @@ func (c *Client) Read(ctx context.Context, accountId string, opt ...Option) (*Ac return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err) } - target := new(Account) - apiErr, err := resp.Decode(target) + target := new(AccountReadResult) + target.Item = new(Account) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Read response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Update(ctx context.Context, accountId string, version uint32, opt ...Option) (*Account, *api.Error, error) { +func (c *Client) Update(ctx context.Context, accountId string, version uint32, opt ...Option) (*AccountUpdateResult, *api.Error, error) { if accountId == "" { return nil, nil, fmt.Errorf("empty accountId value passed into Update request") } @@ -161,9 +218,12 @@ func (c *Client) Update(ctx context.Context, accountId string, version uint32, o 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -186,30 +246,33 @@ func (c *Client) Update(ctx context.Context, accountId string, version uint32, o return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) } - target := new(Account) - apiErr, err := resp.Decode(target) + target := new(AccountUpdateResult) + target.Item = new(Account) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Update response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Delete(ctx context.Context, accountId string, opt ...Option) (bool, *api.Error, error) { +func (c *Client) Delete(ctx context.Context, accountId string, opt ...Option) (*AccountDeleteResult, *api.Error, error) { if accountId == "" { - return false, nil, fmt.Errorf("empty accountId value passed into Delete request") + return nil, nil, fmt.Errorf("empty accountId value passed into Delete request") } if c.client == nil { - return false, nil, fmt.Errorf("nil client") + return nil, nil, fmt.Errorf("nil client") } opts, apiOpts := getOpts(opt...) 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) + return nil, nil, fmt.Errorf("error creating Delete request: %w", err) } if len(opts.queryMap) > 0 { @@ -222,25 +285,25 @@ func (c *Client) Delete(ctx context.Context, accountId string, opt ...Option) (b resp, err := c.client.Do(req) if err != nil { - return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err) + return nil, nil, fmt.Errorf("error performing client request during Delete call: %w", err) } apiErr, err := resp.Decode(nil) if err != nil { - return false, nil, fmt.Errorf("error decoding Delete response: %w", err) + return nil, nil, fmt.Errorf("error decoding Delete response: %w", err) } if apiErr != nil { - // We don't treat a 404 in this case as failure, in order for deletes to - // be idempotent - if apiErr.Status == http.StatusNotFound { - return false, nil, nil - } - return false, apiErr, nil + return nil, apiErr, nil } - return true, nil, nil + + target := &AccountDeleteResult{ + responseBody: resp.Body, + responseMap: resp.Map, + } + return target, nil, nil } -func (c *Client) List(ctx context.Context, authMethodId string, opt ...Option) ([]*Account, *api.Error, error) { +func (c *Client) List(ctx context.Context, authMethodId string, opt ...Option) (*AccountListResult, *api.Error, error) { if authMethodId == "" { return nil, nil, fmt.Errorf("empty authMethodId value passed into List request") } @@ -269,10 +332,7 @@ func (c *Client) List(ctx context.Context, authMethodId string, opt ...Option) ( return nil, nil, fmt.Errorf("error performing client request during List call: %w", err) } - type listResponse struct { - Items []*Account - } - target := &listResponse{} + target := new(AccountListResult) apiErr, err := resp.Decode(target) if err != nil { return nil, nil, fmt.Errorf("error decoding List response: %w", err) @@ -280,5 +340,7 @@ func (c *Client) List(ctx context.Context, authMethodId string, opt ...Option) ( if apiErr != nil { return nil, apiErr, nil } - return target.Items, apiErr, nil + target.responseBody = resp.Body + target.responseMap = resp.Map + return target, apiErr, nil } diff --git a/api/accounts/account_test.go b/api/accounts/account_test.go index 40e801c91..f4cb02771 100644 --- a/api/accounts/account_test.go +++ b/api/accounts/account_test.go @@ -30,39 +30,42 @@ func TestList(t *testing.T) { 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", org.GetPublicId()) + amResult, apiErr, err := amClient.Create(tc.Context(), "password", org.GetPublicId()) require.NoError(err) require.Nil(apiErr) - require.NotNil(am) + require.NotNil(amResult) + am := amResult.Item accountClient := accounts.NewClient(client) - expected, apiErr, err := accountClient.List(tc.Context(), am.Id) - assert.NoError(err) - assert.Nil(apiErr) + lr, apiErr, err := accountClient.List(tc.Context(), am.Id) + require.NoError(err) + require.Nil(apiErr) + expected := lr.Items assert.Len(expected, 0) expected = append(expected, &accounts.Account{Attributes: map[string]interface{}{"login_name": "loginname0"}}) - expected[0], apiErr, err = accountClient.Create(tc.Context(), am.Id, accounts.WithPasswordAccountLoginName(expected[0].Attributes["login_name"].(string))) - assert.NoError(err) - assert.Nil(apiErr) + cr, apiErr, err := accountClient.Create(tc.Context(), am.Id, accounts.WithPasswordAccountLoginName(expected[0].Attributes["login_name"].(string))) + require.NoError(err) + require.Nil(apiErr) + expected[0] = cr.Item - ul, apiErr, err := accountClient.List(tc.Context(), am.Id) - assert.NoError(err) - assert.Nil(apiErr) - assert.ElementsMatch(comparableSlice(expected[:1]), comparableSlice(ul)) + ulResult, apiErr, err := accountClient.List(tc.Context(), am.Id) + require.NoError(err) + require.Nil(apiErr) + assert.ElementsMatch(comparableSlice(expected[:1]), comparableSlice(ulResult.Items)) for i := 1; i < 10; i++ { - newAcct, apiErr, err := accountClient.Create(tc.Context(), am.Id, accounts.WithPasswordAccountLoginName(fmt.Sprintf("loginname%d", i))) - expected = append(expected, newAcct) - assert.NoError(err) - assert.Nil(apiErr) + newAcctResult, apiErr, err := accountClient.Create(tc.Context(), am.Id, accounts.WithPasswordAccountLoginName(fmt.Sprintf("loginname%d", i))) + require.NoError(err) + require.Nil(apiErr) + expected = append(expected, newAcctResult.Item) } - ul, apiErr, err = accountClient.List(tc.Context(), am.Id) + ulResult, apiErr, err = accountClient.List(tc.Context(), am.Id) require.NoError(err) assert.Nil(apiErr) - assert.ElementsMatch(comparableSlice(expected), comparableSlice(ul)) + assert.ElementsMatch(comparableSlice(expected), comparableSlice(ulResult.Items)) } func comparableSlice(in []*accounts.Account) []accounts.Account { @@ -107,21 +110,20 @@ func TestCrud(t *testing.T) { } u, apiErr, err := accountClient.Create(tc.Context(), amId, accounts.WithName("foo"), accounts.WithPasswordAccountLoginName("loginname")) - checkAccount("create", u, apiErr, err, "foo", 1) + checkAccount("create", u.Item, apiErr, err, "foo", 1) - u, apiErr, err = accountClient.Read(tc.Context(), u.Id) - checkAccount("read", u, apiErr, err, "foo", 1) + u, apiErr, err = accountClient.Read(tc.Context(), u.Item.Id) + checkAccount("read", u.Item, apiErr, err, "foo", 1) - 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(), u.Item.Id, u.Item.Version, accounts.WithName("bar")) + checkAccount("update", u.Item, apiErr, err, "bar", 2) - u, apiErr, err = accountClient.Update(tc.Context(), u.Id, u.Version, accounts.DefaultName()) - checkAccount("update", u, apiErr, err, "", 3) + u, apiErr, err = accountClient.Update(tc.Context(), u.Item.Id, u.Item.Version, accounts.DefaultName()) + checkAccount("update", u.Item, apiErr, err, "", 3) - existed, _, err := accountClient.Delete(tc.Context(), u.Id) + _, apiErr, err = accountClient.Delete(tc.Context(), u.Item.Id) require.NoError(err) assert.Nil(apiErr) - assert.True(existed, "Expected existing account when deleted, but it wasn't.") } func TestCustomMethods(t *testing.T) { @@ -139,21 +141,21 @@ func TestCustomMethods(t *testing.T) { al, apiErr, err := accountClient.List(tc.Context(), amId) require.NoError(err) require.Nil(apiErr) - require.Len(al, 1) + require.Len(al.Items, 1) - acct := al[0] + acct := al.Items[0] 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) + assert.Equal(acct.Version+1, setAcct.Item.Version) - changeAcct, apiErr, err := accountClient.ChangePassword(tc.Context(), acct.Id, "setpassword", "changepassword", setAcct.Version) + changeAcct, apiErr, err := accountClient.ChangePassword(tc.Context(), acct.Id, "setpassword", "changepassword", setAcct.Item.Version) require.NoError(err) require.Nil(apiErr) require.NotNil(changeAcct) - assert.Equal(setAcct.Version+1, changeAcct.Version) + assert.Equal(setAcct.Item.Version+1, changeAcct.Item.Version) } func TestErrors(t *testing.T) { @@ -187,7 +189,7 @@ func TestErrors(t *testing.T) { assert.NotNil(apiErr) assert.EqualValues(http.StatusBadRequest, apiErr.Status) - _, apiErr, err = accountClient.Update(tc.Context(), u.Id, u.Version) + _, apiErr, err = accountClient.Update(tc.Context(), u.Item.Id, u.Item.Version) require.NoError(err) assert.NotNil(apiErr) assert.EqualValues(http.StatusBadRequest, apiErr.Status) diff --git a/api/accounts/changepassword.go b/api/accounts/changepassword.go index 95dba51c2..dfa974fb1 100644 --- a/api/accounts/changepassword.go +++ b/api/accounts/changepassword.go @@ -9,7 +9,7 @@ import ( "github.com/kr/pretty" ) -func (c *Client) ChangePassword(ctx context.Context, accountId, currentPassword, newPassword string, version uint32, opt ...Option) (*Account, *api.Error, error) { +func (c *Client) ChangePassword(ctx context.Context, accountId, currentPassword, newPassword string, version uint32, opt ...Option) (*AccountUpdateResult, *api.Error, error) { if accountId == "" { return nil, nil, fmt.Errorf("empty accountId value passed into ChangePassword request") } @@ -33,7 +33,7 @@ func (c *Client) ChangePassword(ctx context.Context, accountId, currentPassword, if existingTarget == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } reqBody := map[string]interface{}{ @@ -52,8 +52,9 @@ func (c *Client) ChangePassword(ctx context.Context, accountId, currentPassword, return nil, nil, fmt.Errorf("error performing client request during ChangePassword call: %w", err) } - target := new(Account) - apiErr, err := resp.Decode(target) + target := new(AccountUpdateResult) + target.Item = new(Account) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding ChangePassword response: %w", err) } diff --git a/api/accounts/password_account_attributes.gen.go b/api/accounts/password_account_attributes.gen.go index ec6f3d56c..2e20d119c 100644 --- a/api/accounts/password_account_attributes.gen.go +++ b/api/accounts/password_account_attributes.gen.go @@ -1,20 +1,7 @@ // Code generated by "make api"; DO NOT EDIT. package accounts -import "bytes" - type PasswordAccountAttributes struct { LoginName string `json:"login_name,omitempty"` Password string `json:"password,omitempty"` - - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} -} - -func (n PasswordAccountAttributes) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody -} - -func (n PasswordAccountAttributes) LastResponseMap() map[string]interface{} { - return n.lastResponseMap } diff --git a/api/accounts/setpassword.go b/api/accounts/setpassword.go index d9e0f7b7d..1ab4ec456 100644 --- a/api/accounts/setpassword.go +++ b/api/accounts/setpassword.go @@ -9,7 +9,7 @@ import ( "github.com/kr/pretty" ) -func (c *Client) SetPassword(ctx context.Context, accountId, password string, version uint32, opt ...Option) (*Account, *api.Error, error) { +func (c *Client) SetPassword(ctx context.Context, accountId, password string, version uint32, opt ...Option) (*AccountUpdateResult, *api.Error, error) { if accountId == "" { return nil, nil, fmt.Errorf("empty accountId value passed into SetPassword request") } @@ -33,7 +33,7 @@ func (c *Client) SetPassword(ctx context.Context, accountId, password string, ve if existingTarget == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } reqBody := map[string]interface{}{ @@ -51,8 +51,9 @@ func (c *Client) SetPassword(ctx context.Context, accountId, password string, ve return nil, nil, fmt.Errorf("error performing client request during SetPassword call: %w", err) } - target := new(Account) - apiErr, err := resp.Decode(target) + target := new(AccountUpdateResult) + target.Item = new(Account) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding SetPassword response: %w", err) } diff --git a/api/authmethods/authenticate.go b/api/authmethods/authenticate.go index fd5cb702c..2f409c0c9 100644 --- a/api/authmethods/authenticate.go +++ b/api/authmethods/authenticate.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/boundary/api/authtokens" ) -func (c *Client) Authenticate(ctx context.Context, authMethodId string, credentials map[string]interface{}, opt ...Option) (*authtokens.AuthToken, *api.Error, error) { +func (c *Client) Authenticate(ctx context.Context, authMethodId string, credentials map[string]interface{}, opt ...Option) (*authtokens.AuthTokenReadResult, *api.Error, error) { if c.client == nil { return nil, nil, fmt.Errorf("nil client in Authenticate request") } @@ -29,8 +29,9 @@ func (c *Client) Authenticate(ctx context.Context, authMethodId string, credenti return nil, nil, fmt.Errorf("error performing client request during Authenticate call: %w", err) } - target := new(authtokens.AuthToken) - apiErr, err := resp.Decode(target) + target := new(authtokens.AuthTokenReadResult) + target.Item = new(authtokens.AuthToken) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Authenticate response: %w", err) } diff --git a/api/authmethods/authenticate_test.go b/api/authmethods/authenticate_test.go index e5bfced97..504f8c4ef 100644 --- a/api/authmethods/authenticate_test.go +++ b/api/authmethods/authenticate_test.go @@ -32,5 +32,5 @@ func TestAuthenticate(t *testing.T) { _, 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) + assert.EqualValuesf(http.StatusUnauthorized, apiErr.Status, "Expected unauthorized, got %q", apiErr.Message) } diff --git a/api/authmethods/authmethods.gen.go b/api/authmethods/authmethods.gen.go index 924b9e54f..8a8258257 100644 --- a/api/authmethods/authmethods.gen.go +++ b/api/authmethods/authmethods.gen.go @@ -6,7 +6,6 @@ import ( "context" "errors" "fmt" - "net/http" "net/url" "time" @@ -28,16 +27,68 @@ type AuthMethod struct { Type string `json:"type,omitempty"` Attributes map[string]interface{} `json:"attributes,omitempty"` - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} + responseBody *bytes.Buffer + responseMap map[string]interface{} } -func (n AuthMethod) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody +func (n AuthMethod) ResponseBody() *bytes.Buffer { + return n.responseBody } -func (n AuthMethod) LastResponseMap() map[string]interface{} { - return n.lastResponseMap +func (n AuthMethod) ResponseMap() map[string]interface{} { + return n.responseMap +} + +type AuthMethodReadResult struct { + Item *AuthMethod + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n AuthMethodReadResult) GetItem() interface{} { + return n.Item +} + +func (n AuthMethodReadResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n AuthMethodReadResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type AuthMethodCreateResult = AuthMethodReadResult +type AuthMethodUpdateResult = AuthMethodReadResult + +type AuthMethodDeleteResult struct { + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n AuthMethodDeleteResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n AuthMethodDeleteResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type AuthMethodListResult struct { + Items []*AuthMethod + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n AuthMethodListResult) GetItems() interface{} { + return n.Items +} + +func (n AuthMethodListResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n AuthMethodListResult) GetResponseMap() map[string]interface{} { + return n.responseMap } // Client is a client for this collection @@ -58,7 +109,7 @@ 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) { +func (c *Client) Create(ctx context.Context, resourceType string, scopeId string, opt ...Option) (*AuthMethodCreateResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into Create request") } @@ -94,18 +145,21 @@ func (c *Client) Create(ctx context.Context, resourceType string, scopeId string return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err) } - target := new(AuthMethod) - apiErr, err := resp.Decode(target) + target := new(AuthMethodCreateResult) + target.Item = new(AuthMethod) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Create response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Read(ctx context.Context, authMethodId string, opt ...Option) (*AuthMethod, *api.Error, error) { +func (c *Client) Read(ctx context.Context, authMethodId string, opt ...Option) (*AuthMethodReadResult, *api.Error, error) { if authMethodId == "" { return nil, nil, fmt.Errorf("empty authMethodId value passed into Read request") } @@ -133,18 +187,21 @@ func (c *Client) Read(ctx context.Context, authMethodId string, opt ...Option) ( return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err) } - target := new(AuthMethod) - apiErr, err := resp.Decode(target) + target := new(AuthMethodReadResult) + target.Item = new(AuthMethod) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Read response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Update(ctx context.Context, authMethodId string, version uint32, opt ...Option) (*AuthMethod, *api.Error, error) { +func (c *Client) Update(ctx context.Context, authMethodId string, version uint32, opt ...Option) (*AuthMethodUpdateResult, *api.Error, error) { if authMethodId == "" { return nil, nil, fmt.Errorf("empty authMethodId value passed into Update request") } @@ -166,9 +223,12 @@ func (c *Client) Update(ctx context.Context, authMethodId string, version uint32 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -191,30 +251,33 @@ func (c *Client) Update(ctx context.Context, authMethodId string, version uint32 return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) } - target := new(AuthMethod) - apiErr, err := resp.Decode(target) + target := new(AuthMethodUpdateResult) + target.Item = new(AuthMethod) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Update response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Delete(ctx context.Context, authMethodId string, opt ...Option) (bool, *api.Error, error) { +func (c *Client) Delete(ctx context.Context, authMethodId string, opt ...Option) (*AuthMethodDeleteResult, *api.Error, error) { if authMethodId == "" { - return false, nil, fmt.Errorf("empty authMethodId value passed into Delete request") + return nil, nil, fmt.Errorf("empty authMethodId value passed into Delete request") } if c.client == nil { - return false, nil, fmt.Errorf("nil client") + return nil, nil, fmt.Errorf("nil client") } opts, apiOpts := getOpts(opt...) req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("auth-methods/%s", authMethodId), nil, apiOpts...) if err != nil { - return false, nil, fmt.Errorf("error creating Delete request: %w", err) + return nil, nil, fmt.Errorf("error creating Delete request: %w", err) } if len(opts.queryMap) > 0 { @@ -227,25 +290,25 @@ func (c *Client) Delete(ctx context.Context, authMethodId string, opt ...Option) resp, err := c.client.Do(req) if err != nil { - return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err) + return nil, nil, fmt.Errorf("error performing client request during Delete call: %w", err) } apiErr, err := resp.Decode(nil) if err != nil { - return false, nil, fmt.Errorf("error decoding Delete response: %w", err) + return nil, nil, fmt.Errorf("error decoding Delete response: %w", err) } if apiErr != nil { - // We don't treat a 404 in this case as failure, in order for deletes to - // be idempotent - if apiErr.Status == http.StatusNotFound { - return false, nil, nil - } - return false, apiErr, nil + return nil, apiErr, nil } - return true, nil, nil + + target := &AuthMethodDeleteResult{ + responseBody: resp.Body, + responseMap: resp.Map, + } + return target, nil, nil } -func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*AuthMethod, *api.Error, error) { +func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) (*AuthMethodListResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into List request") } @@ -274,10 +337,7 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Au return nil, nil, fmt.Errorf("error performing client request during List call: %w", err) } - type listResponse struct { - Items []*AuthMethod - } - target := &listResponse{} + target := new(AuthMethodListResult) apiErr, err := resp.Decode(target) if err != nil { return nil, nil, fmt.Errorf("error decoding List response: %w", err) @@ -285,5 +345,7 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Au if apiErr != nil { return nil, apiErr, nil } - return target.Items, apiErr, nil + target.responseBody = resp.Body + target.responseMap = resp.Map + return target, apiErr, nil } diff --git a/api/authmethods/password_auth_method_attributes.gen.go b/api/authmethods/password_auth_method_attributes.gen.go index 9f1e77354..32b389e63 100644 --- a/api/authmethods/password_auth_method_attributes.gen.go +++ b/api/authmethods/password_auth_method_attributes.gen.go @@ -1,20 +1,7 @@ // Code generated by "make api"; DO NOT EDIT. package authmethods -import "bytes" - type PasswordAuthMethodAttributes struct { MinLoginNameLength uint32 `json:"min_login_name_length,omitempty"` MinPasswordLength uint32 `json:"min_password_length,omitempty"` - - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} -} - -func (n PasswordAuthMethodAttributes) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody -} - -func (n PasswordAuthMethodAttributes) LastResponseMap() map[string]interface{} { - return n.lastResponseMap } diff --git a/api/authtokens/authtoken_test.go b/api/authtokens/authtoken_test.go index b01ed3f96..4ace78c4e 100644 --- a/api/authtokens/authtoken_test.go +++ b/api/authtokens/authtoken_test.go @@ -32,22 +32,22 @@ func TestList(t *testing.T) { org := iam.TestOrg(t, tc.IamRepo(), iam.WithUserId(token.UserId)) amClient := authmethods.NewClient(client) - am, apiErr, err := amClient.Create(tc.Context(), "password", org.GetPublicId()) + amResult, apiErr, err := amClient.Create(tc.Context(), "password", org.GetPublicId()) require.NoError(err) require.Nil(apiErr) - require.NotNil(am) - amId = am.Id + require.NotNil(amResult) + amId = amResult.Item.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)) + role, apiErr, err = rolesClient.AddPrincipals(tc.Context(), role.Item.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)) + role, apiErr, err = rolesClient.AddGrants(tc.Context(), role.Item.Id, 0, []string{"type=auth-method;actions=authenticate"}, roles.WithAutomaticVersioning(true)) require.NoError(err) require.Nil(apiErr) require.NotNil(role) @@ -63,7 +63,7 @@ func TestList(t *testing.T) { atl, apiErr, err := tokens.List(tc.Context(), org.GetPublicId()) require.NoError(err) assert.Nil(apiErr) - assert.Empty(atl) + assert.Empty(atl.Items) var expected []*authtokens.AuthToken methods := authmethods.NewClient(client) @@ -71,23 +71,23 @@ func TestList(t *testing.T) { 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) + expected = append(expected, at.Item) atl, apiErr, err = tokens.List(tc.Context(), org.GetPublicId()) require.NoError(err) assert.Nil(apiErr) - assert.ElementsMatch(comparableSlice(expected), comparableSlice(atl)) + assert.ElementsMatch(comparableSlice(expected), comparableSlice(atl.Items)) for i := 1; i < 10; i++ { 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) + expected = append(expected, at.Item) } atl, apiErr, err = tokens.List(tc.Context(), org.GetPublicId()) require.NoError(err) assert.Nil(apiErr) - assert.ElementsMatch(comparableSlice(expected), comparableSlice(atl)) + assert.ElementsMatch(comparableSlice(expected), comparableSlice(atl.Items)) } func comparableResource(i *authtokens.AuthToken) authtokens.AuthToken { @@ -133,15 +133,14 @@ func TestCrud(t *testing.T) { require.NoError(err) assert.Empty(apiErr) - at, apiErr, err := tokens.Read(tc.Context(), want.Id) + at, apiErr, err := tokens.Read(tc.Context(), want.Item.Id) require.NoError(err) assert.Nil(apiErr) - assert.EqualValues(comparableResource(want), comparableResource(at)) + assert.EqualValues(comparableResource(want.Item), comparableResource(at.Item)) - existed, _, err := tokens.Delete(tc.Context(), at.Id) + _, _, err = tokens.Delete(tc.Context(), at.Item.Id) require.NoError(err) assert.Nil(apiErr) - assert.True(existed, "Expected existing token when deleted, but it wasn't.") } func TestErrors(t *testing.T) { diff --git a/api/authtokens/authtokens.gen.go b/api/authtokens/authtokens.gen.go index 4fea0428f..4edbb47c2 100644 --- a/api/authtokens/authtokens.gen.go +++ b/api/authtokens/authtokens.gen.go @@ -5,7 +5,6 @@ import ( "bytes" "context" "fmt" - "net/http" "net/url" "time" @@ -25,16 +24,68 @@ type AuthToken struct { ApproximateLastUsedTime time.Time `json:"approximate_last_used_time,omitempty"` ExpirationTime time.Time `json:"expiration_time,omitempty"` - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} + responseBody *bytes.Buffer + responseMap map[string]interface{} } -func (n AuthToken) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody +func (n AuthToken) ResponseBody() *bytes.Buffer { + return n.responseBody } -func (n AuthToken) LastResponseMap() map[string]interface{} { - return n.lastResponseMap +func (n AuthToken) ResponseMap() map[string]interface{} { + return n.responseMap +} + +type AuthTokenReadResult struct { + Item *AuthToken + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n AuthTokenReadResult) GetItem() interface{} { + return n.Item +} + +func (n AuthTokenReadResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n AuthTokenReadResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type AuthTokenCreateResult = AuthTokenReadResult +type AuthTokenUpdateResult = AuthTokenReadResult + +type AuthTokenDeleteResult struct { + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n AuthTokenDeleteResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n AuthTokenDeleteResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type AuthTokenListResult struct { + Items []*AuthToken + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n AuthTokenListResult) GetItems() interface{} { + return n.Items +} + +func (n AuthTokenListResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n AuthTokenListResult) GetResponseMap() map[string]interface{} { + return n.responseMap } // Client is a client for this collection @@ -55,7 +106,7 @@ func (c *Client) ApiClient() *api.Client { return c.client } -func (c *Client) Read(ctx context.Context, authTokenId string, opt ...Option) (*AuthToken, *api.Error, error) { +func (c *Client) Read(ctx context.Context, authTokenId string, opt ...Option) (*AuthTokenReadResult, *api.Error, error) { if authTokenId == "" { return nil, nil, fmt.Errorf("empty authTokenId value passed into Read request") } @@ -83,30 +134,33 @@ func (c *Client) Read(ctx context.Context, authTokenId string, opt ...Option) (* return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err) } - target := new(AuthToken) - apiErr, err := resp.Decode(target) + target := new(AuthTokenReadResult) + target.Item = new(AuthToken) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Read response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Delete(ctx context.Context, authTokenId string, opt ...Option) (bool, *api.Error, error) { +func (c *Client) Delete(ctx context.Context, authTokenId string, opt ...Option) (*AuthTokenDeleteResult, *api.Error, error) { if authTokenId == "" { - return false, nil, fmt.Errorf("empty authTokenId value passed into Delete request") + return nil, nil, fmt.Errorf("empty authTokenId value passed into Delete request") } if c.client == nil { - return false, nil, fmt.Errorf("nil client") + return nil, nil, fmt.Errorf("nil client") } opts, apiOpts := getOpts(opt...) req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("auth-tokens/%s", authTokenId), nil, apiOpts...) if err != nil { - return false, nil, fmt.Errorf("error creating Delete request: %w", err) + return nil, nil, fmt.Errorf("error creating Delete request: %w", err) } if len(opts.queryMap) > 0 { @@ -119,25 +173,25 @@ func (c *Client) Delete(ctx context.Context, authTokenId string, opt ...Option) resp, err := c.client.Do(req) if err != nil { - return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err) + return nil, nil, fmt.Errorf("error performing client request during Delete call: %w", err) } apiErr, err := resp.Decode(nil) if err != nil { - return false, nil, fmt.Errorf("error decoding Delete response: %w", err) + return nil, nil, fmt.Errorf("error decoding Delete response: %w", err) } if apiErr != nil { - // We don't treat a 404 in this case as failure, in order for deletes to - // be idempotent - if apiErr.Status == http.StatusNotFound { - return false, nil, nil - } - return false, apiErr, nil + return nil, apiErr, nil } - return true, nil, nil + + target := &AuthTokenDeleteResult{ + responseBody: resp.Body, + responseMap: resp.Map, + } + return target, nil, nil } -func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*AuthToken, *api.Error, error) { +func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) (*AuthTokenListResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into List request") } @@ -166,10 +220,7 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Au return nil, nil, fmt.Errorf("error performing client request during List call: %w", err) } - type listResponse struct { - Items []*AuthToken - } - target := &listResponse{} + target := new(AuthTokenListResult) apiErr, err := resp.Decode(target) if err != nil { return nil, nil, fmt.Errorf("error decoding List response: %w", err) @@ -177,5 +228,7 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Au if apiErr != nil { return nil, apiErr, nil } - return target.Items, apiErr, nil + target.responseBody = resp.Body + target.responseMap = resp.Map + return target, apiErr, nil } diff --git a/api/error.gen.go b/api/error.gen.go index b40489dac..5edebab15 100644 --- a/api/error.gen.go +++ b/api/error.gen.go @@ -9,14 +9,14 @@ type Error struct { Message string `json:"message,omitempty"` Details *ErrorDetails `json:"details,omitempty"` - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} + responseBody *bytes.Buffer + responseMap map[string]interface{} } -func (n Error) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody +func (n Error) ResponseBody() *bytes.Buffer { + return n.responseBody } -func (n Error) LastResponseMap() map[string]interface{} { - return n.lastResponseMap +func (n Error) ResponseMap() map[string]interface{} { + return n.responseMap } diff --git a/api/error_details.gen.go b/api/error_details.gen.go index 0521c8cc0..fe64c3339 100644 --- a/api/error_details.gen.go +++ b/api/error_details.gen.go @@ -1,21 +1,8 @@ // Code generated by "make api"; DO NOT EDIT. package api -import "bytes" - type ErrorDetails struct { TraceId string `json:"TraceId,omitempty"` RequestId string `json:"request_id,omitempty"` RequestFields []*FieldError `json:"request_fields,omitempty"` - - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} -} - -func (n ErrorDetails) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody -} - -func (n ErrorDetails) LastResponseMap() map[string]interface{} { - return n.lastResponseMap } diff --git a/api/field_error.gen.go b/api/field_error.gen.go index e79a6a374..80ad72883 100644 --- a/api/field_error.gen.go +++ b/api/field_error.gen.go @@ -1,20 +1,7 @@ // Code generated by "make api"; DO NOT EDIT. package api -import "bytes" - type FieldError struct { Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` - - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} -} - -func (n FieldError) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody -} - -func (n FieldError) LastResponseMap() map[string]interface{} { - return n.lastResponseMap } diff --git a/api/groups/group.gen.go b/api/groups/group.gen.go index 037d66d34..dae88902b 100644 --- a/api/groups/group.gen.go +++ b/api/groups/group.gen.go @@ -6,7 +6,6 @@ import ( "context" "errors" "fmt" - "net/http" "net/url" "time" @@ -28,16 +27,68 @@ type Group struct { MemberIds []string `json:"member_ids,omitempty"` Members []*Member `json:"members,omitempty"` - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} + responseBody *bytes.Buffer + responseMap map[string]interface{} } -func (n Group) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody +func (n Group) ResponseBody() *bytes.Buffer { + return n.responseBody } -func (n Group) LastResponseMap() map[string]interface{} { - return n.lastResponseMap +func (n Group) ResponseMap() map[string]interface{} { + return n.responseMap +} + +type GroupReadResult struct { + Item *Group + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n GroupReadResult) GetItem() interface{} { + return n.Item +} + +func (n GroupReadResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n GroupReadResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type GroupCreateResult = GroupReadResult +type GroupUpdateResult = GroupReadResult + +type GroupDeleteResult struct { + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n GroupDeleteResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n GroupDeleteResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type GroupListResult struct { + Items []*Group + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n GroupListResult) GetItems() interface{} { + return n.Items +} + +func (n GroupListResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n GroupListResult) GetResponseMap() map[string]interface{} { + return n.responseMap } // Client is a client for this collection @@ -58,7 +109,7 @@ func (c *Client) ApiClient() *api.Client { return c.client } -func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Group, *api.Error, error) { +func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*GroupCreateResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into Create request") } @@ -89,18 +140,21 @@ func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Gr return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err) } - target := new(Group) - apiErr, err := resp.Decode(target) + target := new(GroupCreateResult) + target.Item = new(Group) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Create response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Read(ctx context.Context, groupId string, opt ...Option) (*Group, *api.Error, error) { +func (c *Client) Read(ctx context.Context, groupId string, opt ...Option) (*GroupReadResult, *api.Error, error) { if groupId == "" { return nil, nil, fmt.Errorf("empty groupId value passed into Read request") } @@ -128,18 +182,21 @@ func (c *Client) Read(ctx context.Context, groupId string, opt ...Option) (*Grou return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err) } - target := new(Group) - apiErr, err := resp.Decode(target) + target := new(GroupReadResult) + target.Item = new(Group) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Read response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Update(ctx context.Context, groupId string, version uint32, opt ...Option) (*Group, *api.Error, error) { +func (c *Client) Update(ctx context.Context, groupId string, version uint32, opt ...Option) (*GroupUpdateResult, *api.Error, error) { if groupId == "" { return nil, nil, fmt.Errorf("empty groupId value passed into Update request") } @@ -161,9 +218,12 @@ func (c *Client) Update(ctx context.Context, groupId string, version uint32, opt 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -186,30 +246,33 @@ func (c *Client) Update(ctx context.Context, groupId string, version uint32, opt return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) } - target := new(Group) - apiErr, err := resp.Decode(target) + target := new(GroupUpdateResult) + target.Item = new(Group) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Update response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Delete(ctx context.Context, groupId string, opt ...Option) (bool, *api.Error, error) { +func (c *Client) Delete(ctx context.Context, groupId string, opt ...Option) (*GroupDeleteResult, *api.Error, error) { if groupId == "" { - return false, nil, fmt.Errorf("empty groupId value passed into Delete request") + return nil, nil, fmt.Errorf("empty groupId value passed into Delete request") } if c.client == nil { - return false, nil, fmt.Errorf("nil client") + return nil, nil, fmt.Errorf("nil client") } opts, apiOpts := getOpts(opt...) req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("groups/%s", groupId), nil, apiOpts...) if err != nil { - return false, nil, fmt.Errorf("error creating Delete request: %w", err) + return nil, nil, fmt.Errorf("error creating Delete request: %w", err) } if len(opts.queryMap) > 0 { @@ -222,25 +285,25 @@ func (c *Client) Delete(ctx context.Context, groupId string, opt ...Option) (boo resp, err := c.client.Do(req) if err != nil { - return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err) + return nil, nil, fmt.Errorf("error performing client request during Delete call: %w", err) } apiErr, err := resp.Decode(nil) if err != nil { - return false, nil, fmt.Errorf("error decoding Delete response: %w", err) + return nil, nil, fmt.Errorf("error decoding Delete response: %w", err) } if apiErr != nil { - // We don't treat a 404 in this case as failure, in order for deletes to - // be idempotent - if apiErr.Status == http.StatusNotFound { - return false, nil, nil - } - return false, apiErr, nil + return nil, apiErr, nil } - return true, nil, nil + + target := &GroupDeleteResult{ + responseBody: resp.Body, + responseMap: resp.Map, + } + return target, nil, nil } -func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Group, *api.Error, error) { +func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) (*GroupListResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into List request") } @@ -269,10 +332,7 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Gr return nil, nil, fmt.Errorf("error performing client request during List call: %w", err) } - type listResponse struct { - Items []*Group - } - target := &listResponse{} + target := new(GroupListResult) apiErr, err := resp.Decode(target) if err != nil { return nil, nil, fmt.Errorf("error decoding List response: %w", err) @@ -280,10 +340,12 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Gr if apiErr != nil { return nil, apiErr, nil } - return target.Items, apiErr, nil + target.responseBody = resp.Body + target.responseMap = resp.Map + return target, apiErr, nil } -func (c *Client) AddMembers(ctx context.Context, groupId string, version uint32, memberIds []string, opt ...Option) (*Group, *api.Error, error) { +func (c *Client) AddMembers(ctx context.Context, groupId string, version uint32, memberIds []string, opt ...Option) (*GroupUpdateResult, *api.Error, error) { if groupId == "" { return nil, nil, fmt.Errorf("empty groupId value passed into AddMembers request") } @@ -308,9 +370,12 @@ func (c *Client) AddMembers(ctx context.Context, groupId string, version uint32, 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -334,18 +399,21 @@ func (c *Client) AddMembers(ctx context.Context, groupId string, version uint32, return nil, nil, fmt.Errorf("error performing client request during AddMembers call: %w", err) } - target := new(Group) - apiErr, err := resp.Decode(target) + target := new(GroupUpdateResult) + target.Item = new(Group) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding AddMembers response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) SetMembers(ctx context.Context, groupId string, version uint32, memberIds []string, opt ...Option) (*Group, *api.Error, error) { +func (c *Client) SetMembers(ctx context.Context, groupId string, version uint32, memberIds []string, opt ...Option) (*GroupUpdateResult, *api.Error, error) { if groupId == "" { return nil, nil, fmt.Errorf("empty groupId value passed into SetMembers request") } @@ -368,9 +436,12 @@ func (c *Client) SetMembers(ctx context.Context, groupId string, version uint32, 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -394,18 +465,21 @@ func (c *Client) SetMembers(ctx context.Context, groupId string, version uint32, return nil, nil, fmt.Errorf("error performing client request during SetMembers call: %w", err) } - target := new(Group) - apiErr, err := resp.Decode(target) + target := new(GroupUpdateResult) + target.Item = new(Group) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding SetMembers response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) RemoveMembers(ctx context.Context, groupId string, version uint32, memberIds []string, opt ...Option) (*Group, *api.Error, error) { +func (c *Client) RemoveMembers(ctx context.Context, groupId string, version uint32, memberIds []string, opt ...Option) (*GroupUpdateResult, *api.Error, error) { if groupId == "" { return nil, nil, fmt.Errorf("empty groupId value passed into RemoveMembers request") } @@ -430,9 +504,12 @@ func (c *Client) RemoveMembers(ctx context.Context, groupId string, version uint 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -456,13 +533,16 @@ func (c *Client) RemoveMembers(ctx context.Context, groupId string, version uint return nil, nil, fmt.Errorf("error performing client request during RemoveMembers call: %w", err) } - target := new(Group) - apiErr, err := resp.Decode(target) + target := new(GroupUpdateResult) + target.Item = new(Group) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding RemoveMembers response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } diff --git a/api/groups/group_test.go b/api/groups/group_test.go index 1f37ee81f..927f03acc 100644 --- a/api/groups/group_test.go +++ b/api/groups/group_test.go @@ -44,20 +44,21 @@ func TestList(t *testing.T) { pl, apiErr, err := grps.List(tc.Context(), tt.scopeId) assert.NoError(err) assert.Nil(apiErr) - assert.Empty(pl) + assert.Empty(pl.Items) expected := make([]*groups.Group, 10) for i := 0; i < 10; i++ { - expected[i], apiErr, err = grps.Create(tc.Context(), tt.scopeId, groups.WithName(fmt.Sprint(i))) + createResult, apiErr, err := grps.Create(tc.Context(), tt.scopeId, groups.WithName(fmt.Sprint(i))) require.NoError(err) assert.Nil(apiErr) + expected[i] = createResult.Item } pl, apiErr, err = grps.List(tc.Context(), tt.scopeId) require.NoError(err) assert.Nil(apiErr) require.NotNil(pl) - require.Len(pl, 10) - assert.ElementsMatch(comparableSlice(expected), comparableSlice(pl)) + require.Len(pl.Items, 10) + assert.ElementsMatch(comparableSlice(expected), comparableSlice(pl.Items)) }) } } @@ -131,34 +132,34 @@ func TestCrud(t *testing.T) { t.Run(tt.name, func(t *testing.T) { groupsClient := groups.NewClient(client) g, apiErr, err := groupsClient.Create(tc.Context(), tt.scopeId, groups.WithName("foo")) - checkGroup("create", g, apiErr, err, "foo", 1, nil) + checkGroup("create", g.Item, apiErr, err, "foo", 1, nil) - g, apiErr, err = groupsClient.Read(tc.Context(), g.Id) - checkGroup("read", g, apiErr, err, "foo", 1, nil) + g, apiErr, err = groupsClient.Read(tc.Context(), g.Item.Id) + checkGroup("read", g.Item, apiErr, err, "foo", 1, nil) - g, apiErr, err = groupsClient.Update(tc.Context(), g.Id, g.Version, groups.WithName("bar")) - checkGroup("update", g, apiErr, err, "bar", 2, nil) + g, apiErr, err = groupsClient.Update(tc.Context(), g.Item.Id, g.Item.Version, groups.WithName("bar")) + checkGroup("update", g.Item, apiErr, err, "bar", 2, nil) - g, apiErr, err = groupsClient.Update(tc.Context(), g.Id, g.Version, groups.DefaultName()) - checkGroup("update", g, apiErr, err, "", 3, nil) + g, apiErr, err = groupsClient.Update(tc.Context(), g.Item.Id, g.Item.Version, groups.DefaultName()) + checkGroup("update", g.Item, apiErr, err, "", 3, nil) - g, apiErr, err = groupsClient.AddMembers(tc.Context(), g.Id, g.Version, []string{user1.Id}) - checkGroup("update", g, apiErr, err, "", 4, []string{user1.Id}) + g, apiErr, err = groupsClient.AddMembers(tc.Context(), g.Item.Id, g.Item.Version, []string{user1.Item.Id}) + checkGroup("update", g.Item, apiErr, err, "", 4, []string{user1.Item.Id}) - g, apiErr, err = groupsClient.SetMembers(tc.Context(), g.Id, g.Version, []string{user2.Id}) - checkGroup("update", g, apiErr, err, "", 5, []string{user2.Id}) + g, apiErr, err = groupsClient.SetMembers(tc.Context(), g.Item.Id, g.Item.Version, []string{user2.Item.Id}) + checkGroup("update", g.Item, apiErr, err, "", 5, []string{user2.Item.Id}) - g, apiErr, err = groupsClient.RemoveMembers(tc.Context(), g.Id, g.Version, []string{user2.Id}) - checkGroup("update", g, apiErr, err, "", 6, nil) + g, apiErr, err = groupsClient.RemoveMembers(tc.Context(), g.Item.Id, g.Item.Version, []string{user2.Item.Id}) + checkGroup("update", g.Item, apiErr, err, "", 6, nil) - existed, apiErr, err := groupsClient.Delete(tc.Context(), g.Id) - assert.NoError(err) - assert.True(existed, "Expected existing user when deleted, but it wasn't.") - - existed, apiErr, err = groupsClient.Delete(tc.Context(), g.Id) + _, apiErr, err = groupsClient.Delete(tc.Context(), g.Item.Id) require.NoError(err) assert.Nil(apiErr) - assert.False(existed) + + _, apiErr, err = groupsClient.Delete(tc.Context(), g.Item.Id) + require.NoError(err) + require.NotNil(apiErr) + assert.EqualValues(http.StatusNotFound, apiErr.Status) }) } } @@ -211,7 +212,7 @@ func TestErrors(t *testing.T) { assert.NotNil(apiErr) assert.EqualValues(http.StatusBadRequest, apiErr.Status) - _, apiErr, err = groupClient.Update(tc.Context(), g.Id, g.Version) + _, apiErr, err = groupClient.Update(tc.Context(), g.Item.Id, g.Item.Version) require.NoError(err) assert.NotNil(apiErr) assert.EqualValues(http.StatusBadRequest, apiErr.Status) diff --git a/api/groups/member.gen.go b/api/groups/member.gen.go index 4fb11fd91..351a66d54 100644 --- a/api/groups/member.gen.go +++ b/api/groups/member.gen.go @@ -1,20 +1,7 @@ // Code generated by "make api"; DO NOT EDIT. package groups -import "bytes" - type Member struct { Id string `json:"id,omitempty"` ScopeId string `json:"scope_id,omitempty"` - - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} -} - -func (n Member) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody -} - -func (n Member) LastResponseMap() map[string]interface{} { - return n.lastResponseMap } diff --git a/api/hostcatalogs/host_catalog.gen.go b/api/hostcatalogs/host_catalog.gen.go index d56c0567c..43cb89b34 100644 --- a/api/hostcatalogs/host_catalog.gen.go +++ b/api/hostcatalogs/host_catalog.gen.go @@ -6,7 +6,6 @@ import ( "context" "errors" "fmt" - "net/http" "net/url" "time" @@ -28,16 +27,68 @@ type HostCatalog struct { Type string `json:"type,omitempty"` Attributes map[string]interface{} `json:"attributes,omitempty"` - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} + responseBody *bytes.Buffer + responseMap map[string]interface{} } -func (n HostCatalog) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody +func (n HostCatalog) ResponseBody() *bytes.Buffer { + return n.responseBody } -func (n HostCatalog) LastResponseMap() map[string]interface{} { - return n.lastResponseMap +func (n HostCatalog) ResponseMap() map[string]interface{} { + return n.responseMap +} + +type HostCatalogReadResult struct { + Item *HostCatalog + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n HostCatalogReadResult) GetItem() interface{} { + return n.Item +} + +func (n HostCatalogReadResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n HostCatalogReadResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type HostCatalogCreateResult = HostCatalogReadResult +type HostCatalogUpdateResult = HostCatalogReadResult + +type HostCatalogDeleteResult struct { + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n HostCatalogDeleteResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n HostCatalogDeleteResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type HostCatalogListResult struct { + Items []*HostCatalog + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n HostCatalogListResult) GetItems() interface{} { + return n.Items +} + +func (n HostCatalogListResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n HostCatalogListResult) GetResponseMap() map[string]interface{} { + return n.responseMap } // Client is a client for this collection @@ -58,7 +109,7 @@ 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) { +func (c *Client) Create(ctx context.Context, resourceType string, scopeId string, opt ...Option) (*HostCatalogCreateResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into Create request") } @@ -94,18 +145,21 @@ func (c *Client) Create(ctx context.Context, resourceType string, scopeId string return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err) } - target := new(HostCatalog) - apiErr, err := resp.Decode(target) + target := new(HostCatalogCreateResult) + target.Item = new(HostCatalog) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Create response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Read(ctx context.Context, hostCatalogId string, opt ...Option) (*HostCatalog, *api.Error, error) { +func (c *Client) Read(ctx context.Context, hostCatalogId string, opt ...Option) (*HostCatalogReadResult, *api.Error, error) { if hostCatalogId == "" { return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Read request") } @@ -133,18 +187,21 @@ func (c *Client) Read(ctx context.Context, hostCatalogId string, opt ...Option) return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err) } - target := new(HostCatalog) - apiErr, err := resp.Decode(target) + target := new(HostCatalogReadResult) + target.Item = new(HostCatalog) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Read response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Update(ctx context.Context, hostCatalogId string, version uint32, opt ...Option) (*HostCatalog, *api.Error, error) { +func (c *Client) Update(ctx context.Context, hostCatalogId string, version uint32, opt ...Option) (*HostCatalogUpdateResult, *api.Error, error) { if hostCatalogId == "" { return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Update request") } @@ -166,9 +223,12 @@ func (c *Client) Update(ctx context.Context, hostCatalogId string, version uint3 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -191,30 +251,33 @@ func (c *Client) Update(ctx context.Context, hostCatalogId string, version uint3 return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) } - target := new(HostCatalog) - apiErr, err := resp.Decode(target) + target := new(HostCatalogUpdateResult) + target.Item = new(HostCatalog) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Update response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Delete(ctx context.Context, hostCatalogId string, opt ...Option) (bool, *api.Error, error) { +func (c *Client) Delete(ctx context.Context, hostCatalogId string, opt ...Option) (*HostCatalogDeleteResult, *api.Error, error) { if hostCatalogId == "" { - return false, nil, fmt.Errorf("empty hostCatalogId value passed into Delete request") + return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Delete request") } if c.client == nil { - return false, nil, fmt.Errorf("nil client") + return nil, nil, fmt.Errorf("nil client") } opts, apiOpts := getOpts(opt...) req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("host-catalogs/%s", hostCatalogId), nil, apiOpts...) if err != nil { - return false, nil, fmt.Errorf("error creating Delete request: %w", err) + return nil, nil, fmt.Errorf("error creating Delete request: %w", err) } if len(opts.queryMap) > 0 { @@ -227,25 +290,25 @@ func (c *Client) Delete(ctx context.Context, hostCatalogId string, opt ...Option resp, err := c.client.Do(req) if err != nil { - return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err) + return nil, nil, fmt.Errorf("error performing client request during Delete call: %w", err) } apiErr, err := resp.Decode(nil) if err != nil { - return false, nil, fmt.Errorf("error decoding Delete response: %w", err) + return nil, nil, fmt.Errorf("error decoding Delete response: %w", err) } if apiErr != nil { - // We don't treat a 404 in this case as failure, in order for deletes to - // be idempotent - if apiErr.Status == http.StatusNotFound { - return false, nil, nil - } - return false, apiErr, nil + return nil, apiErr, nil } - return true, nil, nil + + target := &HostCatalogDeleteResult{ + responseBody: resp.Body, + responseMap: resp.Map, + } + return target, nil, nil } -func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*HostCatalog, *api.Error, error) { +func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) (*HostCatalogListResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into List request") } @@ -274,10 +337,7 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Ho return nil, nil, fmt.Errorf("error performing client request during List call: %w", err) } - type listResponse struct { - Items []*HostCatalog - } - target := &listResponse{} + target := new(HostCatalogListResult) apiErr, err := resp.Decode(target) if err != nil { return nil, nil, fmt.Errorf("error decoding List response: %w", err) @@ -285,5 +345,7 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Ho if apiErr != nil { return nil, apiErr, nil } - return target.Items, apiErr, nil + target.responseBody = resp.Body + target.responseMap = resp.Map + return target, apiErr, nil } diff --git a/api/hostcatalogs/host_catalog_test.go b/api/hostcatalogs/host_catalog_test.go index 22659171b..0cdaf560b 100644 --- a/api/hostcatalogs/host_catalog_test.go +++ b/api/hostcatalogs/host_catalog_test.go @@ -26,33 +26,35 @@ func TestList(t *testing.T) { catalogClient := hostcatalogs.NewClient(client) ul, apiErr, err := catalogClient.List(tc.Context(), proj.GetPublicId()) - assert.NoError(err) - assert.Nil(apiErr) - assert.Empty(ul) + require.NoError(err) + require.Nil(apiErr) + assert.Empty(ul.Items) var expected []*hostcatalogs.HostCatalog for i := 0; i < 10; i++ { expected = append(expected, &hostcatalogs.HostCatalog{Name: fmt.Sprint(i)}) } - expected[0], apiErr, err = catalogClient.Create(tc.Context(), "static", proj.GetPublicId(), hostcatalogs.WithName(expected[0].Name)) - assert.NoError(err) - assert.Nil(apiErr) + cr, apiErr, err := catalogClient.Create(tc.Context(), "static", proj.GetPublicId(), hostcatalogs.WithName(expected[0].Name)) + require.NoError(err) + require.Nil(apiErr) + expected[0] = cr.Item ul, apiErr, err = catalogClient.List(tc.Context(), proj.GetPublicId()) - assert.NoError(err) - assert.Nil(apiErr) - assert.ElementsMatch(comparableCatalogSlice(expected[:1]), comparableCatalogSlice(ul)) + require.NoError(err) + require.Nil(apiErr) + assert.ElementsMatch(comparableCatalogSlice(expected[:1]), comparableCatalogSlice(ul.Items)) for i := 1; i < 10; i++ { - expected[i], apiErr, err = catalogClient.Create(tc.Context(), "static", proj.GetPublicId(), hostcatalogs.WithName(expected[i].Name)) - assert.NoError(err) - assert.Nil(apiErr) + cr, apiErr, err = catalogClient.Create(tc.Context(), "static", proj.GetPublicId(), hostcatalogs.WithName(expected[i].Name)) + require.NoError(err) + require.Nil(apiErr) + expected[i] = cr.Item } ul, apiErr, err = catalogClient.List(tc.Context(), proj.GetPublicId()) require.NoError(err) assert.Nil(apiErr) - assert.ElementsMatch(comparableCatalogSlice(expected), comparableCatalogSlice(ul)) + assert.ElementsMatch(comparableCatalogSlice(expected), comparableCatalogSlice(ul.Items)) } func comparableCatalogSlice(in []*hostcatalogs.HostCatalog) []hostcatalogs.HostCatalog { @@ -97,25 +99,25 @@ func TestCrud(t *testing.T) { hcClient := hostcatalogs.NewClient(client) hc, apiErr, err := hcClient.Create(tc.Context(), "static", proj.GetPublicId(), hostcatalogs.WithName("foo")) - checkCatalog("create", hc, apiErr, err, "foo", 1) + checkCatalog("create", hc.Item, apiErr, err, "foo", 1) - hc, apiErr, err = hcClient.Read(tc.Context(), hc.Id) - checkCatalog("read", hc, apiErr, err, "foo", 1) + hc, apiErr, err = hcClient.Read(tc.Context(), hc.Item.Id) + checkCatalog("read", hc.Item, apiErr, err, "foo", 1) - hc, apiErr, err = hcClient.Update(tc.Context(), hc.Id, hc.Version, hostcatalogs.WithName("bar")) - checkCatalog("update", hc, apiErr, err, "bar", 2) + hc, apiErr, err = hcClient.Update(tc.Context(), hc.Item.Id, hc.Item.Version, hostcatalogs.WithName("bar")) + checkCatalog("update", hc.Item, apiErr, err, "bar", 2) - hc, apiErr, err = hcClient.Update(tc.Context(), hc.Id, hc.Version, hostcatalogs.DefaultName()) - checkCatalog("update", hc, apiErr, err, "", 3) + hc, apiErr, err = hcClient.Update(tc.Context(), hc.Item.Id, hc.Item.Version, hostcatalogs.DefaultName()) + checkCatalog("update", hc.Item, apiErr, err, "", 3) - existed, apiErr, err := hcClient.Delete(tc.Context(), hc.Id) + _, apiErr, err = hcClient.Delete(tc.Context(), hc.Item.Id) assert.NoError(err) - assert.True(existed, "Expected existing catalog when deleted, but it wasn't.") - - existed, apiErr, err = hcClient.Delete(tc.Context(), hc.Id) - require.NoError(err) assert.Nil(apiErr) - assert.False(existed) + + _, apiErr, err = hcClient.Delete(tc.Context(), hc.Item.Id) + require.NoError(err) + assert.NotNil(apiErr) + assert.EqualValues(http.StatusNotFound, apiErr.Status) } // TODO: Get better coverage for expected errors and error formats. diff --git a/api/hosts/host.gen.go b/api/hosts/host.gen.go index 68b537080..fd917e2b3 100644 --- a/api/hosts/host.gen.go +++ b/api/hosts/host.gen.go @@ -6,7 +6,6 @@ import ( "context" "errors" "fmt" - "net/http" "net/url" "time" @@ -29,16 +28,68 @@ type Host struct { HostSetIds []string `json:"host_set_ids,omitempty"` Attributes map[string]interface{} `json:"attributes,omitempty"` - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} + responseBody *bytes.Buffer + responseMap map[string]interface{} } -func (n Host) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody +func (n Host) ResponseBody() *bytes.Buffer { + return n.responseBody } -func (n Host) LastResponseMap() map[string]interface{} { - return n.lastResponseMap +func (n Host) ResponseMap() map[string]interface{} { + return n.responseMap +} + +type HostReadResult struct { + Item *Host + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n HostReadResult) GetItem() interface{} { + return n.Item +} + +func (n HostReadResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n HostReadResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type HostCreateResult = HostReadResult +type HostUpdateResult = HostReadResult + +type HostDeleteResult struct { + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n HostDeleteResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n HostDeleteResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type HostListResult struct { + Items []*Host + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n HostListResult) GetItems() interface{} { + return n.Items +} + +func (n HostListResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n HostListResult) GetResponseMap() map[string]interface{} { + return n.responseMap } // Client is a client for this collection @@ -59,7 +110,7 @@ func (c *Client) ApiClient() *api.Client { return c.client } -func (c *Client) Create(ctx context.Context, hostCatalogId string, opt ...Option) (*Host, *api.Error, error) { +func (c *Client) Create(ctx context.Context, hostCatalogId string, opt ...Option) (*HostCreateResult, *api.Error, error) { if hostCatalogId == "" { return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Create request") } @@ -90,18 +141,21 @@ func (c *Client) Create(ctx context.Context, hostCatalogId string, opt ...Option return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err) } - target := new(Host) - apiErr, err := resp.Decode(target) + target := new(HostCreateResult) + target.Item = new(Host) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Create response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Read(ctx context.Context, hostId string, opt ...Option) (*Host, *api.Error, error) { +func (c *Client) Read(ctx context.Context, hostId string, opt ...Option) (*HostReadResult, *api.Error, error) { if hostId == "" { return nil, nil, fmt.Errorf("empty hostId value passed into Read request") } @@ -129,18 +183,21 @@ func (c *Client) Read(ctx context.Context, hostId string, opt ...Option) (*Host, return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err) } - target := new(Host) - apiErr, err := resp.Decode(target) + target := new(HostReadResult) + target.Item = new(Host) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Read response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Update(ctx context.Context, hostId string, version uint32, opt ...Option) (*Host, *api.Error, error) { +func (c *Client) Update(ctx context.Context, hostId string, version uint32, opt ...Option) (*HostUpdateResult, *api.Error, error) { if hostId == "" { return nil, nil, fmt.Errorf("empty hostId value passed into Update request") } @@ -162,9 +219,12 @@ func (c *Client) Update(ctx context.Context, hostId string, version uint32, opt 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -187,30 +247,33 @@ func (c *Client) Update(ctx context.Context, hostId string, version uint32, opt return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) } - target := new(Host) - apiErr, err := resp.Decode(target) + target := new(HostUpdateResult) + target.Item = new(Host) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Update response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Delete(ctx context.Context, hostId string, opt ...Option) (bool, *api.Error, error) { +func (c *Client) Delete(ctx context.Context, hostId string, opt ...Option) (*HostDeleteResult, *api.Error, error) { if hostId == "" { - return false, nil, fmt.Errorf("empty hostId value passed into Delete request") + return nil, nil, fmt.Errorf("empty hostId value passed into Delete request") } if c.client == nil { - return false, nil, fmt.Errorf("nil client") + return nil, nil, fmt.Errorf("nil client") } opts, apiOpts := getOpts(opt...) 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) + return nil, nil, fmt.Errorf("error creating Delete request: %w", err) } if len(opts.queryMap) > 0 { @@ -223,25 +286,25 @@ func (c *Client) Delete(ctx context.Context, hostId string, opt ...Option) (bool resp, err := c.client.Do(req) if err != nil { - return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err) + return nil, nil, fmt.Errorf("error performing client request during Delete call: %w", err) } apiErr, err := resp.Decode(nil) if err != nil { - return false, nil, fmt.Errorf("error decoding Delete response: %w", err) + return nil, nil, fmt.Errorf("error decoding Delete response: %w", err) } if apiErr != nil { - // We don't treat a 404 in this case as failure, in order for deletes to - // be idempotent - if apiErr.Status == http.StatusNotFound { - return false, nil, nil - } - return false, apiErr, nil + return nil, apiErr, nil } - return true, nil, nil + + target := &HostDeleteResult{ + responseBody: resp.Body, + responseMap: resp.Map, + } + return target, nil, nil } -func (c *Client) List(ctx context.Context, hostCatalogId string, opt ...Option) ([]*Host, *api.Error, error) { +func (c *Client) List(ctx context.Context, hostCatalogId string, opt ...Option) (*HostListResult, *api.Error, error) { if hostCatalogId == "" { return nil, nil, fmt.Errorf("empty hostCatalogId value passed into List request") } @@ -270,10 +333,7 @@ func (c *Client) List(ctx context.Context, hostCatalogId string, opt ...Option) return nil, nil, fmt.Errorf("error performing client request during List call: %w", err) } - type listResponse struct { - Items []*Host - } - target := &listResponse{} + target := new(HostListResult) apiErr, err := resp.Decode(target) if err != nil { return nil, nil, fmt.Errorf("error decoding List response: %w", err) @@ -281,5 +341,7 @@ func (c *Client) List(ctx context.Context, hostCatalogId string, opt ...Option) if apiErr != nil { return nil, apiErr, nil } - return target.Items, apiErr, nil + target.responseBody = resp.Body + target.responseMap = resp.Map + return target, apiErr, nil } diff --git a/api/hosts/host_test.go b/api/hosts/host_test.go index 0ea2d35a3..5e9ed4749 100644 --- a/api/hosts/host_test.go +++ b/api/hosts/host_test.go @@ -32,34 +32,36 @@ func TestList(t *testing.T) { hClient := hosts.NewClient(client) - ul, apiErr, err := hClient.List(tc.Context(), hc.Id) + ul, apiErr, err := hClient.List(tc.Context(), hc.Item.Id) assert.NoError(err) assert.Nil(apiErr) - assert.Empty(ul) + assert.Empty(ul.Items) var expected []*hosts.Host for i := 0; i < 10; i++ { expected = append(expected, &hosts.Host{Name: fmt.Sprint(i)}) } - expected[0], apiErr, err = hClient.Create(tc.Context(), hc.Id, hosts.WithName(expected[0].Name), hosts.WithStaticHostAddress("someaddress")) + hcr, apiErr, err := hClient.Create(tc.Context(), hc.Item.Id, hosts.WithName(expected[0].Name), hosts.WithStaticHostAddress("someaddress")) assert.NoError(err) assert.Nil(apiErr) + expected[0] = hcr.Item - ul, apiErr, err = hClient.List(tc.Context(), hc.Id) + ul, apiErr, err = hClient.List(tc.Context(), hc.Item.Id) assert.NoError(err) assert.Nil(apiErr) - assert.ElementsMatch(comparableHostSlice(expected[:1]), comparableHostSlice(ul)) + assert.ElementsMatch(comparableHostSlice(expected[:1]), comparableHostSlice(ul.Items)) for i := 1; i < 10; i++ { - expected[i], apiErr, err = hClient.Create(tc.Context(), hc.Id, hosts.WithName(expected[i].Name), hosts.WithStaticHostAddress("someaddress")) + hcr, apiErr, err = hClient.Create(tc.Context(), hc.Item.Id, hosts.WithName(expected[i].Name), hosts.WithStaticHostAddress("someaddress")) assert.NoError(err) assert.Nil(apiErr) + expected[i] = hcr.Item } - ul, apiErr, err = hClient.List(tc.Context(), hc.Id) + ul, apiErr, err = hClient.List(tc.Context(), hc.Item.Id) require.NoError(err) assert.Nil(apiErr) - assert.ElementsMatch(comparableHostSlice(expected), comparableHostSlice(ul)) + assert.ElementsMatch(comparableHostSlice(expected), comparableHostSlice(ul.Items)) } func comparableHostSlice(in []*hosts.Host) []hosts.Host { @@ -108,26 +110,26 @@ func TestCrud(t *testing.T) { 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.Create(tc.Context(), hc.Item.Id, hosts.WithName("foo"), hosts.WithStaticHostAddress("someaddress")) + checkHost("create", h.Item, apiErr, err, "foo", 1) - h, apiErr, err = hClient.Read(tc.Context(), h.Id) - checkHost("read", h, apiErr, err, "foo", 1) + h, apiErr, err = hClient.Read(tc.Context(), h.Item.Id) + checkHost("read", h.Item, apiErr, err, "foo", 1) - 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(), h.Item.Id, h.Item.Version, hosts.WithName("bar")) + checkHost("update", h.Item, apiErr, err, "bar", 2) - h, apiErr, err = hClient.Update(tc.Context(), h.Id, h.Version, hosts.DefaultName()) - checkHost("update", h, apiErr, err, "", 3) + h, apiErr, err = hClient.Update(tc.Context(), h.Item.Id, h.Item.Version, hosts.DefaultName()) + checkHost("update", h.Item, apiErr, err, "", 3) - existed, apiErr, err := hClient.Delete(tc.Context(), h.Id) + _, apiErr, err = hClient.Delete(tc.Context(), h.Item.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.Nil(apiErr) - assert.False(existed) + + _, apiErr, err = hClient.Delete(tc.Context(), h.Item.Id) + require.NoError(err) + assert.NotNil(apiErr) + assert.EqualValues(http.StatusNotFound, apiErr.Status) } // TODO: Get better coverage for expected errors and error formats. @@ -148,12 +150,12 @@ func TestErrors(t *testing.T) { hClient := hosts.NewClient(client) - h, apiErr, err := hClient.Create(tc.Context(), hc.Id, hosts.WithName("foo"), hosts.WithStaticHostAddress("someaddress")) + h, apiErr, err := hClient.Create(tc.Context(), hc.Item.Id, hosts.WithName("foo"), hosts.WithStaticHostAddress("someaddress")) require.NoError(err) require.Nil(apiErr) assert.NotNil(h) - _, apiErr, err = hClient.Create(tc.Context(), hc.Id, hosts.WithName("foo"), hosts.WithStaticHostAddress("someaddress")) + _, apiErr, err = hClient.Create(tc.Context(), hc.Item.Id, hosts.WithName("foo"), hosts.WithStaticHostAddress("someaddress")) require.NoError(err) assert.NotNil(apiErr) diff --git a/api/hosts/static_host_attributes.gen.go b/api/hosts/static_host_attributes.gen.go index e7d3fdce2..f16d27136 100644 --- a/api/hosts/static_host_attributes.gen.go +++ b/api/hosts/static_host_attributes.gen.go @@ -1,19 +1,6 @@ // Code generated by "make api"; DO NOT EDIT. package hosts -import "bytes" - type StaticHostAttributes struct { Address string `json:"address,omitempty"` - - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} -} - -func (n StaticHostAttributes) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody -} - -func (n StaticHostAttributes) LastResponseMap() map[string]interface{} { - return n.lastResponseMap } diff --git a/api/hostsets/host_set.gen.go b/api/hostsets/host_set.gen.go index 4d21e406f..d14c42c19 100644 --- a/api/hostsets/host_set.gen.go +++ b/api/hostsets/host_set.gen.go @@ -6,7 +6,6 @@ import ( "context" "errors" "fmt" - "net/http" "net/url" "time" @@ -29,16 +28,68 @@ type HostSet struct { HostIds []string `json:"host_ids,omitempty"` Attributes map[string]interface{} `json:"attributes,omitempty"` - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} + responseBody *bytes.Buffer + responseMap map[string]interface{} } -func (n HostSet) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody +func (n HostSet) ResponseBody() *bytes.Buffer { + return n.responseBody } -func (n HostSet) LastResponseMap() map[string]interface{} { - return n.lastResponseMap +func (n HostSet) ResponseMap() map[string]interface{} { + return n.responseMap +} + +type HostSetReadResult struct { + Item *HostSet + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n HostSetReadResult) GetItem() interface{} { + return n.Item +} + +func (n HostSetReadResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n HostSetReadResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type HostSetCreateResult = HostSetReadResult +type HostSetUpdateResult = HostSetReadResult + +type HostSetDeleteResult struct { + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n HostSetDeleteResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n HostSetDeleteResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type HostSetListResult struct { + Items []*HostSet + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n HostSetListResult) GetItems() interface{} { + return n.Items +} + +func (n HostSetListResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n HostSetListResult) GetResponseMap() map[string]interface{} { + return n.responseMap } // Client is a client for this collection @@ -59,7 +110,7 @@ func (c *Client) ApiClient() *api.Client { return c.client } -func (c *Client) Create(ctx context.Context, hostCatalogId string, opt ...Option) (*HostSet, *api.Error, error) { +func (c *Client) Create(ctx context.Context, hostCatalogId string, opt ...Option) (*HostSetCreateResult, *api.Error, error) { if hostCatalogId == "" { return nil, nil, fmt.Errorf("empty hostCatalogId value passed into Create request") } @@ -90,18 +141,21 @@ func (c *Client) Create(ctx context.Context, hostCatalogId string, opt ...Option return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err) } - target := new(HostSet) - apiErr, err := resp.Decode(target) + target := new(HostSetCreateResult) + target.Item = new(HostSet) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Create response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Read(ctx context.Context, hostSetId string, opt ...Option) (*HostSet, *api.Error, error) { +func (c *Client) Read(ctx context.Context, hostSetId string, opt ...Option) (*HostSetReadResult, *api.Error, error) { if hostSetId == "" { return nil, nil, fmt.Errorf("empty hostSetId value passed into Read request") } @@ -129,18 +183,21 @@ func (c *Client) Read(ctx context.Context, hostSetId string, opt ...Option) (*Ho return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err) } - target := new(HostSet) - apiErr, err := resp.Decode(target) + target := new(HostSetReadResult) + target.Item = new(HostSet) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Read response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Update(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) (*HostSetUpdateResult, *api.Error, error) { if hostSetId == "" { return nil, nil, fmt.Errorf("empty hostSetId value passed into Update request") } @@ -162,9 +219,12 @@ func (c *Client) Update(ctx context.Context, hostSetId string, version uint32, o 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -187,30 +247,33 @@ func (c *Client) Update(ctx context.Context, hostSetId string, version uint32, o return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) } - target := new(HostSet) - apiErr, err := resp.Decode(target) + target := new(HostSetUpdateResult) + target.Item = new(HostSet) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Update response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Delete(ctx context.Context, hostSetId string, opt ...Option) (bool, *api.Error, error) { +func (c *Client) Delete(ctx context.Context, hostSetId string, opt ...Option) (*HostSetDeleteResult, *api.Error, error) { if hostSetId == "" { - return false, nil, fmt.Errorf("empty hostSetId value passed into Delete request") + return nil, nil, fmt.Errorf("empty hostSetId value passed into Delete request") } if c.client == nil { - return false, nil, fmt.Errorf("nil client") + return nil, nil, fmt.Errorf("nil client") } opts, apiOpts := getOpts(opt...) req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("host-sets/%s", hostSetId), nil, apiOpts...) if err != nil { - return false, nil, fmt.Errorf("error creating Delete request: %w", err) + return nil, nil, fmt.Errorf("error creating Delete request: %w", err) } if len(opts.queryMap) > 0 { @@ -223,25 +286,25 @@ func (c *Client) Delete(ctx context.Context, hostSetId string, opt ...Option) (b resp, err := c.client.Do(req) if err != nil { - return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err) + return nil, nil, fmt.Errorf("error performing client request during Delete call: %w", err) } apiErr, err := resp.Decode(nil) if err != nil { - return false, nil, fmt.Errorf("error decoding Delete response: %w", err) + return nil, nil, fmt.Errorf("error decoding Delete response: %w", err) } if apiErr != nil { - // We don't treat a 404 in this case as failure, in order for deletes to - // be idempotent - if apiErr.Status == http.StatusNotFound { - return false, nil, nil - } - return false, apiErr, nil + return nil, apiErr, nil } - return true, nil, nil + + target := &HostSetDeleteResult{ + responseBody: resp.Body, + responseMap: resp.Map, + } + return target, nil, nil } -func (c *Client) List(ctx context.Context, hostCatalogId string, opt ...Option) ([]*HostSet, *api.Error, error) { +func (c *Client) List(ctx context.Context, hostCatalogId string, opt ...Option) (*HostSetListResult, *api.Error, error) { if hostCatalogId == "" { return nil, nil, fmt.Errorf("empty hostCatalogId value passed into List request") } @@ -270,10 +333,7 @@ func (c *Client) List(ctx context.Context, hostCatalogId string, opt ...Option) return nil, nil, fmt.Errorf("error performing client request during List call: %w", err) } - type listResponse struct { - Items []*HostSet - } - target := &listResponse{} + target := new(HostSetListResult) apiErr, err := resp.Decode(target) if err != nil { return nil, nil, fmt.Errorf("error decoding List response: %w", err) @@ -281,10 +341,12 @@ func (c *Client) List(ctx context.Context, hostCatalogId string, opt ...Option) if apiErr != nil { return nil, apiErr, nil } - return target.Items, apiErr, nil + target.responseBody = resp.Body + target.responseMap = resp.Map + return target, apiErr, nil } -func (c *Client) AddHosts(ctx context.Context, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSet, *api.Error, error) { +func (c *Client) AddHosts(ctx context.Context, hostSetId string, version uint32, hostIds []string, opt ...Option) (*HostSetUpdateResult, *api.Error, error) { if hostSetId == "" { return nil, nil, fmt.Errorf("empty hostSetId value passed into AddHosts request") } @@ -309,9 +371,12 @@ func (c *Client) AddHosts(ctx context.Context, hostSetId string, version uint32, 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -335,18 +400,21 @@ func (c *Client) AddHosts(ctx context.Context, hostSetId string, version uint32, return nil, nil, fmt.Errorf("error performing client request during AddHosts call: %w", err) } - target := new(HostSet) - apiErr, err := resp.Decode(target) + target := new(HostSetUpdateResult) + target.Item = new(HostSet) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding AddHosts response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) SetHosts(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) (*HostSetUpdateResult, *api.Error, error) { if hostSetId == "" { return nil, nil, fmt.Errorf("empty hostSetId value passed into SetHosts request") } @@ -369,9 +437,12 @@ func (c *Client) SetHosts(ctx context.Context, hostSetId string, version uint32, 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -395,18 +466,21 @@ func (c *Client) SetHosts(ctx context.Context, hostSetId string, version uint32, return nil, nil, fmt.Errorf("error performing client request during SetHosts call: %w", err) } - target := new(HostSet) - apiErr, err := resp.Decode(target) + target := new(HostSetUpdateResult) + target.Item = new(HostSet) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding SetHosts response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) RemoveHosts(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) (*HostSetUpdateResult, *api.Error, error) { if hostSetId == "" { return nil, nil, fmt.Errorf("empty hostSetId value passed into RemoveHosts request") } @@ -431,9 +505,12 @@ func (c *Client) RemoveHosts(ctx context.Context, hostSetId string, version uint 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -457,13 +534,16 @@ func (c *Client) RemoveHosts(ctx context.Context, hostSetId string, version uint return nil, nil, fmt.Errorf("error performing client request during RemoveHosts call: %w", err) } - target := new(HostSet) - apiErr, err := resp.Decode(target) + target := new(HostSetUpdateResult) + target.Item = new(HostSet) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding RemoveHosts response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } diff --git a/api/hostsets/host_set_test.go b/api/hostsets/host_set_test.go index a2c95ea3d..8c08d2b33 100644 --- a/api/hostsets/host_set_test.go +++ b/api/hostsets/host_set_test.go @@ -32,33 +32,32 @@ func TestCustom(t *testing.T) { require.Nil(apiErr) hClient := hosts.NewClient(client) - h1, apiErr, err := hClient.Create(tc.Context(), hc.Id, hosts.WithStaticHostAddress("someaddress")) + h1, apiErr, err := hClient.Create(tc.Context(), hc.Item.Id, hosts.WithStaticHostAddress("someaddress")) require.NoError(err) require.Nil(apiErr) - h2, apiErr, err := hClient.Create(tc.Context(), hc.Id, hosts.WithStaticHostAddress("someaddress")) + h2, apiErr, err := hClient.Create(tc.Context(), hc.Item.Id, hosts.WithStaticHostAddress("someaddress")) require.NoError(err) require.Nil(apiErr) hSetClient := hostsets.NewClient(client) - var hSet *hostsets.HostSet - hSet, apiErr, err = hSetClient.Create(tc.Context(), hc.Id) + hSet, apiErr, err := hSetClient.Create(tc.Context(), hc.Item.Id) require.NoError(err) require.Nil(apiErr) - hSet, apiErr, err = hSetClient.AddHosts(tc.Context(), hSet.Id, hSet.Version, []string{h1.Id, h2.Id}) + hSet, apiErr, err = hSetClient.AddHosts(tc.Context(), hSet.Item.Id, hSet.Item.Version, []string{h1.Item.Id, h2.Item.Id}) require.NoError(err) require.Nil(apiErr) - assert.Contains(hSet.HostIds, h1.Id, h2.Id) + assert.Contains(hSet.Item.HostIds, h1.Item.Id, h2.Item.Id) - hSet, apiErr, err = hSetClient.SetHosts(tc.Context(), hSet.Id, hSet.Version, []string{h1.Id}) + hSet, apiErr, err = hSetClient.SetHosts(tc.Context(), hSet.Item.Id, hSet.Item.Version, []string{h1.Item.Id}) require.NoError(err) require.Nil(apiErr, pretty.Sprint(apiErr)) - assert.ElementsMatch([]string{h1.Id}, hSet.HostIds) + assert.ElementsMatch([]string{h1.Item.Id}, hSet.Item.HostIds) - hSet, apiErr, err = hSetClient.RemoveHosts(tc.Context(), hSet.Id, hSet.Version, []string{h1.Id}) + hSet, apiErr, err = hSetClient.RemoveHosts(tc.Context(), hSet.Item.Id, hSet.Item.Version, []string{h1.Item.Id}) require.NoError(err) require.Nil(apiErr) - assert.Empty(hSet.HostIds) + assert.Empty(hSet.Item.HostIds) } func TestList(t *testing.T) { @@ -77,36 +76,37 @@ func TestList(t *testing.T) { require.NotNil(hc) hClient := hostsets.NewClient(client) - var ul []*hostsets.HostSet - ul, apiErr, err = hClient.List(tc.Context(), hc.Id) + ul, apiErr, err := hClient.List(tc.Context(), hc.Item.Id) require.NoError(err) require.Nil(apiErr) - assert.Empty(ul) + assert.Empty(ul.Items) 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)) + hcr, apiErr, err := hClient.Create(tc.Context(), hc.Item.Id, hostsets.WithName(expected[0].Name)) require.NoError(err) require.Nil(apiErr) + expected[0] = hcr.Item - ul, apiErr, err = hClient.List(tc.Context(), hc.Id) + ul, apiErr, err = hClient.List(tc.Context(), hc.Item.Id) require.NoError(err) require.Nil(apiErr) - assert.ElementsMatch(comparableSetSlice(expected[:1]), comparableSetSlice(ul)) + assert.ElementsMatch(comparableSetSlice(expected[:1]), comparableSetSlice(ul.Items)) for i := 1; i < 10; i++ { - expected[i], apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName(expected[i].Name)) + hcr, apiErr, err = hClient.Create(tc.Context(), hc.Item.Id, hostsets.WithName(expected[i].Name)) require.NoError(err) require.Nil(apiErr) + expected[i] = hcr.Item } - ul, apiErr, err = hClient.List(tc.Context(), hc.Id) + ul, apiErr, err = hClient.List(tc.Context(), hc.Item.Id) require.NoError(err) require.Nil(apiErr) - assert.ElementsMatch(comparableSetSlice(expected), comparableSetSlice(ul)) + assert.ElementsMatch(comparableSetSlice(expected), comparableSetSlice(ul.Items)) } func comparableSetSlice(in []*hostsets.HostSet) []hostsets.HostSet { @@ -156,27 +156,25 @@ func TestCrud(t *testing.T) { 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.Create(tc.Context(), hc.Item.Id, hostsets.WithName("foo")) + checkHost(t, "create", h.Item, 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.Read(tc.Context(), h.Item.Id) + checkHost(t, "read", h.Item, 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.Item.Id, h.Item.Version, hostsets.WithName("bar")) + checkHost(t, "update", h.Item, apiErr, err, "bar", 2) - h, apiErr, err = hClient.Update(tc.Context(), h.Id, h.Version, hostsets.DefaultName()) - checkHost(t, "update", h, apiErr, err, "", 3) + h, apiErr, err = hClient.Update(tc.Context(), h.Item.Id, h.Item.Version, hostsets.DefaultName()) + checkHost(t, "update", h.Item, apiErr, err, "", 3) - var existed bool - existed, apiErr, err = hClient.Delete(tc.Context(), h.Id) + _, apiErr, err = hClient.Delete(tc.Context(), h.Item.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.Nil(apiErr) - assert.False(existed) + _, apiErr, err = hClient.Delete(tc.Context(), h.Item.Id) + require.NoError(err) + assert.NotNil(apiErr) + assert.EqualValues(http.StatusNotFound, apiErr.Status) } // TODO: Get better coverage for expected errors and error formats. @@ -197,13 +195,12 @@ func TestErrors(t *testing.T) { hClient := hostsets.NewClient(client) - var h *hostsets.HostSet - h, apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName("foo")) + h, apiErr, err := hClient.Create(tc.Context(), hc.Item.Id, hostsets.WithName("foo")) require.NoError(err) require.Nil(apiErr) assert.NotNil(h) - h, apiErr, err = hClient.Create(tc.Context(), hc.Id, hostsets.WithName("foo")) + h, apiErr, err = hClient.Create(tc.Context(), hc.Item.Id, hostsets.WithName("foo")) require.NoError(err) assert.NotNil(apiErr) assert.Nil(h) diff --git a/api/internal/genapi/input.go b/api/internal/genapi/input.go index 53d9c37e4..f81cfb388 100644 --- a/api/internal/genapi/input.go +++ b/api/internal/genapi/input.go @@ -80,6 +80,9 @@ type structInfo struct { // given type, e.g. arguments only valid for one call or purpose and not // conveyed within the item itself extraOptions []fieldInfo + + // createResponseTypes controls for which structs response types are created + createResponseTypes bool } var inputStructs = []*structInfo{ @@ -124,7 +127,8 @@ var inputStructs = []*structInfo{ Query: true, }, }, - versionEnabled: true, + versionEnabled: true, + createResponseTypes: true, }, // User related resources { @@ -138,8 +142,9 @@ var inputStructs = []*structInfo{ deleteTemplate, listTemplate, }, - pathArgs: []string{"user"}, - versionEnabled: true, + pathArgs: []string{"user"}, + versionEnabled: true, + createResponseTypes: true, }, // Group related resources { @@ -161,8 +166,9 @@ var inputStructs = []*structInfo{ sliceSubTypes: map[string]string{ "Members": "memberIds", }, - pathArgs: []string{"group"}, - versionEnabled: true, + pathArgs: []string{"group"}, + versionEnabled: true, + createResponseTypes: true, }, // Role related resources { @@ -195,8 +201,9 @@ var inputStructs = []*structInfo{ "Principals": "principalIds", "Grants": "grantStrings", }, - pathArgs: []string{"role"}, - versionEnabled: true, + pathArgs: []string{"role"}, + versionEnabled: true, + createResponseTypes: true, }, // Auth Methods related resources { @@ -210,9 +217,10 @@ var inputStructs = []*structInfo{ deleteTemplate, listTemplate, }, - pathArgs: []string{"auth-method"}, - typeOnCreate: true, - versionEnabled: true, + pathArgs: []string{"auth-method"}, + typeOnCreate: true, + versionEnabled: true, + createResponseTypes: true, }, { inProto: &authmethods.PasswordAuthMethodAttributes{}, @@ -231,9 +239,10 @@ var inputStructs = []*structInfo{ deleteTemplate, listTemplate, }, - pathArgs: []string{"account"}, - parentTypeName: "auth-method", - versionEnabled: true, + pathArgs: []string{"account"}, + parentTypeName: "auth-method", + versionEnabled: true, + createResponseTypes: true, }, { inProto: &accounts.PasswordAccountAttributes{}, @@ -250,7 +259,8 @@ var inputStructs = []*structInfo{ deleteTemplate, listTemplate, }, - pathArgs: []string{"auth-token"}, + pathArgs: []string{"auth-token"}, + createResponseTypes: true, }, // Host related resources { @@ -264,9 +274,10 @@ var inputStructs = []*structInfo{ deleteTemplate, listTemplate, }, - pathArgs: []string{"host-catalog"}, - typeOnCreate: true, - versionEnabled: true, + pathArgs: []string{"host-catalog"}, + typeOnCreate: true, + versionEnabled: true, + createResponseTypes: true, }, { inProto: &hosts.Host{}, @@ -279,9 +290,10 @@ var inputStructs = []*structInfo{ deleteTemplate, listTemplate, }, - pathArgs: []string{"host"}, - parentTypeName: "host-catalog", - versionEnabled: true, + pathArgs: []string{"host"}, + parentTypeName: "host-catalog", + versionEnabled: true, + createResponseTypes: true, }, { inProto: &hosts.StaticHostAttributes{}, @@ -304,7 +316,8 @@ var inputStructs = []*structInfo{ sliceSubTypes: map[string]string{ "Hosts": "hostIds", }, - versionEnabled: true, + versionEnabled: true, + createResponseTypes: true, }, { inProto: &targets.HostSet{}, @@ -325,7 +338,8 @@ var inputStructs = []*structInfo{ sliceSubTypes: map[string]string{ "HostSets": "hostSetIds", }, - versionEnabled: true, - typeOnCreate: true, + versionEnabled: true, + typeOnCreate: true, + createResponseTypes: true, }, } diff --git a/api/internal/genapi/templates.go b/api/internal/genapi/templates.go index 84bed5a31..a7352c591 100644 --- a/api/internal/genapi/templates.go +++ b/api/internal/genapi/templates.go @@ -73,6 +73,7 @@ type templateInput struct { ExtraOptions []fieldInfo VersionEnabled bool TypeOnCreate bool + CreateResponseTypes bool } func fillTemplates() { @@ -80,14 +81,15 @@ func fillTemplates() { for _, in := range inputStructs { outBuf := new(bytes.Buffer) input := templateInput{ - Name: in.generatedStructure.name, - Package: in.generatedStructure.pkg, - Fields: in.generatedStructure.fields, - PathArgs: in.pathArgs, - ParentTypeName: in.parentTypeName, - ExtraOptions: in.extraOptions, - VersionEnabled: in.versionEnabled, - TypeOnCreate: in.typeOnCreate, + Name: in.generatedStructure.name, + Package: in.generatedStructure.pkg, + Fields: in.generatedStructure.fields, + PathArgs: in.pathArgs, + ParentTypeName: in.parentTypeName, + ExtraOptions: in.extraOptions, + VersionEnabled: in.versionEnabled, + TypeOnCreate: in.typeOnCreate, + CreateResponseTypes: in.createResponseTypes, } if len(in.pathArgs) > 0 { @@ -205,7 +207,7 @@ var listTemplate = template.Must(template.New("").Funcs( "snakeCase": snakeCase, }, ).Parse(` -func (c *Client) List(ctx context.Context, {{ .CollectionFunctionArg }} string, opt... Option) ([]*{{ .Name }}, *api.Error, error) { +func (c *Client) List(ctx context.Context, {{ .CollectionFunctionArg }} string, opt... Option) (*{{ .Name }}ListResult, *api.Error, error) { if {{ .CollectionFunctionArg }} == "" { return nil, nil, fmt.Errorf("empty {{ .CollectionFunctionArg }} value passed into List request") } @@ -236,10 +238,7 @@ func (c *Client) List(ctx context.Context, {{ .CollectionFunctionArg }} string, return nil, nil, fmt.Errorf("error performing client request during List call: %w", err) } - type listResponse struct { - Items []*{{ .Name }} - } - target := &listResponse{} + target := new({{ .Name }}ListResult) apiErr, err := resp.Decode(target) if err != nil { return nil, nil, fmt.Errorf("error decoding List response: %w", err) @@ -247,12 +246,14 @@ func (c *Client) List(ctx context.Context, {{ .CollectionFunctionArg }} string, if apiErr != nil { return nil, apiErr, nil } - return target.Items, apiErr, nil + target.responseBody = resp.Body + target.responseMap = resp.Map + return target, apiErr, nil } `)) var readTemplate = template.Must(template.New("").Parse(` -func (c *Client) Read(ctx context.Context, {{ .ResourceFunctionArg }} string, opt... Option) (*{{ .Name }}, *api.Error, error) { +func (c *Client) Read(ctx context.Context, {{ .ResourceFunctionArg }} string, opt... Option) (*{{ .Name }}ReadResult, *api.Error, error) { if {{ .ResourceFunctionArg }} == "" { return nil, nil, fmt.Errorf("empty {{ .ResourceFunctionArg }} value passed into Read request") } @@ -280,32 +281,35 @@ func (c *Client) Read(ctx context.Context, {{ .ResourceFunctionArg }} string, op return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err) } - target := new({{ .Name }}) - apiErr, err := resp.Decode(target) + target := new({{ .Name }}ReadResult) + target.Item = new({{ .Name }}) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Read response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } `)) var deleteTemplate = template.Must(template.New("").Parse(` -func (c *Client) Delete(ctx context.Context, {{ .ResourceFunctionArg }} string, opt... Option) (bool, *api.Error, error) { +func (c *Client) Delete(ctx context.Context, {{ .ResourceFunctionArg }} string, opt... Option) (*{{ .Name }}DeleteResult, *api.Error, error) { if {{ .ResourceFunctionArg }} == "" { - return false, nil, fmt.Errorf("empty {{ .ResourceFunctionArg }} value passed into Delete request") + return nil, nil, fmt.Errorf("empty {{ .ResourceFunctionArg }} value passed into Delete request") } if c.client == nil { - return false, nil, fmt.Errorf("nil client") + return nil, nil, fmt.Errorf("nil client") } opts, apiOpts := getOpts(opt...) req, err := c.client.NewRequest(ctx, "DELETE", {{ .ResourcePath }}, nil, apiOpts...) if err != nil { - return false, nil, fmt.Errorf("error creating Delete request: %w", err) + return nil, nil, fmt.Errorf("error creating Delete request: %w", err) } if len(opts.queryMap) > 0 { @@ -318,22 +322,22 @@ func (c *Client) Delete(ctx context.Context, {{ .ResourceFunctionArg }} string, resp, err := c.client.Do(req) if err != nil { - return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err) + return nil, nil, fmt.Errorf("error performing client request during Delete call: %w", err) } apiErr, err := resp.Decode(nil) if err != nil { - return false, nil, fmt.Errorf("error decoding Delete response: %w", err) + return nil, nil, fmt.Errorf("error decoding Delete response: %w", err) } if apiErr != nil { - // We don't treat a 404 in this case as failure, in order for deletes to - // be idempotent - if apiErr.Status == http.StatusNotFound { - return false, nil, nil - } - return false, apiErr, nil + return nil, apiErr, nil } - return true, nil, nil + + target := &{{ .Name }}DeleteResult{ + responseBody: resp.Body, + responseMap: resp.Map, + } + return target, nil, nil } `)) @@ -342,7 +346,7 @@ var createTemplate = template.Must(template.New("").Funcs( "snakeCase": snakeCase, }, ).Parse(` -func (c *Client) Create (ctx context.Context, {{ if .TypeOnCreate }} resourceType string, {{ end }} {{ .CollectionFunctionArg }} string, opt... Option) (*{{ .Name }}, *api.Error, error) { +func (c *Client) Create (ctx context.Context, {{ if .TypeOnCreate }} resourceType string, {{ end }} {{ .CollectionFunctionArg }} string, opt... Option) (*{{ .Name }}CreateResult, *api.Error, error) { if {{ .CollectionFunctionArg }} == "" { return nil, nil, fmt.Errorf("empty {{ .CollectionFunctionArg }} value passed into Create request") } @@ -380,20 +384,23 @@ func (c *Client) Create (ctx context.Context, {{ if .TypeOnCreate }} resourceTyp return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err) } - target := new({{ .Name }}) - apiErr, err := resp.Decode(target) + target := new({{ .Name }}CreateResult) + target.Item = new({{ .Name }}) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Create response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } `)) var updateTemplate = template.Must(template.New("").Parse(` -func (c *Client) Update(ctx context.Context, {{ .ResourceFunctionArg }} string, version uint32, opt... Option) (*{{ .Name }}, *api.Error, error) { +func (c *Client) Update(ctx context.Context, {{ .ResourceFunctionArg }} string, version uint32, opt... Option) (*{{ .Name }}UpdateResult, *api.Error, error) { if {{ .ResourceFunctionArg }} == "" { return nil, nil, fmt.Errorf("empty {{ .ResourceFunctionArg }} value passed into Update request") } @@ -416,9 +423,12 @@ func (c *Client) Update(ctx context.Context, {{ .ResourceFunctionArg }} string, 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } {{ end }} @@ -442,14 +452,17 @@ func (c *Client) Update(ctx context.Context, {{ .ResourceFunctionArg }} string, return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) } - target := new({{ .Name }}) - apiErr, err := resp.Decode(target) + target := new({{ .Name }}UpdateResult) + target.Item = new({{ .Name }}) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Update response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } `)) @@ -468,7 +481,7 @@ var sliceSubTypeTemplate = template.Must(template.New("").Funcs( {{ $fullName := print $op $key }} {{ $actionName := kebabCase $fullName }} {{ $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) { +func (c *Client) {{ $fullName }}(ctx context.Context, {{ $input.ResourceFunctionArg }} string, version uint32, {{ $value }} []string, opt... Option) (*{{ $input.Name }}UpdateResult, *api.Error, error) { if {{ $input.ResourceFunctionArg }} == "" { return nil, nil, fmt.Errorf("empty {{ $input.ResourceFunctionArg }} value passed into {{ $fullName }} request") } @@ -494,9 +507,12 @@ func (c *Client) {{ $fullName }}(ctx context.Context, {{ $input.ResourceFunction 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } {{ end }} opts.postMap["version"] = version @@ -520,14 +536,17 @@ func (c *Client) {{ $fullName }}(ctx context.Context, {{ $input.ResourceFunction return nil, nil, fmt.Errorf("error performing client request during {{ $fullName }} call: %w", err) } - target := new({{ $input.Name }}) - apiErr, err := resp.Decode(target) + target := new({{ $input.Name }}UpdateResult) + target.Item = new({{ $input.Name }}) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding {{ $fullName }} response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } {{ end }} @@ -551,18 +570,75 @@ import ( type {{ .Name }} struct { {{ range .Fields }} {{ .Name }} {{ .FieldType }} `, "`json:\"{{ .ProtoName }},omitempty\"`", `{{ end }} - - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} +{{ if ( or .CreateResponseTypes ( eq .Name "Error" ) ) }} + responseBody *bytes.Buffer + responseMap map[string]interface{} +{{ end }} } -func (n {{ .Name }}) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody +{{ if ( or .CreateResponseTypes ( eq .Name "Error" ) ) }} +func (n {{ .Name }}) ResponseBody() *bytes.Buffer { + return n.responseBody } -func (n {{ .Name }}) LastResponseMap() map[string]interface{} { - return n.lastResponseMap +func (n {{ .Name }}) ResponseMap() map[string]interface{} { + return n.responseMap } +{{ end }} + +{{ if .CreateResponseTypes }} +type {{ .Name }}ReadResult struct { + Item *{{ .Name }} + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n {{ .Name }}ReadResult) GetItem() interface{} { + return n.Item +} + +func (n {{ .Name }}ReadResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n {{ .Name }}ReadResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type {{ .Name }}CreateResult = {{ .Name }}ReadResult +type {{ .Name }}UpdateResult = {{ .Name }}ReadResult + +type {{ .Name }}DeleteResult struct { + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n {{ .Name }}DeleteResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n {{ .Name }}DeleteResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type {{ .Name }}ListResult struct { + Items []*{{ .Name }} + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n {{ .Name }}ListResult) GetItems() interface{} { + return n.Items +} + +func (n {{ .Name }}ListResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n {{ .Name }}ListResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} +{{ end }} `))) var clientTemplate = template.Must(template.New("").Parse(` diff --git a/api/response.go b/api/response.go index 7340867dc..8ca0b28de 100644 --- a/api/response.go +++ b/api/response.go @@ -71,6 +71,9 @@ func (r *Response) Decode(inStruct interface{}) (*Error, error) { } } if r.resp.StatusCode >= 400 { + errStruct := inStruct.(*Error) + errStruct.responseBody = r.Body + errStruct.responseMap = r.Map return apiErr, nil } diff --git a/api/roles/grant.gen.go b/api/roles/grant.gen.go index 4cca2ce99..79da581f7 100644 --- a/api/roles/grant.gen.go +++ b/api/roles/grant.gen.go @@ -1,21 +1,8 @@ // Code generated by "make api"; DO NOT EDIT. package roles -import "bytes" - type Grant struct { Raw string `json:"raw,omitempty"` Canonical string `json:"canonical,omitempty"` Json *GrantJson `json:"json,omitempty"` - - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} -} - -func (n Grant) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody -} - -func (n Grant) LastResponseMap() map[string]interface{} { - return n.lastResponseMap } diff --git a/api/roles/grant_json.gen.go b/api/roles/grant_json.gen.go index 32c8818cc..310a1d0d2 100644 --- a/api/roles/grant_json.gen.go +++ b/api/roles/grant_json.gen.go @@ -1,21 +1,8 @@ // Code generated by "make api"; DO NOT EDIT. package roles -import "bytes" - type GrantJson struct { Id string `json:"id,omitempty"` Type string `json:"type,omitempty"` Actions []string `json:"actions,omitempty"` - - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} -} - -func (n GrantJson) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody -} - -func (n GrantJson) LastResponseMap() map[string]interface{} { - return n.lastResponseMap } diff --git a/api/roles/principal.gen.go b/api/roles/principal.gen.go index 73243448f..9419e507e 100644 --- a/api/roles/principal.gen.go +++ b/api/roles/principal.gen.go @@ -1,21 +1,8 @@ // Code generated by "make api"; DO NOT EDIT. package roles -import "bytes" - type Principal struct { Id string `json:"id,omitempty"` Type string `json:"type,omitempty"` ScopeId string `json:"scope_id,omitempty"` - - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} -} - -func (n Principal) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody -} - -func (n Principal) LastResponseMap() map[string]interface{} { - return n.lastResponseMap } diff --git a/api/roles/role.gen.go b/api/roles/role.gen.go index b39163eb9..20aead538 100644 --- a/api/roles/role.gen.go +++ b/api/roles/role.gen.go @@ -6,7 +6,6 @@ import ( "context" "errors" "fmt" - "net/http" "net/url" "time" @@ -31,16 +30,68 @@ type Role struct { GrantStrings []string `json:"grant_strings,omitempty"` Grants []*Grant `json:"grants,omitempty"` - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} + responseBody *bytes.Buffer + responseMap map[string]interface{} } -func (n Role) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody +func (n Role) ResponseBody() *bytes.Buffer { + return n.responseBody } -func (n Role) LastResponseMap() map[string]interface{} { - return n.lastResponseMap +func (n Role) ResponseMap() map[string]interface{} { + return n.responseMap +} + +type RoleReadResult struct { + Item *Role + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n RoleReadResult) GetItem() interface{} { + return n.Item +} + +func (n RoleReadResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n RoleReadResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type RoleCreateResult = RoleReadResult +type RoleUpdateResult = RoleReadResult + +type RoleDeleteResult struct { + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n RoleDeleteResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n RoleDeleteResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type RoleListResult struct { + Items []*Role + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n RoleListResult) GetItems() interface{} { + return n.Items +} + +func (n RoleListResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n RoleListResult) GetResponseMap() map[string]interface{} { + return n.responseMap } // Client is a client for this collection @@ -61,7 +112,7 @@ func (c *Client) ApiClient() *api.Client { return c.client } -func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Role, *api.Error, error) { +func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*RoleCreateResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into Create request") } @@ -92,18 +143,21 @@ func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Ro return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err) } - target := new(Role) - apiErr, err := resp.Decode(target) + target := new(RoleCreateResult) + target.Item = new(Role) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Create response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Read(ctx context.Context, roleId string, opt ...Option) (*Role, *api.Error, error) { +func (c *Client) Read(ctx context.Context, roleId string, opt ...Option) (*RoleReadResult, *api.Error, error) { if roleId == "" { return nil, nil, fmt.Errorf("empty roleId value passed into Read request") } @@ -131,18 +185,21 @@ func (c *Client) Read(ctx context.Context, roleId string, opt ...Option) (*Role, return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err) } - target := new(Role) - apiErr, err := resp.Decode(target) + target := new(RoleReadResult) + target.Item = new(Role) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Read response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Update(ctx context.Context, roleId string, version uint32, opt ...Option) (*Role, *api.Error, error) { +func (c *Client) Update(ctx context.Context, roleId string, version uint32, opt ...Option) (*RoleUpdateResult, *api.Error, error) { if roleId == "" { return nil, nil, fmt.Errorf("empty roleId value passed into Update request") } @@ -164,9 +221,12 @@ func (c *Client) Update(ctx context.Context, roleId string, version uint32, opt 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -189,30 +249,33 @@ func (c *Client) Update(ctx context.Context, roleId string, version uint32, opt return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) } - target := new(Role) - apiErr, err := resp.Decode(target) + target := new(RoleUpdateResult) + target.Item = new(Role) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Update response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Delete(ctx context.Context, roleId string, opt ...Option) (bool, *api.Error, error) { +func (c *Client) Delete(ctx context.Context, roleId string, opt ...Option) (*RoleDeleteResult, *api.Error, error) { if roleId == "" { - return false, nil, fmt.Errorf("empty roleId value passed into Delete request") + return nil, nil, fmt.Errorf("empty roleId value passed into Delete request") } if c.client == nil { - return false, nil, fmt.Errorf("nil client") + return nil, nil, fmt.Errorf("nil client") } opts, apiOpts := getOpts(opt...) req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("roles/%s", roleId), nil, apiOpts...) if err != nil { - return false, nil, fmt.Errorf("error creating Delete request: %w", err) + return nil, nil, fmt.Errorf("error creating Delete request: %w", err) } if len(opts.queryMap) > 0 { @@ -225,25 +288,25 @@ func (c *Client) Delete(ctx context.Context, roleId string, opt ...Option) (bool resp, err := c.client.Do(req) if err != nil { - return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err) + return nil, nil, fmt.Errorf("error performing client request during Delete call: %w", err) } apiErr, err := resp.Decode(nil) if err != nil { - return false, nil, fmt.Errorf("error decoding Delete response: %w", err) + return nil, nil, fmt.Errorf("error decoding Delete response: %w", err) } if apiErr != nil { - // We don't treat a 404 in this case as failure, in order for deletes to - // be idempotent - if apiErr.Status == http.StatusNotFound { - return false, nil, nil - } - return false, apiErr, nil + return nil, apiErr, nil } - return true, nil, nil + + target := &RoleDeleteResult{ + responseBody: resp.Body, + responseMap: resp.Map, + } + return target, nil, nil } -func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Role, *api.Error, error) { +func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) (*RoleListResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into List request") } @@ -272,10 +335,7 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Ro return nil, nil, fmt.Errorf("error performing client request during List call: %w", err) } - type listResponse struct { - Items []*Role - } - target := &listResponse{} + target := new(RoleListResult) apiErr, err := resp.Decode(target) if err != nil { return nil, nil, fmt.Errorf("error decoding List response: %w", err) @@ -283,10 +343,12 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Ro if apiErr != nil { return nil, apiErr, nil } - return target.Items, apiErr, nil + target.responseBody = resp.Body + target.responseMap = resp.Map + return target, apiErr, nil } -func (c *Client) AddGrants(ctx context.Context, roleId string, version uint32, grantStrings []string, opt ...Option) (*Role, *api.Error, error) { +func (c *Client) AddGrants(ctx context.Context, roleId string, version uint32, grantStrings []string, opt ...Option) (*RoleUpdateResult, *api.Error, error) { if roleId == "" { return nil, nil, fmt.Errorf("empty roleId value passed into AddGrants request") } @@ -311,9 +373,12 @@ func (c *Client) AddGrants(ctx context.Context, roleId string, version uint32, g 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -337,18 +402,21 @@ func (c *Client) AddGrants(ctx context.Context, roleId string, version uint32, g return nil, nil, fmt.Errorf("error performing client request during AddGrants call: %w", err) } - target := new(Role) - apiErr, err := resp.Decode(target) + target := new(RoleUpdateResult) + target.Item = new(Role) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding AddGrants response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) AddPrincipals(ctx context.Context, roleId string, version uint32, principalIds []string, opt ...Option) (*Role, *api.Error, error) { +func (c *Client) AddPrincipals(ctx context.Context, roleId string, version uint32, principalIds []string, opt ...Option) (*RoleUpdateResult, *api.Error, error) { if roleId == "" { return nil, nil, fmt.Errorf("empty roleId value passed into AddPrincipals request") } @@ -373,9 +441,12 @@ func (c *Client) AddPrincipals(ctx context.Context, roleId string, version uint3 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -399,18 +470,21 @@ func (c *Client) AddPrincipals(ctx context.Context, roleId string, version uint3 return nil, nil, fmt.Errorf("error performing client request during AddPrincipals call: %w", err) } - target := new(Role) - apiErr, err := resp.Decode(target) + target := new(RoleUpdateResult) + target.Item = new(Role) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding AddPrincipals response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) SetGrants(ctx context.Context, roleId string, version uint32, grantStrings []string, opt ...Option) (*Role, *api.Error, error) { +func (c *Client) SetGrants(ctx context.Context, roleId string, version uint32, grantStrings []string, opt ...Option) (*RoleUpdateResult, *api.Error, error) { if roleId == "" { return nil, nil, fmt.Errorf("empty roleId value passed into SetGrants request") } @@ -433,9 +507,12 @@ func (c *Client) SetGrants(ctx context.Context, roleId string, version uint32, g 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -459,18 +536,21 @@ func (c *Client) SetGrants(ctx context.Context, roleId string, version uint32, g return nil, nil, fmt.Errorf("error performing client request during SetGrants call: %w", err) } - target := new(Role) - apiErr, err := resp.Decode(target) + target := new(RoleUpdateResult) + target.Item = new(Role) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding SetGrants response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) SetPrincipals(ctx context.Context, roleId string, version uint32, principalIds []string, opt ...Option) (*Role, *api.Error, error) { +func (c *Client) SetPrincipals(ctx context.Context, roleId string, version uint32, principalIds []string, opt ...Option) (*RoleUpdateResult, *api.Error, error) { if roleId == "" { return nil, nil, fmt.Errorf("empty roleId value passed into SetPrincipals request") } @@ -493,9 +573,12 @@ func (c *Client) SetPrincipals(ctx context.Context, roleId string, version uint3 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -519,18 +602,21 @@ func (c *Client) SetPrincipals(ctx context.Context, roleId string, version uint3 return nil, nil, fmt.Errorf("error performing client request during SetPrincipals call: %w", err) } - target := new(Role) - apiErr, err := resp.Decode(target) + target := new(RoleUpdateResult) + target.Item = new(Role) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding SetPrincipals response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) RemoveGrants(ctx context.Context, roleId string, version uint32, grantStrings []string, opt ...Option) (*Role, *api.Error, error) { +func (c *Client) RemoveGrants(ctx context.Context, roleId string, version uint32, grantStrings []string, opt ...Option) (*RoleUpdateResult, *api.Error, error) { if roleId == "" { return nil, nil, fmt.Errorf("empty roleId value passed into RemoveGrants request") } @@ -555,9 +641,12 @@ func (c *Client) RemoveGrants(ctx context.Context, roleId string, version uint32 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -581,18 +670,21 @@ func (c *Client) RemoveGrants(ctx context.Context, roleId string, version uint32 return nil, nil, fmt.Errorf("error performing client request during RemoveGrants call: %w", err) } - target := new(Role) - apiErr, err := resp.Decode(target) + target := new(RoleUpdateResult) + target.Item = new(Role) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding RemoveGrants response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) RemovePrincipals(ctx context.Context, roleId string, version uint32, principalIds []string, opt ...Option) (*Role, *api.Error, error) { +func (c *Client) RemovePrincipals(ctx context.Context, roleId string, version uint32, principalIds []string, opt ...Option) (*RoleUpdateResult, *api.Error, error) { if roleId == "" { return nil, nil, fmt.Errorf("empty roleId value passed into RemovePrincipals request") } @@ -617,9 +709,12 @@ func (c *Client) RemovePrincipals(ctx context.Context, roleId string, version ui 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -643,13 +738,16 @@ func (c *Client) RemovePrincipals(ctx context.Context, roleId string, version ui return nil, nil, fmt.Errorf("error performing client request during RemovePrincipals call: %w", err) } - target := new(Role) - apiErr, err := resp.Decode(target) + target := new(RoleUpdateResult) + target.Item = new(Role) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding RemovePrincipals response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } diff --git a/api/roles/role_test.go b/api/roles/role_test.go index a0e95f8fc..dbeccf823 100644 --- a/api/roles/role_test.go +++ b/api/roles/role_test.go @@ -74,49 +74,49 @@ func TestCustom(t *testing.T) { require.NoError(err) require.Nil(apiErr) require.NotNil(r) - require.EqualValues(r.Version, version) + require.EqualValues(r.Item.Version, version) version++ - updatedRole, apiErr, err := rc.AddPrincipals(tc.Context(), r.Id, r.Version, []string{g.Id}) + updatedRole, apiErr, err := rc.AddPrincipals(tc.Context(), r.Item.Id, r.Item.Version, []string{g.Item.Id}) require.NoError(err) require.Nil(apiErr, "Got error ", pretty.Sprint(apiErr)) - assert.EqualValues(updatedRole.Version, version) - assert.True(hasPrincipal(updatedRole, g.Id)) + assert.EqualValues(updatedRole.Item.Version, version) + assert.True(hasPrincipal(updatedRole.Item, g.Item.Id)) version++ - updatedRole, apiErr, err = rc.SetPrincipals(tc.Context(), updatedRole.Id, updatedRole.Version, []string{user.Id}) + updatedRole, apiErr, err = rc.SetPrincipals(tc.Context(), updatedRole.Item.Id, updatedRole.Item.Version, []string{user.Item.Id}) require.NoError(err) require.Nil(apiErr, "Got error ", apiErr) - assert.EqualValues(updatedRole.Version, version) - assert.True(hasPrincipal(updatedRole, user.Id)) + assert.EqualValues(updatedRole.Item.Version, version) + assert.True(hasPrincipal(updatedRole.Item, user.Item.Id)) version++ - updatedRole, apiErr, err = rc.RemovePrincipals(tc.Context(), updatedRole.Id, updatedRole.Version, []string{user.Id}) + updatedRole, apiErr, err = rc.RemovePrincipals(tc.Context(), updatedRole.Item.Id, updatedRole.Item.Version, []string{user.Item.Id}) require.NoError(err) require.Nil(apiErr, "Got error ", apiErr) - assert.EqualValues(updatedRole.Version, version) - assert.Empty(updatedRole.Principals) + assert.EqualValues(updatedRole.Item.Version, version) + assert.Empty(updatedRole.Item.Principals) version++ - updatedRole, apiErr, err = rc.AddGrants(tc.Context(), updatedRole.Id, updatedRole.Version, []string{"id=*;actions=read"}) + updatedRole, apiErr, err = rc.AddGrants(tc.Context(), updatedRole.Item.Id, updatedRole.Item.Version, []string{"id=*;actions=read"}) require.NoError(err) require.Nil(apiErr, "Got error ", apiErr) - assert.EqualValues(updatedRole.Version, version) - assert.Contains(updatedRole.GrantStrings, "id=*;actions=read") + assert.EqualValues(updatedRole.Item.Version, version) + assert.Contains(updatedRole.Item.GrantStrings, "id=*;actions=read") version++ - updatedRole, apiErr, err = rc.SetGrants(tc.Context(), updatedRole.Id, updatedRole.Version, []string{"id=*;actions=*"}) + updatedRole, apiErr, err = rc.SetGrants(tc.Context(), updatedRole.Item.Id, updatedRole.Item.Version, []string{"id=*;actions=*"}) require.NoError(err) require.Nil(apiErr, "Got error ", apiErr) - assert.EqualValues(updatedRole.Version, version) - assert.Contains(updatedRole.GrantStrings, "id=*;actions=*") + assert.EqualValues(updatedRole.Item.Version, version) + assert.Contains(updatedRole.Item.GrantStrings, "id=*;actions=*") version++ - updatedRole, apiErr, err = rc.RemoveGrants(tc.Context(), updatedRole.Id, updatedRole.Version, []string{"id=*;actions=*"}) + updatedRole, apiErr, err = rc.RemoveGrants(tc.Context(), updatedRole.Item.Id, updatedRole.Item.Version, []string{"id=*;actions=*"}) require.NoError(err) require.Nil(apiErr, "Got error ", apiErr) - assert.EqualValues(updatedRole.Version, version) - assert.Empty(updatedRole.Grants) + assert.EqualValues(updatedRole.Item.Version, version) + assert.Empty(updatedRole.Item.Grants) version++ }) } @@ -154,31 +154,33 @@ func TestList(t *testing.T) { p1, apiErr, err := roleClient.List(tc.Context(), tt.scopeId) require.NoError(err) assert.Nil(apiErr) - require.Len(p1, 1) - expected = append(expected, p1[0]) + require.Len(p1.Items, 1) + expected = append(expected, p1.Items[0]) for i := 1; i < 11; i++ { expected = append(expected, &roles.Role{Name: fmt.Sprint(i)}) } - expected[1], apiErr, err = roleClient.Create(tc.Context(), tt.scopeId, roles.WithName(expected[1].Name)) + rcr, apiErr, err := roleClient.Create(tc.Context(), tt.scopeId, roles.WithName(expected[1].Name)) require.NoError(err) - assert.Nil(apiErr) + require.Nil(apiErr) + expected[1] = rcr.Item p2, apiErr, err := roleClient.List(tc.Context(), tt.scopeId) - assert.NoError(err) - assert.Nil(apiErr) - assert.ElementsMatch(comparableSlice(expected[0:2]), comparableSlice(p2)) + require.NoError(err) + require.Nil(apiErr) + assert.ElementsMatch(comparableSlice(expected[0:2]), comparableSlice(p2.Items)) for i := 2; i < 11; i++ { - expected[i], apiErr, err = roleClient.Create(tc.Context(), tt.scopeId, roles.WithName(expected[i].Name)) + rcr, apiErr, err = roleClient.Create(tc.Context(), tt.scopeId, roles.WithName(expected[i].Name)) assert.NoError(err) assert.Nil(apiErr) + expected[i] = rcr.Item } p3, apiErr, err := roleClient.List(tc.Context(), tt.scopeId) require.NoError(err) - assert.Nil(apiErr) - assert.ElementsMatch(comparableSlice(expected), comparableSlice(p3)) + require.Nil(apiErr) + assert.ElementsMatch(comparableSlice(expected), comparableSlice(p3.Items)) }) } } @@ -240,21 +242,20 @@ func TestCrud(t *testing.T) { t.Run(tt.name, func(t *testing.T) { roleClient := roles.NewClient(client) g, apiErr, err := roleClient.Create(tc.Context(), tt.scopeId, roles.WithName("foo")) - checkRole("create", g, apiErr, err, "foo", 1) + checkRole("create", g.Item, apiErr, err, "foo", 1) - g, apiErr, err = roleClient.Read(tc.Context(), g.Id) - checkRole("read", g, apiErr, err, "foo", 1) + g, apiErr, err = roleClient.Read(tc.Context(), g.Item.Id) + checkRole("read", g.Item, apiErr, err, "foo", 1) - g, apiErr, err = roleClient.Update(tc.Context(), g.Id, g.Version, roles.WithName("bar")) - checkRole("update", g, apiErr, err, "bar", 2) + g, apiErr, err = roleClient.Update(tc.Context(), g.Item.Id, g.Item.Version, roles.WithName("bar")) + checkRole("update", g.Item, apiErr, err, "bar", 2) - g, apiErr, err = roleClient.Update(tc.Context(), g.Id, g.Version, roles.DefaultName()) - checkRole("update", g, apiErr, err, "", 3) + g, apiErr, err = roleClient.Update(tc.Context(), g.Item.Id, g.Item.Version, roles.DefaultName()) + checkRole("update", g.Item, apiErr, err, "", 3) - existed, apiErr, err := roleClient.Delete(tc.Context(), g.Id) + _, apiErr, err = roleClient.Delete(tc.Context(), g.Item.Id) require.NoError(err) assert.Nil(apiErr) - assert.True(existed, "Expected existing user when deleted, but it wasn't.") }) } } @@ -306,7 +307,7 @@ func TestErrors(t *testing.T) { assert.NotNil(apiErr) assert.EqualValues(http.StatusBadRequest, apiErr.Status) - _, apiErr, err = roleClient.Update(tc.Context(), u.Id, u.Version) + _, apiErr, err = roleClient.Update(tc.Context(), u.Item.Id, u.Item.Version) require.NoError(err) assert.NotNil(apiErr) assert.EqualValues(http.StatusBadRequest, apiErr.Status) diff --git a/api/scopes/scope.gen.go b/api/scopes/scope.gen.go index 10d0162f9..be1ea16b4 100644 --- a/api/scopes/scope.gen.go +++ b/api/scopes/scope.gen.go @@ -6,7 +6,6 @@ import ( "context" "errors" "fmt" - "net/http" "net/url" "time" @@ -26,16 +25,68 @@ type Scope struct { Version uint32 `json:"version,omitempty"` Type string `json:"type,omitempty"` - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} + responseBody *bytes.Buffer + responseMap map[string]interface{} } -func (n Scope) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody +func (n Scope) ResponseBody() *bytes.Buffer { + return n.responseBody } -func (n Scope) LastResponseMap() map[string]interface{} { - return n.lastResponseMap +func (n Scope) ResponseMap() map[string]interface{} { + return n.responseMap +} + +type ScopeReadResult struct { + Item *Scope + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n ScopeReadResult) GetItem() interface{} { + return n.Item +} + +func (n ScopeReadResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n ScopeReadResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type ScopeCreateResult = ScopeReadResult +type ScopeUpdateResult = ScopeReadResult + +type ScopeDeleteResult struct { + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n ScopeDeleteResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n ScopeDeleteResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type ScopeListResult struct { + Items []*Scope + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n ScopeListResult) GetItems() interface{} { + return n.Items +} + +func (n ScopeListResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n ScopeListResult) GetResponseMap() map[string]interface{} { + return n.responseMap } // Client is a client for this collection @@ -56,7 +107,7 @@ func (c *Client) ApiClient() *api.Client { return c.client } -func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Scope, *api.Error, error) { +func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*ScopeCreateResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into Create request") } @@ -87,18 +138,21 @@ func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Sc return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err) } - target := new(Scope) - apiErr, err := resp.Decode(target) + target := new(ScopeCreateResult) + target.Item = new(Scope) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Create response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Read(ctx context.Context, scopeId string, opt ...Option) (*Scope, *api.Error, error) { +func (c *Client) Read(ctx context.Context, scopeId string, opt ...Option) (*ScopeReadResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into Read request") } @@ -126,18 +180,21 @@ func (c *Client) Read(ctx context.Context, scopeId string, opt ...Option) (*Scop return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err) } - target := new(Scope) - apiErr, err := resp.Decode(target) + target := new(ScopeReadResult) + target.Item = new(Scope) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Read response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Update(ctx context.Context, scopeId string, version uint32, opt ...Option) (*Scope, *api.Error, error) { +func (c *Client) Update(ctx context.Context, scopeId string, version uint32, opt ...Option) (*ScopeUpdateResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into Update request") } @@ -159,9 +216,12 @@ func (c *Client) Update(ctx context.Context, scopeId string, version uint32, opt 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -184,30 +244,33 @@ func (c *Client) Update(ctx context.Context, scopeId string, version uint32, opt return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) } - target := new(Scope) - apiErr, err := resp.Decode(target) + target := new(ScopeUpdateResult) + target.Item = new(Scope) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Update response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Delete(ctx context.Context, scopeId string, opt ...Option) (bool, *api.Error, error) { +func (c *Client) Delete(ctx context.Context, scopeId string, opt ...Option) (*ScopeDeleteResult, *api.Error, error) { if scopeId == "" { - return false, nil, fmt.Errorf("empty scopeId value passed into Delete request") + return nil, nil, fmt.Errorf("empty scopeId value passed into Delete request") } if c.client == nil { - return false, nil, fmt.Errorf("nil client") + return nil, nil, fmt.Errorf("nil client") } opts, apiOpts := getOpts(opt...) req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("scopes/%s", scopeId), nil, apiOpts...) if err != nil { - return false, nil, fmt.Errorf("error creating Delete request: %w", err) + return nil, nil, fmt.Errorf("error creating Delete request: %w", err) } if len(opts.queryMap) > 0 { @@ -220,25 +283,25 @@ func (c *Client) Delete(ctx context.Context, scopeId string, opt ...Option) (boo resp, err := c.client.Do(req) if err != nil { - return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err) + return nil, nil, fmt.Errorf("error performing client request during Delete call: %w", err) } apiErr, err := resp.Decode(nil) if err != nil { - return false, nil, fmt.Errorf("error decoding Delete response: %w", err) + return nil, nil, fmt.Errorf("error decoding Delete response: %w", err) } if apiErr != nil { - // We don't treat a 404 in this case as failure, in order for deletes to - // be idempotent - if apiErr.Status == http.StatusNotFound { - return false, nil, nil - } - return false, apiErr, nil + return nil, apiErr, nil } - return true, nil, nil + + target := &ScopeDeleteResult{ + responseBody: resp.Body, + responseMap: resp.Map, + } + return target, nil, nil } -func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Scope, *api.Error, error) { +func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) (*ScopeListResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into List request") } @@ -267,10 +330,7 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Sc return nil, nil, fmt.Errorf("error performing client request during List call: %w", err) } - type listResponse struct { - Items []*Scope - } - target := &listResponse{} + target := new(ScopeListResult) apiErr, err := resp.Decode(target) if err != nil { return nil, nil, fmt.Errorf("error decoding List response: %w", err) @@ -278,5 +338,7 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Sc if apiErr != nil { return nil, apiErr, nil } - return target.Items, apiErr, nil + target.responseBody = resp.Body + target.responseMap = resp.Map + return target, apiErr, nil } diff --git a/api/scopes/scope_info.gen.go b/api/scopes/scope_info.gen.go index f23dab05b..62d35119e 100644 --- a/api/scopes/scope_info.gen.go +++ b/api/scopes/scope_info.gen.go @@ -1,23 +1,10 @@ // Code generated by "make api"; DO NOT EDIT. package scopes -import "bytes" - type ScopeInfo struct { Id string `json:"id,omitempty"` Type string `json:"type,omitempty"` Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` ParentScopeId string `json:"parent_scope_id,omitempty"` - - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} -} - -func (n ScopeInfo) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody -} - -func (n ScopeInfo) LastResponseMap() map[string]interface{} { - return n.lastResponseMap } diff --git a/api/scopes/project_test.go b/api/scopes/scope_test.go similarity index 79% rename from api/scopes/project_test.go rename to api/scopes/scope_test.go index bd6f47664..97746f7c1 100644 --- a/api/scopes/project_test.go +++ b/api/scopes/scope_test.go @@ -28,18 +28,19 @@ func TestList(t *testing.T) { pl, apiErr, err := scps.List(tc.Context(), org.GetPublicId()) require.NoError(err) assert.Nil(apiErr) - assert.Empty(pl) + assert.Empty(pl.Items) expected := make([]*scopes.Scope, 10) for i := 0; i < 10; i++ { - expected[i], apiErr, err = scps.Create(tc.Context(), org.GetPublicId(), scopes.WithName(fmt.Sprintf("%d", i))) + scr, apiErr, err := scps.Create(tc.Context(), org.GetPublicId(), scopes.WithName(fmt.Sprintf("%d", i))) require.NoError(err) assert.Nil(apiErr) + expected[i] = scr.Item } pl, apiErr, err = scps.List(tc.Context(), org.GetPublicId()) require.NoError(err) assert.Nil(apiErr) - assert.ElementsMatch(comparableSlice(expected), comparableSlice(pl)) + assert.ElementsMatch(comparableSlice(expected), comparableSlice(pl.Items)) } func comparableSlice(in []*scopes.Scope) []scopes.Scope { @@ -83,26 +84,25 @@ func TestCrud(t *testing.T) { } s, apiErr, err := scps.Create(tc.Context(), org.GetPublicId(), scopes.WithName("foo")) - checkProject("create", s, apiErr, err, "foo", 1) + checkProject("create", s.Item, apiErr, err, "foo", 1) - s, apiErr, err = scps.Read(tc.Context(), s.Id) - checkProject("read", s, apiErr, err, "foo", 1) + s, apiErr, err = scps.Read(tc.Context(), s.Item.Id) + checkProject("read", s.Item, apiErr, err, "foo", 1) - s, apiErr, err = scps.Update(tc.Context(), s.Id, s.Version, scopes.WithName("bar")) - checkProject("update", s, apiErr, err, "bar", 2) + s, apiErr, err = scps.Update(tc.Context(), s.Item.Id, s.Item.Version, scopes.WithName("bar")) + checkProject("update", s.Item, apiErr, err, "bar", 2) - s, apiErr, err = scps.Update(tc.Context(), s.Id, s.Version, scopes.DefaultName()) - checkProject("update, unset name", s, apiErr, err, "", 3) + s, apiErr, err = scps.Update(tc.Context(), s.Item.Id, s.Item.Version, scopes.DefaultName()) + checkProject("update, unset name", s.Item, apiErr, err, "", 3) - existed, apiErr, err := scps.Delete(tc.Context(), s.Id) + _, apiErr, err = scps.Delete(tc.Context(), s.Item.Id) require.NoError(err) assert.Nil(apiErr) - assert.True(existed, "Expected existing project when deleted, but it wasn't.") - existed, apiErr, err = scps.Delete(tc.Context(), s.Id) + _, apiErr, err = scps.Delete(tc.Context(), s.Item.Id) require.NoError(err) - assert.Nil(apiErr) - assert.False(existed) + assert.NotNil(apiErr) + assert.EqualValues(http.StatusNotFound, apiErr.Status) } // TODO: Get better coverage for expected errors and error formats. diff --git a/api/targets/host_set.gen.go b/api/targets/host_set.gen.go index c14141494..611e11c3f 100644 --- a/api/targets/host_set.gen.go +++ b/api/targets/host_set.gen.go @@ -1,20 +1,7 @@ // Code generated by "make api"; DO NOT EDIT. package targets -import "bytes" - type HostSet struct { Id string `json:"id,omitempty"` HostCatalogId string `json:"host_catalog_id,omitempty"` - - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} -} - -func (n HostSet) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody -} - -func (n HostSet) LastResponseMap() map[string]interface{} { - return n.lastResponseMap } diff --git a/api/targets/target.gen.go b/api/targets/target.gen.go index 79f466c8f..f46510e87 100644 --- a/api/targets/target.gen.go +++ b/api/targets/target.gen.go @@ -6,7 +6,6 @@ import ( "context" "errors" "fmt" - "net/http" "net/url" "time" @@ -30,16 +29,68 @@ type Target struct { HostSets []*HostSet `json:"host_sets,omitempty"` DefaultPort uint32 `json:"default_port,omitempty"` - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} + responseBody *bytes.Buffer + responseMap map[string]interface{} } -func (n Target) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody +func (n Target) ResponseBody() *bytes.Buffer { + return n.responseBody } -func (n Target) LastResponseMap() map[string]interface{} { - return n.lastResponseMap +func (n Target) ResponseMap() map[string]interface{} { + return n.responseMap +} + +type TargetReadResult struct { + Item *Target + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n TargetReadResult) GetItem() interface{} { + return n.Item +} + +func (n TargetReadResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n TargetReadResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type TargetCreateResult = TargetReadResult +type TargetUpdateResult = TargetReadResult + +type TargetDeleteResult struct { + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n TargetDeleteResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n TargetDeleteResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type TargetListResult struct { + Items []*Target + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n TargetListResult) GetItems() interface{} { + return n.Items +} + +func (n TargetListResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n TargetListResult) GetResponseMap() map[string]interface{} { + return n.responseMap } // Client is a client for this collection @@ -60,7 +111,7 @@ 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) { +func (c *Client) Create(ctx context.Context, resourceType string, scopeId string, opt ...Option) (*TargetCreateResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into Create request") } @@ -96,18 +147,21 @@ func (c *Client) Create(ctx context.Context, resourceType string, scopeId string return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err) } - target := new(Target) - apiErr, err := resp.Decode(target) + target := new(TargetCreateResult) + target.Item = new(Target) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Create response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Read(ctx context.Context, targetId string, opt ...Option) (*Target, *api.Error, error) { +func (c *Client) Read(ctx context.Context, targetId string, opt ...Option) (*TargetReadResult, *api.Error, error) { if targetId == "" { return nil, nil, fmt.Errorf("empty targetId value passed into Read request") } @@ -135,18 +189,21 @@ func (c *Client) Read(ctx context.Context, targetId string, opt ...Option) (*Tar return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err) } - target := new(Target) - apiErr, err := resp.Decode(target) + target := new(TargetReadResult) + target.Item = new(Target) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Read response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Update(ctx context.Context, targetId string, version uint32, opt ...Option) (*Target, *api.Error, error) { +func (c *Client) Update(ctx context.Context, targetId string, version uint32, opt ...Option) (*TargetUpdateResult, *api.Error, error) { if targetId == "" { return nil, nil, fmt.Errorf("empty targetId value passed into Update request") } @@ -168,9 +225,12 @@ func (c *Client) Update(ctx context.Context, targetId string, version uint32, op 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -193,30 +253,33 @@ func (c *Client) Update(ctx context.Context, targetId string, version uint32, op return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) } - target := new(Target) - apiErr, err := resp.Decode(target) + target := new(TargetUpdateResult) + target.Item = new(Target) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Update response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Delete(ctx context.Context, targetId string, opt ...Option) (bool, *api.Error, error) { +func (c *Client) Delete(ctx context.Context, targetId string, opt ...Option) (*TargetDeleteResult, *api.Error, error) { if targetId == "" { - return false, nil, fmt.Errorf("empty targetId value passed into Delete request") + return nil, nil, fmt.Errorf("empty targetId value passed into Delete request") } if c.client == nil { - return false, nil, fmt.Errorf("nil client") + return nil, nil, fmt.Errorf("nil client") } opts, apiOpts := getOpts(opt...) req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("targets/%s", targetId), nil, apiOpts...) if err != nil { - return false, nil, fmt.Errorf("error creating Delete request: %w", err) + return nil, nil, fmt.Errorf("error creating Delete request: %w", err) } if len(opts.queryMap) > 0 { @@ -229,25 +292,25 @@ func (c *Client) Delete(ctx context.Context, targetId string, opt ...Option) (bo resp, err := c.client.Do(req) if err != nil { - return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err) + return nil, nil, fmt.Errorf("error performing client request during Delete call: %w", err) } apiErr, err := resp.Decode(nil) if err != nil { - return false, nil, fmt.Errorf("error decoding Delete response: %w", err) + return nil, nil, fmt.Errorf("error decoding Delete response: %w", err) } if apiErr != nil { - // We don't treat a 404 in this case as failure, in order for deletes to - // be idempotent - if apiErr.Status == http.StatusNotFound { - return false, nil, nil - } - return false, apiErr, nil + return nil, apiErr, nil } - return true, nil, nil + + target := &TargetDeleteResult{ + responseBody: resp.Body, + responseMap: resp.Map, + } + return target, nil, nil } -func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Target, *api.Error, error) { +func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) (*TargetListResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into List request") } @@ -276,10 +339,7 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Ta return nil, nil, fmt.Errorf("error performing client request during List call: %w", err) } - type listResponse struct { - Items []*Target - } - target := &listResponse{} + target := new(TargetListResult) apiErr, err := resp.Decode(target) if err != nil { return nil, nil, fmt.Errorf("error decoding List response: %w", err) @@ -287,10 +347,12 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Ta if apiErr != nil { return nil, apiErr, nil } - return target.Items, apiErr, nil + target.responseBody = resp.Body + target.responseMap = resp.Map + return target, apiErr, nil } -func (c *Client) AddHostSets(ctx context.Context, targetId string, version uint32, hostSetIds []string, opt ...Option) (*Target, *api.Error, error) { +func (c *Client) AddHostSets(ctx context.Context, targetId string, version uint32, hostSetIds []string, opt ...Option) (*TargetUpdateResult, *api.Error, error) { if targetId == "" { return nil, nil, fmt.Errorf("empty targetId value passed into AddHostSets request") } @@ -315,9 +377,12 @@ func (c *Client) AddHostSets(ctx context.Context, targetId string, version uint3 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -341,18 +406,21 @@ func (c *Client) AddHostSets(ctx context.Context, targetId string, version uint3 return nil, nil, fmt.Errorf("error performing client request during AddHostSets call: %w", err) } - target := new(Target) - apiErr, err := resp.Decode(target) + target := new(TargetUpdateResult) + target.Item = new(Target) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding AddHostSets response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) SetHostSets(ctx context.Context, targetId string, version uint32, hostSetIds []string, opt ...Option) (*Target, *api.Error, error) { +func (c *Client) SetHostSets(ctx context.Context, targetId string, version uint32, hostSetIds []string, opt ...Option) (*TargetUpdateResult, *api.Error, error) { if targetId == "" { return nil, nil, fmt.Errorf("empty targetId value passed into SetHostSets request") } @@ -375,9 +443,12 @@ func (c *Client) SetHostSets(ctx context.Context, targetId string, version uint3 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -401,18 +472,21 @@ func (c *Client) SetHostSets(ctx context.Context, targetId string, version uint3 return nil, nil, fmt.Errorf("error performing client request during SetHostSets call: %w", err) } - target := new(Target) - apiErr, err := resp.Decode(target) + target := new(TargetUpdateResult) + target.Item = new(Target) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding SetHostSets response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) RemoveHostSets(ctx context.Context, targetId string, version uint32, hostSetIds []string, opt ...Option) (*Target, *api.Error, error) { +func (c *Client) RemoveHostSets(ctx context.Context, targetId string, version uint32, hostSetIds []string, opt ...Option) (*TargetUpdateResult, *api.Error, error) { if targetId == "" { return nil, nil, fmt.Errorf("empty targetId value passed into RemoveHostSets request") } @@ -437,9 +511,12 @@ func (c *Client) RemoveHostSets(ctx context.Context, targetId string, version ui 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -463,13 +540,16 @@ func (c *Client) RemoveHostSets(ctx context.Context, targetId string, version ui return nil, nil, fmt.Errorf("error performing client request during RemoveHostSets call: %w", err) } - target := new(Target) - apiErr, err := resp.Decode(target) + target := new(TargetUpdateResult) + target.Item = new(Target) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding RemoveHostSets response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } diff --git a/api/targets/target_test.go b/api/targets/target_test.go index c537fddea..cd333a715 100644 --- a/api/targets/target_test.go +++ b/api/targets/target_test.go @@ -31,11 +31,11 @@ func TestCustom(t *testing.T) { require.Nil(apiErr) hSetClient := hostsets.NewClient(client) - hSet, apiErr, err := hSetClient.Create(tc.Context(), hc.Id) + hSet, apiErr, err := hSetClient.Create(tc.Context(), hc.Item.Id) require.NoError(err) require.Nil(apiErr) require.NotNil(hSet) - hSet2, apiErr, err := hSetClient.Create(tc.Context(), hc.Id) + hSet2, apiErr, err := hSetClient.Create(tc.Context(), hc.Item.Id) require.NoError(err) require.Nil(apiErr) require.NotNil(hSet2) @@ -45,25 +45,25 @@ func TestCustom(t *testing.T) { require.NoError(err) require.Nil(apiErr) require.NotNil(tar) - assert.Empty(tar.HostSetIds) + assert.Empty(tar.Item.HostSetIds) - tar, apiErr, err = tarClient.AddHostSets(tc.Context(), tar.Id, tar.Version, []string{hSet.Id}) + tar, apiErr, err = tarClient.AddHostSets(tc.Context(), tar.Item.Id, tar.Item.Version, []string{hSet.Item.Id}) require.NoError(err) require.Nil(apiErr) require.NotNil(tar) - assert.ElementsMatch(tar.HostSetIds, []string{hSet.Id}) + assert.ElementsMatch(tar.Item.HostSetIds, []string{hSet.Item.Id}) - tar, apiErr, err = tarClient.SetHostSets(tc.Context(), tar.Id, tar.Version, []string{hSet2.Id}) + tar, apiErr, err = tarClient.SetHostSets(tc.Context(), tar.Item.Id, tar.Item.Version, []string{hSet2.Item.Id}) require.NoError(err) require.Nil(apiErr) require.NotNil(tar) - assert.ElementsMatch(tar.HostSetIds, []string{hSet2.Id}) + assert.ElementsMatch(tar.Item.HostSetIds, []string{hSet2.Item.Id}) - tar, apiErr, err = tarClient.RemoveHostSets(tc.Context(), tar.Id, tar.Version, []string{hSet2.Id}) + tar, apiErr, err = tarClient.RemoveHostSets(tc.Context(), tar.Item.Id, tar.Item.Version, []string{hSet2.Item.Id}) require.NoError(err) require.Nil(apiErr) require.NotNil(tar) - assert.Empty(tar.HostSetIds) + assert.Empty(tar.Item.HostSetIds) } func TestList(t *testing.T) { @@ -80,31 +80,33 @@ func TestList(t *testing.T) { ul, apiErr, err := tarClient.List(tc.Context(), proj.GetPublicId()) require.NoError(err) require.Nil(apiErr) - assert.Empty(ul) + assert.Empty(ul.Items) var expected []*targets.Target for i := 0; i < 10; i++ { expected = append(expected, &targets.Target{Name: fmt.Sprint(i)}) } - expected[0], apiErr, err = tarClient.Create(tc.Context(), "tcp", proj.GetPublicId(), targets.WithName(expected[0].Name)) + tcr, apiErr, err := tarClient.Create(tc.Context(), "tcp", proj.GetPublicId(), targets.WithName(expected[0].Name)) require.NoError(err) require.Nil(apiErr) + expected[0] = tcr.Item ul, apiErr, err = tarClient.List(tc.Context(), proj.GetPublicId()) require.NoError(err) require.Nil(apiErr) - assert.ElementsMatch(comparableSlice(expected[:1]), comparableSlice(ul)) + assert.ElementsMatch(comparableSlice(expected[:1]), comparableSlice(ul.Items)) for i := 1; i < 10; i++ { - expected[i], apiErr, err = tarClient.Create(tc.Context(), "tcp", proj.GetPublicId(), targets.WithName(expected[i].Name)) + tcr, apiErr, err = tarClient.Create(tc.Context(), "tcp", proj.GetPublicId(), targets.WithName(expected[i].Name)) require.NoError(err) require.Nil(apiErr) + expected[i] = tcr.Item } ul, apiErr, err = tarClient.List(tc.Context(), proj.GetPublicId()) require.NoError(err) require.Nil(apiErr) - assert.ElementsMatch(comparableSlice(expected), comparableSlice(ul)) + assert.ElementsMatch(comparableSlice(expected), comparableSlice(ul.Items)) } func comparableSlice(in []*targets.Target) []targets.Target { @@ -150,22 +152,22 @@ func TestCrud(t *testing.T) { tarClient := targets.NewClient(client) tar, apiErr, err := tarClient.Create(tc.Context(), "tcp", proj.GetPublicId(), targets.WithName("foo")) - checkResource(t, "create", tar, apiErr, err, "foo", 1) + checkResource(t, "create", tar.Item, apiErr, err, "foo", 1) - tar, apiErr, err = tarClient.Read(tc.Context(), tar.Id) - checkResource(t, "read", tar, apiErr, err, "foo", 1) + tar, apiErr, err = tarClient.Read(tc.Context(), tar.Item.Id) + checkResource(t, "read", tar.Item, apiErr, err, "foo", 1) - tar, apiErr, err = tarClient.Update(tc.Context(), tar.Id, tar.Version, targets.WithName("bar")) - checkResource(t, "update", tar, apiErr, err, "bar", 2) + tar, apiErr, err = tarClient.Update(tc.Context(), tar.Item.Id, tar.Item.Version, targets.WithName("bar")) + checkResource(t, "update", tar.Item, apiErr, err, "bar", 2) - existed, apiErr, err := tarClient.Delete(tc.Context(), tar.Id) - assert.NoError(err) - assert.True(existed, "Expected existing target when deleted, but it wasn't.") - - existed, apiErr, err = tarClient.Delete(tc.Context(), tar.Id) + _, apiErr, err = tarClient.Delete(tc.Context(), tar.Item.Id) assert.NoError(err) assert.Nil(apiErr) - assert.False(existed) + + _, apiErr, err = tarClient.Delete(tc.Context(), tar.Item.Id) + assert.NoError(err) + assert.NotNil(apiErr) + assert.EqualValues(http.StatusNotFound, apiErr.Status) } // TODO: Get better coverage for expected errors and error formats. diff --git a/api/users/user.gen.go b/api/users/user.gen.go index f22465f09..647706ffb 100644 --- a/api/users/user.gen.go +++ b/api/users/user.gen.go @@ -6,7 +6,6 @@ import ( "context" "errors" "fmt" - "net/http" "net/url" "time" @@ -26,16 +25,68 @@ type User struct { UpdatedTime time.Time `json:"updated_time,omitempty"` Version uint32 `json:"version,omitempty"` - lastResponseBody *bytes.Buffer - lastResponseMap map[string]interface{} + responseBody *bytes.Buffer + responseMap map[string]interface{} } -func (n User) LastResponseBody() *bytes.Buffer { - return n.lastResponseBody +func (n User) ResponseBody() *bytes.Buffer { + return n.responseBody } -func (n User) LastResponseMap() map[string]interface{} { - return n.lastResponseMap +func (n User) ResponseMap() map[string]interface{} { + return n.responseMap +} + +type UserReadResult struct { + Item *User + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n UserReadResult) GetItem() interface{} { + return n.Item +} + +func (n UserReadResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n UserReadResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type UserCreateResult = UserReadResult +type UserUpdateResult = UserReadResult + +type UserDeleteResult struct { + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n UserDeleteResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n UserDeleteResult) GetResponseMap() map[string]interface{} { + return n.responseMap +} + +type UserListResult struct { + Items []*User + responseBody *bytes.Buffer + responseMap map[string]interface{} +} + +func (n UserListResult) GetItems() interface{} { + return n.Items +} + +func (n UserListResult) GetResponseBody() *bytes.Buffer { + return n.responseBody +} + +func (n UserListResult) GetResponseMap() map[string]interface{} { + return n.responseMap } // Client is a client for this collection @@ -56,7 +107,7 @@ func (c *Client) ApiClient() *api.Client { return c.client } -func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*User, *api.Error, error) { +func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*UserCreateResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into Create request") } @@ -87,18 +138,21 @@ func (c *Client) Create(ctx context.Context, scopeId string, opt ...Option) (*Us return nil, nil, fmt.Errorf("error performing client request during Create call: %w", err) } - target := new(User) - apiErr, err := resp.Decode(target) + target := new(UserCreateResult) + target.Item = new(User) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Create response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Read(ctx context.Context, userId string, opt ...Option) (*User, *api.Error, error) { +func (c *Client) Read(ctx context.Context, userId string, opt ...Option) (*UserReadResult, *api.Error, error) { if userId == "" { return nil, nil, fmt.Errorf("empty userId value passed into Read request") } @@ -126,18 +180,21 @@ func (c *Client) Read(ctx context.Context, userId string, opt ...Option) (*User, return nil, nil, fmt.Errorf("error performing client request during Read call: %w", err) } - target := new(User) - apiErr, err := resp.Decode(target) + target := new(UserReadResult) + target.Item = new(User) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Read response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Update(ctx context.Context, userId string, version uint32, opt ...Option) (*User, *api.Error, error) { +func (c *Client) Update(ctx context.Context, userId string, version uint32, opt ...Option) (*UserUpdateResult, *api.Error, error) { if userId == "" { return nil, nil, fmt.Errorf("empty userId value passed into Update request") } @@ -159,9 +216,12 @@ func (c *Client) Update(ctx context.Context, userId string, version uint32, opt 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 response found when performing initial check-and-set read") + } + if existingTarget.Item == nil { return nil, nil, errors.New("nil resource found when performing initial check-and-set read") } - version = existingTarget.Version + version = existingTarget.Item.Version } opts.postMap["version"] = version @@ -184,30 +244,33 @@ func (c *Client) Update(ctx context.Context, userId string, version uint32, opt return nil, nil, fmt.Errorf("error performing client request during Update call: %w", err) } - target := new(User) - apiErr, err := resp.Decode(target) + target := new(UserUpdateResult) + target.Item = new(User) + apiErr, err := resp.Decode(target.Item) if err != nil { return nil, nil, fmt.Errorf("error decoding Update response: %w", err) } if apiErr != nil { return nil, apiErr, nil } + target.responseBody = resp.Body + target.responseMap = resp.Map return target, apiErr, nil } -func (c *Client) Delete(ctx context.Context, userId string, opt ...Option) (bool, *api.Error, error) { +func (c *Client) Delete(ctx context.Context, userId string, opt ...Option) (*UserDeleteResult, *api.Error, error) { if userId == "" { - return false, nil, fmt.Errorf("empty userId value passed into Delete request") + return nil, nil, fmt.Errorf("empty userId value passed into Delete request") } if c.client == nil { - return false, nil, fmt.Errorf("nil client") + return nil, nil, fmt.Errorf("nil client") } opts, apiOpts := getOpts(opt...) req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("users/%s", userId), nil, apiOpts...) if err != nil { - return false, nil, fmt.Errorf("error creating Delete request: %w", err) + return nil, nil, fmt.Errorf("error creating Delete request: %w", err) } if len(opts.queryMap) > 0 { @@ -220,25 +283,25 @@ func (c *Client) Delete(ctx context.Context, userId string, opt ...Option) (bool resp, err := c.client.Do(req) if err != nil { - return false, nil, fmt.Errorf("error performing client request during Delete call: %w", err) + return nil, nil, fmt.Errorf("error performing client request during Delete call: %w", err) } apiErr, err := resp.Decode(nil) if err != nil { - return false, nil, fmt.Errorf("error decoding Delete response: %w", err) + return nil, nil, fmt.Errorf("error decoding Delete response: %w", err) } if apiErr != nil { - // We don't treat a 404 in this case as failure, in order for deletes to - // be idempotent - if apiErr.Status == http.StatusNotFound { - return false, nil, nil - } - return false, apiErr, nil + return nil, apiErr, nil } - return true, nil, nil + + target := &UserDeleteResult{ + responseBody: resp.Body, + responseMap: resp.Map, + } + return target, nil, nil } -func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*User, *api.Error, error) { +func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) (*UserListResult, *api.Error, error) { if scopeId == "" { return nil, nil, fmt.Errorf("empty scopeId value passed into List request") } @@ -267,10 +330,7 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Us return nil, nil, fmt.Errorf("error performing client request during List call: %w", err) } - type listResponse struct { - Items []*User - } - target := &listResponse{} + target := new(UserListResult) apiErr, err := resp.Decode(target) if err != nil { return nil, nil, fmt.Errorf("error decoding List response: %w", err) @@ -278,5 +338,7 @@ func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) ([]*Us if apiErr != nil { return nil, apiErr, nil } - return target.Items, apiErr, nil + target.responseBody = resp.Body + target.responseMap = resp.Map + return target, apiErr, nil } diff --git a/api/users/user_test.go b/api/users/user_test.go index 3ada5618d..c7f97dc84 100644 --- a/api/users/user_test.go +++ b/api/users/user_test.go @@ -27,31 +27,33 @@ func TestList(t *testing.T) { ul, apiErr, err := userClient.List(tc.Context(), org.GetPublicId()) assert.NoError(err) assert.Nil(apiErr) - assert.Empty(ul) + assert.Empty(ul.Items) var expected []*users.User for i := 0; i < 10; i++ { expected = append(expected, &users.User{Name: fmt.Sprint(i)}) } - expected[0], apiErr, err = userClient.Create(tc.Context(), org.GetPublicId(), users.WithName(expected[0].Name)) + ucr, apiErr, err := userClient.Create(tc.Context(), org.GetPublicId(), users.WithName(expected[0].Name)) assert.NoError(err) assert.Nil(apiErr) + expected[0] = ucr.Item ul, apiErr, err = userClient.List(tc.Context(), org.GetPublicId()) assert.NoError(err) assert.Nil(apiErr) - assert.ElementsMatch(comparableSlice(expected[:1]), comparableSlice(ul)) + assert.ElementsMatch(comparableSlice(expected[:1]), comparableSlice(ul.Items)) for i := 1; i < 10; i++ { - expected[i], apiErr, err = userClient.Create(tc.Context(), org.GetPublicId(), users.WithName(expected[i].Name)) + ucr, apiErr, err = userClient.Create(tc.Context(), org.GetPublicId(), users.WithName(expected[i].Name)) assert.NoError(err) assert.Nil(apiErr) + expected[i] = ucr.Item } ul, apiErr, err = userClient.List(tc.Context(), org.GetPublicId()) require.NoError(err) assert.Nil(apiErr) - assert.ElementsMatch(comparableSlice(expected), comparableSlice(ul)) + assert.ElementsMatch(comparableSlice(expected), comparableSlice(ul.Items)) } func comparableSlice(in []*users.User) []users.User { @@ -95,26 +97,25 @@ func TestCrud(t *testing.T) { } u, apiErr, err := userClient.Create(tc.Context(), org.GetPublicId(), users.WithName("foo")) - checkUser("create", u, apiErr, err, "foo", 1) + checkUser("create", u.Item, apiErr, err, "foo", 1) - u, apiErr, err = userClient.Read(tc.Context(), u.Id) - checkUser("read", u, apiErr, err, "foo", 1) + u, apiErr, err = userClient.Read(tc.Context(), u.Item.Id) + checkUser("read", u.Item, apiErr, err, "foo", 1) - u, apiErr, err = userClient.Update(tc.Context(), u.Id, u.Version, users.WithName("bar")) - checkUser("update", u, apiErr, err, "bar", 2) + u, apiErr, err = userClient.Update(tc.Context(), u.Item.Id, u.Item.Version, users.WithName("bar")) + checkUser("update", u.Item, apiErr, err, "bar", 2) - u, apiErr, err = userClient.Update(tc.Context(), u.Id, u.Version, users.DefaultName()) - checkUser("update", u, apiErr, err, "", 3) + u, apiErr, err = userClient.Update(tc.Context(), u.Item.Id, u.Item.Version, users.DefaultName()) + checkUser("update", u.Item, apiErr, err, "", 3) - existed, _, err := userClient.Delete(tc.Context(), u.Id) + _, apiErr, err = userClient.Delete(tc.Context(), u.Item.Id) require.NoError(err) assert.Nil(apiErr) - assert.True(existed, "Expected existing user when deleted, but it wasn't.") - existed, apiErr, err = userClient.Delete(tc.Context(), u.Id) + _, apiErr, err = userClient.Delete(tc.Context(), u.Item.Id) require.NoError(err) - assert.Nil(apiErr) - assert.False(existed) + assert.NotNil(apiErr) + assert.EqualValues(http.StatusNotFound, apiErr.Status) } func TestErrors(t *testing.T) { @@ -148,7 +149,7 @@ func TestErrors(t *testing.T) { assert.NotNil(apiErr) assert.EqualValues(http.StatusBadRequest, apiErr.Status) - _, apiErr, err = userClient.Update(tc.Context(), u.Id, u.Version) + _, apiErr, err = userClient.Update(tc.Context(), u.Item.Id, u.Item.Version) require.NoError(err) assert.NotNil(apiErr) assert.EqualValues(http.StatusBadRequest, apiErr.Status) diff --git a/api/util.go b/api/util.go index 1aa359fe2..b6d549cc6 100644 --- a/api/util.go +++ b/api/util.go @@ -1,46 +1,28 @@ package api -import "github.com/fatih/structs" +import ( + "bytes" + + "github.com/fatih/structs" +) func init() { structs.DefaultTagName = "json" } -// Bool returns the given bool as a bool pointer -func Bool(in bool) *bool { - ret := new(bool) - *ret = in - return ret +type GenericResult interface { + GetItem() interface{} + GetResponseBody() *bytes.Buffer + GetResponseMap() map[string]interface{} } -// String returns the given string as a string pointer -func String(in string) *string { - ret := new(string) - *ret = in - return ret +type GenericDeleteResult interface { + GetResponseBody() *bytes.Buffer + GetResponseMap() map[string]interface{} } -// StringOrNil is like String, but the returned pointer will be nil if the -// string is empty -func StringOrNil(in string) *string { - if in == "" { - return nil - } - return String(in) -} - -// Int returns the given int64 as an int64 pointer -func Int(in int32) *int32 { - ret := new(int32) - *ret = in - return ret -} - -// IntOrNil is like Int, but the returned pointer will be nil if the integer is -// 0 -func IntOrNil(in int32) *int32 { - if in == 0 { - return nil - } - return Int(in) +type GenericListResult interface { + GetItems() interface{} + GetResponseBody() *bytes.Buffer + GetResponseMap() map[string]interface{} } diff --git a/internal/cmd/commands/accounts/account.go b/internal/cmd/commands/accounts/account.go index 2453d91bc..7c85256c0 100644 --- a/internal/cmd/commands/accounts/account.go +++ b/internal/cmd/commands/accounts/account.go @@ -2,6 +2,7 @@ package accounts import ( "fmt" + "net/http" "os" "strings" @@ -260,22 +261,26 @@ func (c *Command) Run(args []string) int { accountClient := accounts.NewClient(client) - var existed bool - var account *accounts.Account - var listedAccounts []*accounts.Account + existed := true + var result api.GenericResult + var listResult api.GenericListResult var apiErr *api.Error switch c.Func { case "read": - account, apiErr, err = accountClient.Read(c.Context, c.FlagId, opts...) + result, apiErr, err = accountClient.Read(c.Context, c.FlagId, opts...) case "delete": - existed, apiErr, err = accountClient.Delete(c.Context, c.FlagId, opts...) + _, apiErr, err = accountClient.Delete(c.Context, c.FlagId, opts...) + if apiErr != nil && apiErr.Status == int32(http.StatusNotFound) { + existed = false + apiErr = nil + } case "list": - listedAccounts, apiErr, err = accountClient.List(c.Context, c.flagAuthMethodId, opts...) + listResult, 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...) + result, 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...) + result, apiErr, err = accountClient.ChangePassword(c.Context, c.FlagId, c.flagCurrentPassword, c.flagNewPassword, version, opts...) } plural := "account" @@ -309,13 +314,14 @@ func (c *Command) Run(args []string) int { return 0 case "list": + accounts := listResult.GetItems().([]*accounts.Account) switch base.Format(c.UI) { case "json": - if len(listedAccounts) == 0 { + if len(accounts) == 0 { c.UI.Output("null") return 0 } - b, err := base.JsonFormatter{}.Format(listedAccounts) + b, err := base.JsonFormatter{}.Format(accounts) if err != nil { c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error()) return 1 @@ -323,7 +329,7 @@ func (c *Command) Run(args []string) int { c.UI.Output(string(b)) case "table": - if len(listedAccounts) == 0 { + if len(accounts) == 0 { c.UI.Output("No accounts found") return 0 } @@ -332,7 +338,7 @@ func (c *Command) Run(args []string) int { "", "Account information:", } - for i, m := range listedAccounts { + for i, m := range accounts { if i > 0 { output = append(output, "") } @@ -359,6 +365,7 @@ func (c *Command) Run(args []string) int { return 0 } + account := result.GetItem().(*accounts.Account) switch base.Format(c.UI) { case "table": c.UI.Output(generateAccountTableOutput(account)) diff --git a/internal/cmd/commands/accounts/password.go b/internal/cmd/commands/accounts/password.go index 83fadefb6..2233b5303 100644 --- a/internal/cmd/commands/accounts/password.go +++ b/internal/cmd/commands/accounts/password.go @@ -206,14 +206,14 @@ func (c *PasswordCommand) Run(args []string) int { } } - var account *accounts.Account + var result api.GenericResult var apiErr *api.Error switch c.Func { case "create": - account, apiErr, err = accountClient.Create(c.Context, c.flagAuthMethodId, opts...) + result, apiErr, err = accountClient.Create(c.Context, c.flagAuthMethodId, opts...) case "update": - account, apiErr, err = accountClient.Update(c.Context, c.FlagId, version, opts...) + result, apiErr, err = accountClient.Update(c.Context, c.FlagId, version, opts...) } plural := "password-type account" @@ -226,6 +226,7 @@ func (c *PasswordCommand) Run(args []string) int { return 1 } + account := result.GetItem().(*accounts.Account) switch base.Format(c.UI) { case "table": c.UI.Output(generateAccountTableOutput(account)) diff --git a/internal/cmd/commands/authenticate/password.go b/internal/cmd/commands/authenticate/password.go index cbeeb9add..459781907 100644 --- a/internal/cmd/commands/authenticate/password.go +++ b/internal/cmd/commands/authenticate/password.go @@ -135,14 +135,15 @@ func (c *PasswordCommand) Run(args []string) int { return 1 } + token := result.Item switch base.Format(c.UI) { case "table": c.UI.Output(base.WrapForHelpText([]string{ "", "Authentication information:", - fmt.Sprintf(" Expiration Time: %s", result.ExpirationTime.Local().Format(time.RFC3339)), - fmt.Sprintf(" Token: %s", result.Token), - fmt.Sprintf(" User ID: %s", result.UserId), + fmt.Sprintf(" Expiration Time: %s", token.ExpirationTime.Local().Format(time.RFC3339)), + fmt.Sprintf(" Token: %s", token.Token), + fmt.Sprintf(" User ID: %s", token.UserId), })) } diff --git a/internal/cmd/commands/authmethods/authmethod.go b/internal/cmd/commands/authmethods/authmethod.go index f12ddb08c..ad78e8b57 100644 --- a/internal/cmd/commands/authmethods/authmethod.go +++ b/internal/cmd/commands/authmethods/authmethod.go @@ -2,6 +2,7 @@ package authmethods import ( "fmt" + "net/http" "github.com/hashicorp/boundary/api" "github.com/hashicorp/boundary/api/authmethods" @@ -153,18 +154,22 @@ func (c *Command) Run(args []string) int { authmethodClient := authmethods.NewClient(client) - var existed bool - var method *authmethods.AuthMethod - var listedMethods []*authmethods.AuthMethod + existed := true + var result api.GenericResult + var listResult api.GenericListResult var apiErr *api.Error switch c.Func { case "read": - method, apiErr, err = authmethodClient.Read(c.Context, c.FlagId, opts...) + result, apiErr, err = authmethodClient.Read(c.Context, c.FlagId, opts...) case "delete": - existed, apiErr, err = authmethodClient.Delete(c.Context, c.FlagId, opts...) + _, apiErr, err = authmethodClient.Delete(c.Context, c.FlagId, opts...) + if apiErr != nil && apiErr.Status == int32(http.StatusNotFound) { + existed = false + apiErr = nil + } case "list": - listedMethods, apiErr, err = authmethodClient.List(c.Context, c.FlagScopeId, opts...) + listResult, apiErr, err = authmethodClient.List(c.Context, c.FlagScopeId, opts...) } plural := "auth method" @@ -198,6 +203,7 @@ func (c *Command) Run(args []string) int { return 0 case "list": + listedMethods := listResult.GetItems().([]*authmethods.AuthMethod) switch base.Format(c.UI) { case "json": if len(listedMethods) == 0 { @@ -252,6 +258,7 @@ func (c *Command) Run(args []string) int { return 0 } + method := result.GetItem().(*authmethods.AuthMethod) switch base.Format(c.UI) { case "table": c.UI.Output(generateAuthMethodTableOutput(method)) diff --git a/internal/cmd/commands/authmethods/password.go b/internal/cmd/commands/authmethods/password.go index 5fc283704..2eb9ac8e7 100644 --- a/internal/cmd/commands/authmethods/password.go +++ b/internal/cmd/commands/authmethods/password.go @@ -184,14 +184,14 @@ func (c *PasswordCommand) Run(args []string) int { } } - var method *authmethods.AuthMethod + var result api.GenericResult var apiErr *api.Error switch c.Func { case "create": - method, apiErr, err = authmethodClient.Create(c.Context, "password", c.FlagScopeId, opts...) + result, apiErr, err = authmethodClient.Create(c.Context, "password", c.FlagScopeId, opts...) case "update": - method, apiErr, err = authmethodClient.Update(c.Context, c.FlagId, version, opts...) + result, apiErr, err = authmethodClient.Update(c.Context, c.FlagId, version, opts...) } plural := "password-type auth-method" @@ -204,6 +204,7 @@ func (c *PasswordCommand) Run(args []string) int { return 1 } + method := result.GetItem().(*authmethods.AuthMethod) switch base.Format(c.UI) { case "table": c.UI.Output(generateAuthMethodTableOutput(method)) diff --git a/internal/cmd/commands/authtokens/authtokens.go b/internal/cmd/commands/authtokens/authtokens.go index ee0966d0a..d26f905cc 100644 --- a/internal/cmd/commands/authtokens/authtokens.go +++ b/internal/cmd/commands/authtokens/authtokens.go @@ -2,6 +2,7 @@ package authtokens import ( "fmt" + "net/http" "time" "github.com/hashicorp/boundary/api" @@ -90,18 +91,22 @@ func (c *Command) Run(args []string) int { authtokenClient := authtokens.NewClient(client) - var existed bool - var token *authtokens.AuthToken - var listedTokens []*authtokens.AuthToken + existed := true + var result api.GenericResult + var listResult api.GenericListResult var apiErr *api.Error switch c.Func { case "read": - token, apiErr, err = authtokenClient.Read(c.Context, c.FlagId) + result, apiErr, err = authtokenClient.Read(c.Context, c.FlagId) case "delete": - existed, apiErr, err = authtokenClient.Delete(c.Context, c.FlagId) + _, apiErr, err = authtokenClient.Delete(c.Context, c.FlagId) + if apiErr != nil && apiErr.Status == int32(http.StatusNotFound) { + existed = false + apiErr = nil + } case "list": - listedTokens, apiErr, err = authtokenClient.List(c.Context, c.FlagScopeId) + listResult, apiErr, err = authtokenClient.List(c.Context, c.FlagScopeId) } plural := "auth token" @@ -135,6 +140,7 @@ func (c *Command) Run(args []string) int { return 0 case "list": + listedTokens := listResult.GetItems().([]*authtokens.AuthToken) switch base.Format(c.UI) { case "json": if len(listedTokens) == 0 { @@ -177,6 +183,7 @@ func (c *Command) Run(args []string) int { return 0 } + token := result.GetItem().(*authtokens.AuthToken) switch base.Format(c.UI) { case "table": c.UI.Output(generateAuthTokenTableOutput(token)) diff --git a/internal/cmd/commands/groups/group.go b/internal/cmd/commands/groups/group.go index 1fbd36b75..61ee191c2 100644 --- a/internal/cmd/commands/groups/group.go +++ b/internal/cmd/commands/groups/group.go @@ -2,6 +2,7 @@ package groups import ( "fmt" + "net/http" "github.com/hashicorp/boundary/api" "github.com/hashicorp/boundary/api/groups" @@ -161,28 +162,32 @@ func (c *Command) Run(args []string) int { } } - var existed bool - var group *groups.Group - var listedGroups []*groups.Group + existed := true + var result api.GenericResult + var listResult api.GenericListResult var apiErr *api.Error switch c.Func { case "create": - group, apiErr, err = groupClient.Create(c.Context, c.FlagScopeId, opts...) + result, apiErr, err = groupClient.Create(c.Context, c.FlagScopeId, opts...) case "update": - group, apiErr, err = groupClient.Update(c.Context, c.FlagId, version, opts...) + result, apiErr, err = groupClient.Update(c.Context, c.FlagId, version, opts...) case "read": - group, apiErr, err = groupClient.Read(c.Context, c.FlagId, opts...) + result, apiErr, err = groupClient.Read(c.Context, c.FlagId, opts...) case "delete": - existed, apiErr, err = groupClient.Delete(c.Context, c.FlagId, opts...) + _, apiErr, err = groupClient.Delete(c.Context, c.FlagId, opts...) + if apiErr != nil && apiErr.Status == int32(http.StatusNotFound) { + existed = false + apiErr = nil + } case "list": - listedGroups, apiErr, err = groupClient.List(c.Context, c.FlagScopeId, opts...) + listResult, apiErr, err = groupClient.List(c.Context, c.FlagScopeId, opts...) case "add-members": - group, apiErr, err = groupClient.AddMembers(c.Context, c.FlagId, version, members, opts...) + result, apiErr, err = groupClient.AddMembers(c.Context, c.FlagId, version, members, opts...) case "set-members": - group, apiErr, err = groupClient.SetMembers(c.Context, c.FlagId, version, members, opts...) + result, apiErr, err = groupClient.SetMembers(c.Context, c.FlagId, version, members, opts...) case "remove-members": - group, apiErr, err = groupClient.RemoveMembers(c.Context, c.FlagId, version, members, opts...) + result, apiErr, err = groupClient.RemoveMembers(c.Context, c.FlagId, version, members, opts...) } plural := "group" @@ -216,6 +221,7 @@ func (c *Command) Run(args []string) int { return 0 case "list": + listedGroups := listResult.GetItems().([]*groups.Group) switch base.Format(c.UI) { case "json": if len(listedGroups) == 0 { @@ -265,6 +271,7 @@ func (c *Command) Run(args []string) int { return 0 } + group := result.GetItem().(*groups.Group) switch base.Format(c.UI) { case "table": c.UI.Output(generateGroupTableOutput(group)) diff --git a/internal/cmd/commands/hostcatalogs/hostcatalog.go b/internal/cmd/commands/hostcatalogs/hostcatalog.go index 1a5a142f7..440f7d766 100644 --- a/internal/cmd/commands/hostcatalogs/hostcatalog.go +++ b/internal/cmd/commands/hostcatalogs/hostcatalog.go @@ -2,6 +2,7 @@ package hostcatalogs import ( "fmt" + "net/http" "github.com/hashicorp/boundary/api" "github.com/hashicorp/boundary/api/hostcatalogs" @@ -153,18 +154,22 @@ func (c *Command) Run(args []string) int { hostcatalogClient := hostcatalogs.NewClient(client) - var existed bool - var catalog *hostcatalogs.HostCatalog - var listedCatalogs []*hostcatalogs.HostCatalog + existed := true + var result api.GenericResult + var listResult api.GenericListResult var apiErr *api.Error switch c.Func { case "read": - catalog, apiErr, err = hostcatalogClient.Read(c.Context, c.FlagId, opts...) + result, apiErr, err = hostcatalogClient.Read(c.Context, c.FlagId, opts...) case "delete": - existed, apiErr, err = hostcatalogClient.Delete(c.Context, c.FlagId, opts...) + _, apiErr, err = hostcatalogClient.Delete(c.Context, c.FlagId, opts...) + if apiErr != nil && apiErr.Status == int32(http.StatusNotFound) { + existed = false + apiErr = nil + } case "list": - listedCatalogs, apiErr, err = hostcatalogClient.List(c.Context, c.FlagScopeId, opts...) + listResult, apiErr, err = hostcatalogClient.List(c.Context, c.FlagScopeId, opts...) } plural := "host catalog" @@ -198,6 +203,7 @@ func (c *Command) Run(args []string) int { return 0 case "list": + listedCatalogs := listResult.GetItems().([]*hostcatalogs.HostCatalog) switch base.Format(c.UI) { case "json": if len(listedCatalogs) == 0 { @@ -248,6 +254,7 @@ func (c *Command) Run(args []string) int { return 0 } + catalog := result.GetItem().(*hostcatalogs.HostCatalog) switch base.Format(c.UI) { case "table": c.UI.Output(generateHostCatalogTableOutput(catalog)) diff --git a/internal/cmd/commands/hostcatalogs/static.go b/internal/cmd/commands/hostcatalogs/static.go index 8ed4f2859..95419e49c 100644 --- a/internal/cmd/commands/hostcatalogs/static.go +++ b/internal/cmd/commands/hostcatalogs/static.go @@ -140,14 +140,14 @@ func (c *StaticCommand) Run(args []string) int { } } - var catalog *hostcatalogs.HostCatalog + var result api.GenericResult var apiErr *api.Error switch c.Func { case "create": - catalog, apiErr, err = hostcatalogClient.Create(c.Context, "static", c.FlagScopeId, opts...) + result, apiErr, err = hostcatalogClient.Create(c.Context, "static", c.FlagScopeId, opts...) case "update": - catalog, apiErr, err = hostcatalogClient.Update(c.Context, c.FlagId, version, opts...) + result, apiErr, err = hostcatalogClient.Update(c.Context, c.FlagId, version, opts...) } plural := "static-type host-catalog" @@ -160,6 +160,7 @@ func (c *StaticCommand) Run(args []string) int { return 1 } + catalog := result.GetItem().(*hostcatalogs.HostCatalog) switch base.Format(c.UI) { case "table": c.UI.Output(generateHostCatalogTableOutput(catalog)) diff --git a/internal/cmd/commands/hosts/host.go b/internal/cmd/commands/hosts/host.go index 87877bd3a..992061b7d 100644 --- a/internal/cmd/commands/hosts/host.go +++ b/internal/cmd/commands/hosts/host.go @@ -2,6 +2,7 @@ package hosts import ( "fmt" + "net/http" "github.com/hashicorp/boundary/api" "github.com/hashicorp/boundary/api/hosts" @@ -164,18 +165,22 @@ func (c *Command) Run(args []string) int { hostClient := hosts.NewClient(client) - var existed bool - var host *hosts.Host - var listedHosts []*hosts.Host + existed := true + var result api.GenericResult + var listResult api.GenericListResult var apiErr *api.Error switch c.Func { case "read": - host, apiErr, err = hostClient.Read(c.Context, c.FlagId, opts...) + result, apiErr, err = hostClient.Read(c.Context, c.FlagId, opts...) case "delete": - existed, apiErr, err = hostClient.Delete(c.Context, c.FlagId, opts...) + _, apiErr, err = hostClient.Delete(c.Context, c.FlagId, opts...) + if apiErr != nil && apiErr.Status == int32(http.StatusNotFound) { + existed = false + apiErr = nil + } case "list": - listedHosts, apiErr, err = hostClient.List(c.Context, c.flagHostCatalogId, opts...) + listResult, apiErr, err = hostClient.List(c.Context, c.flagHostCatalogId, opts...) } plural := "host" @@ -209,6 +214,7 @@ func (c *Command) Run(args []string) int { return 0 case "list": + listedHosts := listResult.GetItems().([]*hosts.Host) switch base.Format(c.UI) { case "json": if len(listedHosts) == 0 { @@ -259,6 +265,7 @@ func (c *Command) Run(args []string) int { return 0 } + host := result.GetItem().(*hosts.Host) switch base.Format(c.UI) { case "table": c.UI.Output(generateHostTableOutput(host)) diff --git a/internal/cmd/commands/hosts/static.go b/internal/cmd/commands/hosts/static.go index 796343be8..531955dff 100644 --- a/internal/cmd/commands/hosts/static.go +++ b/internal/cmd/commands/hosts/static.go @@ -180,14 +180,14 @@ func (c *StaticCommand) Run(args []string) int { } } - var host *hosts.Host + var result api.GenericResult var apiErr *api.Error switch c.Func { case "create": - host, apiErr, err = hostClient.Create(c.Context, c.flagHostCatalogId, opts...) + result, apiErr, err = hostClient.Create(c.Context, c.flagHostCatalogId, opts...) case "update": - host, apiErr, err = hostClient.Update(c.Context, c.FlagId, version, opts...) + result, apiErr, err = hostClient.Update(c.Context, c.FlagId, version, opts...) } plural := "static-type host" @@ -200,6 +200,7 @@ func (c *StaticCommand) Run(args []string) int { return 1 } + host := result.GetItem().(*hosts.Host) switch base.Format(c.UI) { case "table": c.UI.Output(generateHostTableOutput(host)) diff --git a/internal/cmd/commands/hostsets/hostset.go b/internal/cmd/commands/hostsets/hostset.go index 35ceb8757..7bccc0731 100644 --- a/internal/cmd/commands/hostsets/hostset.go +++ b/internal/cmd/commands/hostsets/hostset.go @@ -2,6 +2,7 @@ package hostsets import ( "fmt" + "net/http" "github.com/hashicorp/boundary/api" "github.com/hashicorp/boundary/api/hostsets" @@ -244,24 +245,28 @@ func (c *Command) Run(args []string) int { hostsetClient := hostsets.NewClient(client) - var existed bool - var set *hostsets.HostSet - var listedSets []*hostsets.HostSet + existed := true + var result api.GenericResult + var listResult api.GenericListResult var apiErr *api.Error switch c.Func { case "read": - set, apiErr, err = hostsetClient.Read(c.Context, c.FlagId, opts...) + result, apiErr, err = hostsetClient.Read(c.Context, c.FlagId, opts...) case "delete": - existed, apiErr, err = hostsetClient.Delete(c.Context, c.FlagId, opts...) + _, apiErr, err = hostsetClient.Delete(c.Context, c.FlagId, opts...) + if apiErr != nil && apiErr.Status == int32(http.StatusNotFound) { + existed = false + apiErr = nil + } case "list": - listedSets, apiErr, err = hostsetClient.List(c.Context, c.flagHostCatalogId, opts...) + listResult, apiErr, err = hostsetClient.List(c.Context, c.flagHostCatalogId, opts...) case "add-hosts": - set, apiErr, err = hostsetClient.AddHosts(c.Context, c.FlagId, version, hosts, opts...) + result, apiErr, err = hostsetClient.AddHosts(c.Context, c.FlagId, version, hosts, opts...) case "remove-hosts": - set, apiErr, err = hostsetClient.RemoveHosts(c.Context, c.FlagId, version, hosts, opts...) + result, apiErr, err = hostsetClient.RemoveHosts(c.Context, c.FlagId, version, hosts, opts...) case "set-hosts": - set, apiErr, err = hostsetClient.SetHosts(c.Context, c.FlagId, version, hosts, opts...) + result, apiErr, err = hostsetClient.SetHosts(c.Context, c.FlagId, version, hosts, opts...) } plural := "host set" @@ -295,6 +300,7 @@ func (c *Command) Run(args []string) int { return 0 case "list": + listedSets := listResult.GetItems().([]*hostsets.HostSet) switch base.Format(c.UI) { case "json": if len(listedSets) == 0 { @@ -345,6 +351,7 @@ func (c *Command) Run(args []string) int { return 0 } + set := result.GetItem().(*hostsets.HostSet) switch base.Format(c.UI) { case "table": c.UI.Output(generateHostSetTableOutput(set)) diff --git a/internal/cmd/commands/hostsets/static.go b/internal/cmd/commands/hostsets/static.go index e9bed142f..a8278b4d7 100644 --- a/internal/cmd/commands/hostsets/static.go +++ b/internal/cmd/commands/hostsets/static.go @@ -151,14 +151,14 @@ func (c *StaticCommand) Run(args []string) int { } } - var set *hostsets.HostSet + var result api.GenericResult var apiErr *api.Error switch c.Func { case "create": - set, apiErr, err = hostsetClient.Create(c.Context, c.flagHostCatalogId, opts...) + result, apiErr, err = hostsetClient.Create(c.Context, c.flagHostCatalogId, opts...) case "update": - set, apiErr, err = hostsetClient.Update(c.Context, c.FlagId, version, opts...) + result, apiErr, err = hostsetClient.Update(c.Context, c.FlagId, version, opts...) } plural := "static-type host-set" @@ -171,6 +171,7 @@ func (c *StaticCommand) Run(args []string) int { return 1 } + set := result.GetItem().(*hostsets.HostSet) switch base.Format(c.UI) { case "table": c.UI.Output(generateHostSetTableOutput(set)) diff --git a/internal/cmd/commands/roles/role.go b/internal/cmd/commands/roles/role.go index f1a02e0bb..2a0475a40 100644 --- a/internal/cmd/commands/roles/role.go +++ b/internal/cmd/commands/roles/role.go @@ -2,6 +2,7 @@ package roles import ( "fmt" + "net/http" "github.com/hashicorp/boundary/api" "github.com/hashicorp/boundary/api/roles" @@ -206,34 +207,36 @@ func (c *Command) Run(args []string) int { } } - var existed bool - var role *roles.Role - var listedRoles []*roles.Role + existed := true + var result api.GenericResult + var listResult api.GenericListResult var apiErr *api.Error switch c.Func { case "create": - role, apiErr, err = roleClient.Create(c.Context, c.FlagScopeId, opts...) + result, apiErr, err = roleClient.Create(c.Context, c.FlagScopeId, opts...) case "update": - role, apiErr, err = roleClient.Update(c.Context, c.FlagId, version, opts...) + result, apiErr, err = roleClient.Update(c.Context, c.FlagId, version, opts...) case "read": - role, apiErr, err = roleClient.Read(c.Context, c.FlagId, opts...) + result, apiErr, err = roleClient.Read(c.Context, c.FlagId, opts...) case "delete": - existed, apiErr, err = roleClient.Delete(c.Context, c.FlagId, opts...) + _, apiErr, err = roleClient.Delete(c.Context, c.FlagId, opts...) + if apiErr != nil && apiErr.Status == int32(http.StatusNotFound) { + existed = false + apiErr = nil + } case "list": - listedRoles, apiErr, err = roleClient.List(c.Context, c.FlagScopeId, opts...) + listResult, apiErr, err = roleClient.List(c.Context, c.FlagScopeId, opts...) case "add-principals": - role, apiErr, err = roleClient.AddPrincipals(c.Context, c.FlagId, version, principals, opts...) + result, apiErr, err = roleClient.AddPrincipals(c.Context, c.FlagId, version, principals, opts...) case "set-principals": - role, apiErr, err = roleClient.SetPrincipals(c.Context, c.FlagId, version, principals, opts...) + result, apiErr, err = roleClient.SetPrincipals(c.Context, c.FlagId, version, principals, opts...) case "remove-principals": - role, apiErr, err = roleClient.RemovePrincipals(c.Context, c.FlagId, version, principals, opts...) + result, apiErr, err = roleClient.RemovePrincipals(c.Context, c.FlagId, version, principals, opts...) case "add-grants": - role, apiErr, err = roleClient.AddGrants(c.Context, c.FlagId, version, grants, opts...) - case "set-grants": - role, apiErr, err = roleClient.SetGrants(c.Context, c.FlagId, version, grants, opts...) + result, apiErr, err = roleClient.SetGrants(c.Context, c.FlagId, version, grants, opts...) case "remove-grants": - role, apiErr, err = roleClient.RemoveGrants(c.Context, c.FlagId, version, grants, opts...) + result, apiErr, err = roleClient.RemoveGrants(c.Context, c.FlagId, version, grants, opts...) } plural := "role" @@ -267,6 +270,7 @@ func (c *Command) Run(args []string) int { return 0 case "list": + listedRoles := listResult.GetItems().([]*roles.Role) switch base.Format(c.UI) { case "json": if len(listedRoles) == 0 { @@ -316,6 +320,7 @@ func (c *Command) Run(args []string) int { return 0 } + role := result.GetItem().(*roles.Role) switch base.Format(c.UI) { case "table": c.UI.Output(generateRoleTableOutput(role)) diff --git a/internal/cmd/commands/scopes/scope.go b/internal/cmd/commands/scopes/scope.go index cc17b45cd..8b3633d88 100644 --- a/internal/cmd/commands/scopes/scope.go +++ b/internal/cmd/commands/scopes/scope.go @@ -2,6 +2,7 @@ package scopes import ( "fmt" + "net/http" "github.com/hashicorp/boundary/api" "github.com/hashicorp/boundary/api/scopes" @@ -134,22 +135,26 @@ func (c *Command) Run(args []string) int { } } - var existed bool - var scope *scopes.Scope - var listedScopes []*scopes.Scope + existed := true + var result api.GenericResult + var listResult api.GenericListResult var apiErr *api.Error switch c.Func { case "create": - scope, apiErr, err = scopeClient.Create(c.Context, c.FlagScopeId, opts...) + result, apiErr, err = scopeClient.Create(c.Context, c.FlagScopeId, opts...) case "update": - scope, apiErr, err = scopeClient.Update(c.Context, c.FlagId, version, opts...) + result, apiErr, err = scopeClient.Update(c.Context, c.FlagId, version, opts...) case "read": - scope, apiErr, err = scopeClient.Read(c.Context, c.FlagId, opts...) + result, apiErr, err = scopeClient.Read(c.Context, c.FlagId, opts...) case "delete": - existed, apiErr, err = scopeClient.Delete(c.Context, c.FlagId, opts...) + _, apiErr, err = scopeClient.Delete(c.Context, c.FlagId, opts...) + if apiErr != nil && apiErr.Status == int32(http.StatusNotFound) { + existed = false + apiErr = nil + } case "list": - listedScopes, apiErr, err = scopeClient.List(c.Context, c.FlagScopeId, opts...) + listResult, apiErr, err = scopeClient.List(c.Context, c.FlagScopeId, opts...) } plural := "scope" @@ -183,6 +188,7 @@ func (c *Command) Run(args []string) int { return 0 case "list": + listedScopes := listResult.GetItems().([]*scopes.Scope) switch base.Format(c.UI) { case "json": if len(listedScopes) == 0 { @@ -232,6 +238,7 @@ func (c *Command) Run(args []string) int { return 0 } + scope := result.GetItem().(*scopes.Scope) switch base.Format(c.UI) { case "table": c.UI.Output(generateScopeTableOutput(scope)) diff --git a/internal/cmd/commands/targets/target.go b/internal/cmd/commands/targets/target.go index 2a94f182c..a1285f6fc 100644 --- a/internal/cmd/commands/targets/target.go +++ b/internal/cmd/commands/targets/target.go @@ -2,6 +2,7 @@ package targets import ( "fmt" + "net/http" "os" "github.com/hashicorp/boundary/api" @@ -238,24 +239,28 @@ func (c *Command) Run(args []string) int { targetClient := targets.NewClient(client) - var existed bool - var target *targets.Target - var listedCatalogs []*targets.Target + existed := true + var result api.GenericResult + var listResult api.GenericListResult var apiErr *api.Error switch c.Func { case "read": - target, apiErr, err = targetClient.Read(c.Context, c.FlagId, opts...) + result, apiErr, err = targetClient.Read(c.Context, c.FlagId, opts...) case "delete": - existed, apiErr, err = targetClient.Delete(c.Context, c.FlagId, opts...) + _, apiErr, err = targetClient.Delete(c.Context, c.FlagId, opts...) + if apiErr != nil && apiErr.Status == int32(http.StatusNotFound) { + existed = false + apiErr = nil + } case "list": - listedCatalogs, apiErr, err = targetClient.List(c.Context, c.FlagScopeId, opts...) + listResult, apiErr, err = targetClient.List(c.Context, c.FlagScopeId, opts...) case "add-host-sets": - target, apiErr, err = targetClient.AddHostSets(c.Context, c.FlagId, version, hostSets, opts...) + result, apiErr, err = targetClient.AddHostSets(c.Context, c.FlagId, version, hostSets, opts...) case "remove-host-sets": - target, apiErr, err = targetClient.RemoveHostSets(c.Context, c.FlagId, version, hostSets, opts...) + result, apiErr, err = targetClient.RemoveHostSets(c.Context, c.FlagId, version, hostSets, opts...) case "set-host-sets": - target, apiErr, err = targetClient.SetHostSets(c.Context, c.FlagId, version, hostSets, opts...) + result, apiErr, err = targetClient.SetHostSets(c.Context, c.FlagId, version, hostSets, opts...) } plural := "target" @@ -289,13 +294,14 @@ func (c *Command) Run(args []string) int { return 0 case "list": + listedTargets := listResult.GetItems().([]*targets.Target) switch base.Format(c.UI) { case "json": - if len(listedCatalogs) == 0 { + if len(listedTargets) == 0 { c.UI.Output("null") return 0 } - b, err := base.JsonFormatter{}.Format(listedCatalogs) + b, err := base.JsonFormatter{}.Format(listedTargets) if err != nil { c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error()) return 1 @@ -303,7 +309,7 @@ func (c *Command) Run(args []string) int { c.UI.Output(string(b)) case "table": - if len(listedCatalogs) == 0 { + if len(listedTargets) == 0 { c.UI.Output("No targets found") return 0 } @@ -312,7 +318,7 @@ func (c *Command) Run(args []string) int { "", "Target information:", } - for i, m := range listedCatalogs { + for i, m := range listedTargets { if i > 0 { output = append(output, "") } @@ -339,6 +345,7 @@ func (c *Command) Run(args []string) int { return 0 } + target := result.GetItem().(*targets.Target) switch base.Format(c.UI) { case "table": c.UI.Output(generateTargetTableOutput(target)) diff --git a/internal/cmd/commands/targets/tcp.go b/internal/cmd/commands/targets/tcp.go index 7fc49c8e8..1b13ba5db 100644 --- a/internal/cmd/commands/targets/tcp.go +++ b/internal/cmd/commands/targets/tcp.go @@ -164,14 +164,14 @@ func (c *TcpCommand) Run(args []string) int { } } - var catalog *targets.Target + var result api.GenericResult var apiErr *api.Error switch c.Func { case "create": - catalog, apiErr, err = targetClient.Create(c.Context, "tcp", c.FlagScopeId, opts...) + result, apiErr, err = targetClient.Create(c.Context, "tcp", c.FlagScopeId, opts...) case "update": - catalog, apiErr, err = targetClient.Update(c.Context, c.FlagId, version, opts...) + result, apiErr, err = targetClient.Update(c.Context, c.FlagId, version, opts...) } plural := "tcp-type target" @@ -184,11 +184,12 @@ func (c *TcpCommand) Run(args []string) int { return 1 } + target := result.GetItem().(*targets.Target) switch base.Format(c.UI) { case "table": - c.UI.Output(generateTargetTableOutput(catalog)) + c.UI.Output(generateTargetTableOutput(target)) case "json": - b, err := base.JsonFormatter{}.Format(catalog) + b, err := base.JsonFormatter{}.Format(target) if err != nil { c.UI.Error(fmt.Errorf("Error formatting as JSON: %w", err).Error()) return 1 diff --git a/internal/cmd/commands/users/user.go b/internal/cmd/commands/users/user.go index cb539c6ab..9b04217f5 100644 --- a/internal/cmd/commands/users/user.go +++ b/internal/cmd/commands/users/user.go @@ -2,6 +2,7 @@ package users import ( "fmt" + "net/http" "github.com/hashicorp/boundary/api" "github.com/hashicorp/boundary/api/users" @@ -123,22 +124,26 @@ func (c *Command) Run(args []string) int { } } - var existed bool - var user *users.User - var listedUsers []*users.User + existed := true + var result api.GenericResult + var listResult api.GenericListResult var apiErr *api.Error switch c.Func { case "create": - user, apiErr, err = userClient.Create(c.Context, c.FlagScopeId, opts...) + result, apiErr, err = userClient.Create(c.Context, c.FlagScopeId, opts...) case "update": - user, apiErr, err = userClient.Update(c.Context, c.FlagId, version, opts...) + result, apiErr, err = userClient.Update(c.Context, c.FlagId, version, opts...) case "read": - user, apiErr, err = userClient.Read(c.Context, c.FlagId, opts...) + result, apiErr, err = userClient.Read(c.Context, c.FlagId, opts...) case "delete": - existed, apiErr, err = userClient.Delete(c.Context, c.FlagId, opts...) + _, apiErr, err = userClient.Delete(c.Context, c.FlagId, opts...) + if apiErr != nil && apiErr.Status == int32(http.StatusNotFound) { + existed = false + apiErr = nil + } case "list": - listedUsers, apiErr, err = userClient.List(c.Context, c.FlagScopeId, opts...) + listResult, apiErr, err = userClient.List(c.Context, c.FlagScopeId, opts...) } plural := "user" @@ -172,6 +177,7 @@ func (c *Command) Run(args []string) int { return 0 case "list": + listedUsers := listResult.GetItems().([]*users.User) switch base.Format(c.UI) { case "json": if len(listedUsers) == 0 { @@ -221,6 +227,7 @@ func (c *Command) Run(args []string) int { return 0 } + user := result.GetItem().(*users.User) switch base.Format(c.UI) { case "table": c.UI.Output(generateUserTableOutput(user)) diff --git a/internal/servers/controller/multi_test.go b/internal/servers/controller/multi_test.go index a1fba3e95..b036cf730 100644 --- a/internal/servers/controller/multi_test.go +++ b/internal/servers/controller/multi_test.go @@ -36,16 +36,18 @@ func TestAuthenticationMulti(t *testing.T) { defer c2.Shutdown() auth := authmethods.NewClient(c1.Client()) - token1, apiErr, err := auth.Authenticate(c1.Context(), amId, map[string]interface{}{"login_name": user, "password": password}) + token1Result, apiErr, err := auth.Authenticate(c1.Context(), amId, map[string]interface{}{"login_name": user, "password": password}) require.Nil(err) require.Nil(apiErr) + token1 := token1Result.Item require.NotNil(token1) time.Sleep(5 * time.Second) auth = authmethods.NewClient(c2.Client()) - token2, apiErr, err := auth.Authenticate(c2.Context(), amId, map[string]interface{}{"login_name": user, "password": password}) + token2Result, apiErr, err := auth.Authenticate(c2.Context(), amId, map[string]interface{}{"login_name": user, "password": password}) require.Nil(err) require.Nil(apiErr) + token2 := token2Result.Item require.NotNil(token2) assert.NotEqual(token1.Token, token2.Token) @@ -57,10 +59,10 @@ func TestAuthenticationMulti(t *testing.T) { org, apiErr, err := scopes.NewClient(c1.Client()).Create(c1.Context(), scope.Global.String()) require.NoError(err) require.Nil(apiErr) - require.NotNil(org) + require.NotNil(org.Item) - proj, apiErr, err := scopes.NewClient(c2.Client()).Read(c2.Context(), org.Id) + proj, apiErr, err := scopes.NewClient(c2.Client()).Read(c2.Context(), org.Item.Id) require.NoError(err) require.Nil(apiErr) - require.NotNil(proj) + require.NotNil(proj.Item) } diff --git a/internal/servers/controller/testing.go b/internal/servers/controller/testing.go index 07320baf0..8631c52dc 100644 --- a/internal/servers/controller/testing.go +++ b/internal/servers/controller/testing.go @@ -116,7 +116,7 @@ func (tc *TestController) Token() *authtokens.AuthToken { tc.t.Error(fmt.Errorf("api err from logging in: %s", pretty.Sprint(apiErr))) return nil } - return token + return token.Item } func (tc *TestController) addrs(purpose string) []string {