Rabbitmq: surface errors from responses (#8619)
* surface errs from responses * add test * Update builtin/logical/rabbitmq/path_role_create.go Co-Authored-By: Vishal Nayak <vishalnayak@users.noreply.github.com> * improve error message Co-authored-by: Vishal Nayak <vishalnayak@users.noreply.github.com>
This commit is contained in:
parent
846d82e95e
commit
ae28ebb94a
|
@ -97,6 +97,39 @@ func TestBackend_basic(t *testing.T) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBackend_returnsErrs(t *testing.T) {
|
||||||
|
if os.Getenv(logicaltest.TestEnvVar) == "" {
|
||||||
|
t.Skip(fmt.Sprintf("Acceptance tests skipped unless env '%s' set", logicaltest.TestEnvVar))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b, _ := Factory(context.Background(), logical.TestBackendConfig())
|
||||||
|
|
||||||
|
cleanup, uri, _ := prepareRabbitMQTestContainer(t)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
logicaltest.Test(t, logicaltest.TestCase{
|
||||||
|
PreCheck: testAccPreCheckFunc(t, uri),
|
||||||
|
LogicalBackend: b,
|
||||||
|
Steps: []logicaltest.TestStep{
|
||||||
|
testAccStepConfig(t, uri),
|
||||||
|
{
|
||||||
|
Operation: logical.CreateOperation,
|
||||||
|
Path: "roles/web",
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"tags": testTags,
|
||||||
|
"vhosts": `{"invalid":{"write": ".*", "read": ".*"}}`,
|
||||||
|
"vhost_topics": testVHostTopics,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Operation: logical.ReadOperation,
|
||||||
|
Path: "creds/web",
|
||||||
|
ErrorOk: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestBackend_roleCrud(t *testing.T) {
|
func TestBackend_roleCrud(t *testing.T) {
|
||||||
if os.Getenv(logicaltest.TestEnvVar) == "" {
|
if os.Getenv(logicaltest.TestEnvVar) == "" {
|
||||||
t.Skip(fmt.Sprintf("Acceptance tests skipped unless env '%s' set", logicaltest.TestEnvVar))
|
t.Skip(fmt.Sprintf("Acceptance tests skipped unless env '%s' set", logicaltest.TestEnvVar))
|
||||||
|
|
|
@ -3,10 +3,9 @@ package rabbitmq
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
"github.com/hashicorp/errwrap"
|
"github.com/hashicorp/go-uuid"
|
||||||
multierror "github.com/hashicorp/go-multierror"
|
|
||||||
uuid "github.com/hashicorp/go-uuid"
|
|
||||||
"github.com/hashicorp/vault/sdk/framework"
|
"github.com/hashicorp/vault/sdk/framework"
|
||||||
"github.com/hashicorp/vault/sdk/logical"
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
rabbithole "github.com/michaelklishin/rabbit-hole"
|
rabbithole "github.com/michaelklishin/rabbit-hole"
|
||||||
|
@ -69,27 +68,63 @@ func (b *backend) pathCredsRead(ctx context.Context, req *logical.Request, d *fr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the generated credentials in the backend, with the RabbitMQ server
|
// Register the generated credentials in the backend, with the RabbitMQ server
|
||||||
if _, err = client.PutUser(username, rabbithole.UserSettings{
|
resp, err := client.PutUser(username, rabbithole.UserSettings{
|
||||||
Password: password,
|
Password: password,
|
||||||
Tags: role.Tags,
|
Tags: role.Tags,
|
||||||
}); err != nil {
|
})
|
||||||
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create a new user with the generated credentials")
|
return nil, fmt.Errorf("failed to create a new user with the generated credentials")
|
||||||
}
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := resp.Body.Close(); err != nil {
|
||||||
|
b.Logger().Error(fmt.Sprintf("unable to close response body: %s", err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if !isIn200s(resp.StatusCode) {
|
||||||
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
return nil, fmt.Errorf("error creating user %s - %d: %s", username, resp.StatusCode, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
success := false
|
||||||
|
defer func() {
|
||||||
|
if success {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Delete the user because it's in an unknown state.
|
||||||
|
resp, err := client.DeleteUser(username)
|
||||||
|
if err != nil {
|
||||||
|
b.Logger().Error(fmt.Sprintf("deleting %s due to permissions being in an unknown state, but failed: %s", username, err))
|
||||||
|
}
|
||||||
|
if !isIn200s(resp.StatusCode) {
|
||||||
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
b.Logger().Error(fmt.Sprintf("deleting %s due to permissions being in an unknown state, but error deleting: %d: %s", username, resp.StatusCode, body))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// If the role had vhost permissions specified, assign those permissions
|
// If the role had vhost permissions specified, assign those permissions
|
||||||
// to the created username for respective vhosts.
|
// to the created username for respective vhosts.
|
||||||
for vhost, permission := range role.VHosts {
|
for vhost, permission := range role.VHosts {
|
||||||
if _, err := client.UpdatePermissionsIn(vhost, username, rabbithole.Permissions{
|
if err := func() error {
|
||||||
|
resp, err := client.UpdatePermissionsIn(vhost, username, rabbithole.Permissions{
|
||||||
Configure: permission.Configure,
|
Configure: permission.Configure,
|
||||||
Write: permission.Write,
|
Write: permission.Write,
|
||||||
Read: permission.Read,
|
Read: permission.Read,
|
||||||
}); err != nil {
|
})
|
||||||
outerErr := errwrap.Wrapf(fmt.Sprintf("failed to update permissions to the %q user: {{err}}", username), err)
|
if err != nil {
|
||||||
// Delete the user because it's in an unknown state
|
return err
|
||||||
if _, rmErr := client.DeleteUser(username); rmErr != nil {
|
|
||||||
return nil, multierror.Append(errwrap.Wrapf("failed to delete user: {{err}}", rmErr), outerErr)
|
|
||||||
}
|
}
|
||||||
return nil, outerErr
|
defer func() {
|
||||||
|
if err := resp.Body.Close(); err != nil {
|
||||||
|
b.Logger().Error(fmt.Sprintf("unable to close response body: %s", err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if !isIn200s(resp.StatusCode) {
|
||||||
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
return fmt.Errorf("error updating vhost permissions for %s - %d: %s", vhost, resp.StatusCode, body)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}(); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,23 +132,34 @@ func (b *backend) pathCredsRead(ctx context.Context, req *logical.Request, d *fr
|
||||||
// to the created username for respective vhosts and exchange.
|
// to the created username for respective vhosts and exchange.
|
||||||
for vhost, permissions := range role.VHostTopics {
|
for vhost, permissions := range role.VHostTopics {
|
||||||
for exchange, permission := range permissions {
|
for exchange, permission := range permissions {
|
||||||
if _, err := client.UpdateTopicPermissionsIn(vhost, username, rabbithole.TopicPermissions{
|
if err := func() error {
|
||||||
|
resp, err := client.UpdateTopicPermissionsIn(vhost, username, rabbithole.TopicPermissions{
|
||||||
Exchange: exchange,
|
Exchange: exchange,
|
||||||
Write: permission.Write,
|
Write: permission.Write,
|
||||||
Read: permission.Read,
|
Read: permission.Read,
|
||||||
}); err != nil {
|
})
|
||||||
outerErr := errwrap.Wrapf(fmt.Sprintf("failed to update topic permissions to the %q user: {{err}}", username), err)
|
if err != nil {
|
||||||
// Delete the user because it's in an unknown state
|
return err
|
||||||
if _, rmErr := client.DeleteUser(username); rmErr != nil {
|
|
||||||
return nil, multierror.Append(errwrap.Wrapf("failed to delete user: {{err}}", rmErr), outerErr)
|
|
||||||
}
|
}
|
||||||
return nil, outerErr
|
defer func() {
|
||||||
|
if err := resp.Body.Close(); err != nil {
|
||||||
|
b.Logger().Error(fmt.Sprintf("unable to close response body: %s", err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if !isIn200s(resp.StatusCode) {
|
||||||
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
return fmt.Errorf("error updating vhost permissions for %s - %d: %s", vhost, resp.StatusCode, body)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}(); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
success = true
|
||||||
|
|
||||||
// Return the secret
|
// Return the secret
|
||||||
resp := b.Secret(SecretCredsType).Response(map[string]interface{}{
|
response := b.Secret(SecretCredsType).Response(map[string]interface{}{
|
||||||
"username": username,
|
"username": username,
|
||||||
"password": password,
|
"password": password,
|
||||||
}, map[string]interface{}{
|
}, map[string]interface{}{
|
||||||
|
@ -127,11 +173,15 @@ func (b *backend) pathCredsRead(ctx context.Context, req *logical.Request, d *fr
|
||||||
}
|
}
|
||||||
|
|
||||||
if lease != nil {
|
if lease != nil {
|
||||||
resp.Secret.TTL = lease.TTL
|
response.Secret.TTL = lease.TTL
|
||||||
resp.Secret.MaxTTL = lease.MaxTTL
|
response.Secret.MaxTTL = lease.MaxTTL
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp, nil
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isIn200s(respStatus int) bool {
|
||||||
|
return respStatus >= 200 && respStatus < 300
|
||||||
}
|
}
|
||||||
|
|
||||||
const pathRoleCreateReadHelpSyn = `
|
const pathRoleCreateReadHelpSyn = `
|
||||||
|
|
Loading…
Reference in a new issue