Skip to content

Commit

Permalink
UI: Show error when seal fails (#23921)
Browse files Browse the repository at this point in the history
* Show error when seal fails

* cleanup, add headers

* add changelog

* Fix test
  • Loading branch information
hashishaw authored Nov 8, 2023
1 parent 1a6c20b commit ba5f856
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 20 deletions.
3 changes: 3 additions & 0 deletions changelog/23921.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
ui: show error from API when seal fails
```
34 changes: 34 additions & 0 deletions ui/app/components/seal-action.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
~}}

<div class="box is-sideless is-fullwidth is-marginless">
{{#if this.error}}
<Hds::Alert @type="inline" @color="critical" class="has-bottom-margin-m" data-test-seal-error as |A|>
<A.Title>Error</A.Title>
<A.Description>
{{this.error}}
</A.Description>
</Hds::Alert>
{{/if}}
<p>
Sealing a vault tells the Vault server to stop responding to any access operations until it is unsealed again. A sealed
vault throws away its root key to unlock the data, so it physically is blocked from responding to operations again until
the Vault is unsealed again with the "unseal" command or via the API.
</p>
</div>

<div class="field is-grouped box is-fullwidth is-bottomless">
<ConfirmAction
@buttonClasses="button is-primary"
@confirmTitle="Seal this cluster?"
@confirmMessage="You will not be able to read or write any data until the cluster is unsealed again."
@confirmButtonText="Seal"
@horizontalPosition="auto-left"
@onConfirmAction={{this.handleSeal}}
data-test-seal
>
Seal
</ConfirmAction>
</div>
22 changes: 22 additions & 0 deletions ui/app/components/seal-action.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import { action } from '@ember/object';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import errorMessage from 'vault/utils/error-message';

export default class SealActionComponent extends Component {
@tracked error;

@action
async handleSeal() {
try {
await this.args.onSeal();
} catch (e) {
this.error = errorMessage(e, 'Seal attempt failed. Check Vault logs for details.');
}
}
}
21 changes: 1 addition & 20 deletions ui/app/templates/vault/cluster/settings/seal.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,7 @@
</PageHeader>

{{#if this.model.seal.canUpdate}}
<div class="box is-sideless is-fullwidth is-marginless">
<p>
Sealing a vault tells the Vault server to stop responding to any access operations until it is unsealed again. A sealed
vault throws away its root key to unlock the data, so it physically is blocked from responding to operations again
until the Vault is unsealed again with the "unseal" command or via the API.
</p>
</div>
<div class="field is-grouped box is-fullwidth is-bottomless">
<ConfirmAction
@buttonClasses="button is-primary"
@confirmTitle="Seal this cluster?"
@confirmMessage="You will not be able to read or write any data until the cluster is unsealed again."
@confirmButtonText="Seal"
@horizontalPosition="auto-left"
@onConfirmAction={{action "seal"}}
data-test-seal="true"
>
Seal
</ConfirmAction>
</div>
<SealAction @onSeal={{action "seal"}} />
{{else}}
<EmptyState @title="This token does not have sufficient capabilities to seal this vault" />
{{/if}}
45 changes: 45 additions & 0 deletions ui/tests/integration/components/seal-action-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import { module, test } from 'qunit';
import { setupRenderingTest } from 'vault/tests/helpers';
import { click, render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import sinon from 'sinon';

const SEAL_WHEN_STANDBY_MSG = 'vault cannot seal when in standby mode; please restart instead';

module('Integration | Component | seal-action', function (hooks) {
setupRenderingTest(hooks);

hooks.beforeEach(function () {
this.sealSuccess = sinon.spy(() => new Promise((resolve) => resolve({})));
this.sealError = sinon.stub().throws({ message: SEAL_WHEN_STANDBY_MSG });
});

test('it handles success', async function (assert) {
this.set('handleSeal', this.sealSuccess);
await render(hbs`<SealAction @onSeal={{action this.handleSeal}} />`);

// attempt seal
await click('[data-test-seal] button');
await click('[data-test-confirm-button]');

assert.ok(this.sealSuccess.calledOnce, 'called onSeal action');
assert.dom('[data-test-seal-error]').doesNotExist('Does not show error when successful');
});

test('it handles error', async function (assert) {
this.set('handleSeal', this.sealError);
await render(hbs`<SealAction @onSeal={{action this.handleSeal}} />`);

// attempt seal
await click('[data-test-seal] button');
await click('[data-test-confirm-button]');

assert.ok(this.sealError.calledOnce, 'called onSeal action');
assert.dom('[data-test-seal-error]').includesText(SEAL_WHEN_STANDBY_MSG, 'Shows error returned from API');
});
});

0 comments on commit ba5f856

Please sign in to comment.