UI unseal screen updates (#11705)

* Styling for empty-state and splash-page

* Update shamir-flow language and trigger onError on non-400 error

* Add license terminated screen to unseal

* Add changelog
This commit is contained in:
Chelsea Shaw 2021-05-26 13:59:11 -05:00 committed by GitHub
parent 7383c6a878
commit 36c8366d5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 86 additions and 29 deletions

3
changelog/11705.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:improvement
ui: Add specific error message if unseal fails due to license
```

View File

@ -3,6 +3,7 @@ import Controller from '@ember/controller';
export default Controller.extend({
wizard: service(),
showLicenseError: false,
actions: {
transitionToCluster(resp) {
@ -19,5 +20,9 @@ export default Controller.extend({
isUnsealed(data) {
return data.sealed === false;
},
handleLicenseError() {
this.set('showLicenseError', true);
},
},
});

View File

@ -8,6 +8,16 @@
box-shadow: 0 -2px 0 -1px $ui-gray-300;
}
.empty-state-transparent {
align-items: center;
color: $grey;
background: transparent;
display: flex;
justify-content: center;
padding: $spacing-xxl 0;
box-shadow: none;
}
.empty-state-content {
max-width: 320px;
}

View File

@ -21,5 +21,5 @@
}
.splash-page-header {
padding: $size-6 $size-5;
padding: $size-6 0;
}

View File

@ -1,26 +1,60 @@
<SplashPage as |Page|>
<Page.header>
<h1 class="title is-3">
Unseal Vault
</h1>
</Page.header>
<Page.content>
<AlertBanner
@type="warning"
@title="{{capitalize model.name}} is {{if model.unsealed 'unsealed' 'sealed'}}"
@message="You can unseal the vault by entering a portion of the master key. Once all portions are entered, the vault will be unsealed."
@class="unseal-warning"
data-test-cluster-status
/>
<ShamirFlow
@action="unseal"
@onUpdate={{action 'setUnsealState'}}
@onShamirSuccess={{action 'transitionToCluster'}}
@buttonText="Unseal"
@thresholdPath="t"
@isComplete={{action 'isUnsealed'}}
@threshold={{model.sealThreshold}}
@progress={{model.sealProgress}}
/>
</Page.content>
</SplashPage>
{{#if showLicenseError}}
<NavHeader as |Nav|>
<Nav.home>
<HomeLink @class="navbar-item splash-page-logo has-text-white">
<LogoEdition />
</HomeLink>
</Nav.home>
<Nav.items>
<div class="navbar-item status-indicator-button" data-status="{{if activeCluster.unsealed "good" "bad"}}">
<StatusMenu @label="Status" @onLinkClick={{action Nav.closeDrawer}} />
</div>
</Nav.items>
</NavHeader>
<div class="section is-flex-v-centered-tablet is-flex-1 is-fullwidth">
<div class="columns is-centered is-gapless is-fullwidth">
<EmptyState
class="empty-state-transparent"
@title="License required"
@subTitle="Vault license has terminated"
@icon="disabled"
@bottomBorder={{true}}
@message="Your Vault license has terminated and Vault is sealed. To unseal, add a current license to your configuration and restart Vault."
>
<p class="align-right"><a href="https://learn.hashicorp.com/tutorials/nomad/hashicorp-enterprise-license" rel="noreferrer noopener">License documentation</a></p>
</EmptyState>
</div>
</div>
{{else}}
<SplashPage as |Page|>
<Page.header>
<h1 class="title is-3">
Unseal Vault
</h1>
</Page.header>
<Page.content>
<div class="box is-borderless is-shadowless is-marginless">
<p class="title is-5">{{capitalize model.name}} is {{if model.unsealed 'unsealed' 'sealed'}}</p>
<p>
Unseal Vault by entering portions of the unseal key. This can be done via multiple mechanisms on multiple computers. Once all portions are entered, the root key will be decrypted and Vault will unseal.
</p>
</div>
<ShamirFlow
@action="unseal"
@onUpdate={{action 'setUnsealState'}}
@onLicenseError={{action 'handleLicenseError'}}
@onShamirSuccess={{action 'transitionToCluster'}}
@buttonText="Unseal"
@thresholdPath="t"
@isComplete={{action 'isUnsealed'}}
@threshold={{model.sealThreshold}}
@progress={{model.sealProgress}}
/>
</Page.content>
<Page.footer>
<div class="box is-borderless is-shadowless">
<p><a target="_blank" rel="noreferrer noopener" href="https://www.vaultproject.io/docs/concepts/seal">Seal/unseal documentation</a></p>
</div>
</Page.footer>
</SplashPage>
{{/if}}

View File

@ -14,7 +14,7 @@ import layout from '../templates/components/empty-state';
* @param title=null{String} - A short label for the empty state
* @param subTitle=null{String} - A sub title that goes underneath the main title
* @param message=null{String} - A description of why a user might be seeing the empty state and possibly instructions for actions they may take.
* @param [icon='']{String} - An optional param to display icon to the right of the title
* @param [icon='']{String} - An optional param to display icon to the left of the title
* @param bottomBorder=false{Boolean} - A bottom border underneath the message. Generally used when you have links under the message
*/

View File

@ -42,6 +42,7 @@ export default Component.extend(DEFAULTS, {
},
onUpdate() {},
onLicenseError() {},
onShamirSuccess() {},
// can be overridden w/an attr
isComplete(data) {
@ -88,6 +89,10 @@ export default Component.extend(DEFAULTS, {
if (e.httpStatus === 400) {
this.set('errors', e.errors);
} else {
// if licensing error, trigger parent method to handle
if (e.httpStatus === 500 && e.errors?.join(' ').includes('licensing is in an invalid state')) {
this.onLicenseError();
}
throw e;
}
},

View File

@ -148,7 +148,7 @@
</div>
<div class="field">
<label for="key" class="is-label">
Master Key Portion
Unseal Key Portion
</label>
<div class="control">
{{input class="input"type="password" name="key" value=key data-test-shamir-input=true}}