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:
parent
7383c6a878
commit
36c8366d5d
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
ui: Add specific error message if unseal fails due to license
|
||||||
|
```
|
|
@ -3,6 +3,7 @@ import Controller from '@ember/controller';
|
||||||
|
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
wizard: service(),
|
wizard: service(),
|
||||||
|
showLicenseError: false,
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
transitionToCluster(resp) {
|
transitionToCluster(resp) {
|
||||||
|
@ -19,5 +20,9 @@ export default Controller.extend({
|
||||||
isUnsealed(data) {
|
isUnsealed(data) {
|
||||||
return data.sealed === false;
|
return data.sealed === false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleLicenseError() {
|
||||||
|
this.set('showLicenseError', true);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,6 +8,16 @@
|
||||||
box-shadow: 0 -2px 0 -1px $ui-gray-300;
|
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 {
|
.empty-state-content {
|
||||||
max-width: 320px;
|
max-width: 320px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,5 +21,5 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.splash-page-header {
|
.splash-page-header {
|
||||||
padding: $size-6 $size-5;
|
padding: $size-6 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,60 @@
|
||||||
<SplashPage as |Page|>
|
{{#if showLicenseError}}
|
||||||
<Page.header>
|
<NavHeader as |Nav|>
|
||||||
<h1 class="title is-3">
|
<Nav.home>
|
||||||
Unseal Vault
|
<HomeLink @class="navbar-item splash-page-logo has-text-white">
|
||||||
</h1>
|
<LogoEdition />
|
||||||
</Page.header>
|
</HomeLink>
|
||||||
<Page.content>
|
</Nav.home>
|
||||||
<AlertBanner
|
<Nav.items>
|
||||||
@type="warning"
|
<div class="navbar-item status-indicator-button" data-status="{{if activeCluster.unsealed "good" "bad"}}">
|
||||||
@title="{{capitalize model.name}} is {{if model.unsealed 'unsealed' 'sealed'}}"
|
<StatusMenu @label="Status" @onLinkClick={{action Nav.closeDrawer}} />
|
||||||
@message="You can unseal the vault by entering a portion of the master key. Once all portions are entered, the vault will be unsealed."
|
</div>
|
||||||
@class="unseal-warning"
|
</Nav.items>
|
||||||
data-test-cluster-status
|
</NavHeader>
|
||||||
/>
|
<div class="section is-flex-v-centered-tablet is-flex-1 is-fullwidth">
|
||||||
<ShamirFlow
|
<div class="columns is-centered is-gapless is-fullwidth">
|
||||||
@action="unseal"
|
<EmptyState
|
||||||
@onUpdate={{action 'setUnsealState'}}
|
class="empty-state-transparent"
|
||||||
@onShamirSuccess={{action 'transitionToCluster'}}
|
@title="License required"
|
||||||
@buttonText="Unseal"
|
@subTitle="Vault license has terminated"
|
||||||
@thresholdPath="t"
|
@icon="disabled"
|
||||||
@isComplete={{action 'isUnsealed'}}
|
@bottomBorder={{true}}
|
||||||
@threshold={{model.sealThreshold}}
|
@message="Your Vault license has terminated and Vault is sealed. To unseal, add a current license to your configuration and restart Vault."
|
||||||
@progress={{model.sealProgress}}
|
>
|
||||||
/>
|
<p class="align-right"><a href="https://learn.hashicorp.com/tutorials/nomad/hashicorp-enterprise-license" rel="noreferrer noopener">License documentation</a></p>
|
||||||
</Page.content>
|
</EmptyState>
|
||||||
</SplashPage>
|
</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}}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import layout from '../templates/components/empty-state';
|
||||||
* @param title=null{String} - A short label for the 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 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 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
|
* @param bottomBorder=false{Boolean} - A bottom border underneath the message. Generally used when you have links under the message
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ export default Component.extend(DEFAULTS, {
|
||||||
},
|
},
|
||||||
|
|
||||||
onUpdate() {},
|
onUpdate() {},
|
||||||
|
onLicenseError() {},
|
||||||
onShamirSuccess() {},
|
onShamirSuccess() {},
|
||||||
// can be overridden w/an attr
|
// can be overridden w/an attr
|
||||||
isComplete(data) {
|
isComplete(data) {
|
||||||
|
@ -88,6 +89,10 @@ export default Component.extend(DEFAULTS, {
|
||||||
if (e.httpStatus === 400) {
|
if (e.httpStatus === 400) {
|
||||||
this.set('errors', e.errors);
|
this.set('errors', e.errors);
|
||||||
} else {
|
} 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;
|
throw e;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -148,7 +148,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="key" class="is-label">
|
<label for="key" class="is-label">
|
||||||
Master Key Portion
|
Unseal Key Portion
|
||||||
</label>
|
</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
{{input class="input"type="password" name="key" value=key data-test-shamir-input=true}}
|
{{input class="input"type="password" name="key" value=key data-test-shamir-input=true}}
|
||||||
|
|
Loading…
Reference in New Issue