Commit 6baad6aa authored by Boris Vasilenko's avatar Boris Vasilenko
Browse files

NAS-114084: Fix ZFS metadata corruption - Pool state green in dashboard

parent 786d0685
Showing with 67 additions and 136 deletions
+67 -136
export enum VDevStatus {
Online = 'ONLINE',
Removed = 'REMOVED',
Offline = 'OFFLINE',
}
import { DiskPowerLevel } from 'app/enums/disk-power-level.enum';
import { DiskStandby } from 'app/enums/disk-standby.enum';
import { DiskWipeMethod } from 'app/enums/disk-wipe-method.enum';
import { VDevStatus } from 'app/enums/vdev-status.enum';
import { ZfsProperty } from './zfs-property.interface';
// As returned by pool.query under topology[<vdevtype>]
......@@ -8,7 +9,7 @@ export interface VDev {
type: string; // 'DISK'
path: string;
guid: string;
status: string;
status: VDevStatus;
children: this[];
unavail_disk: any;
stats: VDevStats;
......
......@@ -93,25 +93,19 @@
<div class="pool-status tr" >
<div class="td label"><strong>Pool Status:</strong></div>
<div class="td">
<div class="td status-cell">
<span class="capitalize">{{poolState.status}}</span>
<ng-container *ngIf="isErrorStatus(poolState.status); else noerrors">
<span class="error icon">
<mat-icon role="img" fontSet="mdi-set" fontIcon="mdi-close-circle"></mat-icon>
</span>
</ng-container>
<ng-template #noerrors>
<span *ngIf="poolState.status == PoolStatus.Locked"
class="lock-icon-wrapper icon">
<mat-icon>lock</mat-icon>
<ng-container [ngSwitch]="poolState.status">
<span *ngSwitchCase="PoolStatus.Locked" class="lock-icon-wrapper icon"><mat-icon>lock</mat-icon></span>
<span *ngSwitchCase="PoolStatus.Online" class="{{poolHealth.level}} icon">
<mat-icon role="img" fontSet="mdi-set" [fontIcon]="poolHealth.isHealthy ? 'mdi-check-circle' : 'mdi-alert'"></mat-icon>
</span>
<span *ngIf="poolState.status == PoolStatus.Online || poolState.status == PoolStatus.Healthy"
class="{{poolHealth.level}} icon">
<span *ngSwitchCase="PoolStatus.Healthy" class="{{poolHealth.level}} icon">
<mat-icon role="img" fontSet="mdi-set" [fontIcon]="poolHealth.isHealthy ? 'mdi-check-circle' : 'mdi-alert'"></mat-icon>
</span>
</ng-template>
<span *ngSwitchDefault class="error icon"><mat-icon role="img" fontSet="mdi-set" fontIcon="mdi-close-circle"></mat-icon></span>
</ng-container>
</div>
</div>
......@@ -231,11 +225,11 @@
>
<strong>{{vdev.type}}:</strong>&nbsp;&nbsp; {{vdev.status}}
<!-- STATUS ICONS -->
<span *ngIf="vdev.status == 'ONLINE'" class="{{poolHealth.level}} healthy" >
<span *ngIf="vdev.status === VDevStatus.Online" class="{{poolHealth.level}} healthy" >
<mat-icon role="img" fontSet="mdi-set" fontIcon="mdi-check-circle"></mat-icon>
&nbsp;&nbsp;
</span>
<span *ngIf="vdev.status !== 'ONLINE'" class="{{poolHealth.level}} healthy" >
<span *ngIf="vdev.status !== VDevStatus.Online" class="{{poolHealth.level}} healthy" >
<mat-icon role="img" fontSet="mdi-set" fontIcon="mdi-alert"></mat-icon>
&nbsp;&nbsp;
</span>
......@@ -293,10 +287,10 @@
&nbsp;&nbsp; {{disk.status | translate}}
<!-- STATUS ICONS -->
<span *ngIf="disk.status == 'ONLINE'" class="{{poolHealth.level}} healthy" >
<span *ngIf="disk.status === VDevStatus.Online" class="{{poolHealth.level}} healthy" >
<mat-icon role="img" fontSet="mdi-set" fontIcon="mdi-check-circle"></mat-icon>
</span>
<span *ngIf="disk.status != 'ONLINE'" class="{{poolHealth.level}} healthy" >
<span *ngIf="disk.status !== VDevStatus.Online" class="{{poolHealth.level}} healthy" >
<mat-icon role="img" fontSet="mdi-set" fontIcon="mdi-alert"></mat-icon>
</span>
......@@ -318,7 +312,7 @@
:
</strong>
&nbsp;&nbsp; {{path[2].dataSource.status | translate}}
<span *ngIf="path[2].dataSource.status == 'ONLINE'" class="{{poolHealth.level}} healthy" >
<span *ngIf="path[2].dataSource.status === VDevStatus.Online" class="{{poolHealth.level}} healthy" >
<mat-icon role="img" fontSet="mdi-set" fontIcon="mdi-check-circle"></mat-icon>
</span>
<mat-icon class="next-slide" ix-auto ix-auto-type="button" ix-auto-identifier="nextSlide">chevron_right</mat-icon>
......
......@@ -311,12 +311,14 @@ span.capitalize {
font-size: 120%;
}
.disk-errors.mat-icon.healthy {
/*font-size: 18px;
margin-bottom: 2px;*/
.mat-list-item .error,
.mat-list-item .warning,
.mat-list-item .healthy {
font-size: 120%;
margin-left: 5px;
margin-top: -5px;
}
/* NARROW SCREENS */
.xs.widget {
height: calc(100vh - 96px);
......
......@@ -18,6 +18,7 @@ import filesize from 'filesize';
import { styler, tween } from 'popmotion';
import { PoolStatus } from 'app/enums/pool-status.enum';
import { VDevType } from 'app/enums/v-dev-type.enum';
import { VDevStatus } from 'app/enums/vdev-status.enum';
import { DisksDataEvent } from 'app/interfaces/events/disks-data-event.interface';
import { Pool, PoolTopologyCategory } from 'app/interfaces/pool.interface';
import { Disk, VDev } from 'app/interfaces/storage.interface';
......@@ -34,10 +35,13 @@ interface Slide {
interface PoolDiagnosis {
isHealthy: boolean;
warnings: string[];
errors: string[];
selector: string;
level: string;
level: PoolHealthLevel;
}
enum PoolHealthLevel {
Warn = 'warn',
Error = 'error',
Safe = 'safe',
}
@UntilDestroy()
......@@ -47,6 +51,7 @@ interface PoolDiagnosis {
styleUrls: ['./widget-pool.component.scss'],
})
export class WidgetPoolComponent extends WidgetComponent implements OnInit, AfterViewInit, OnDestroy, OnChanges {
readonly VDevStatus = VDevStatus;
@Input() poolState: Pool;
@Input() volumeData: VolumeData;
@ViewChild('carousel', { static: true }) carousel: ElementRef;
......@@ -162,10 +167,7 @@ export class WidgetPoolComponent extends WidgetComponent implements OnInit, Afte
diskSizeLabel: string;
poolHealth: PoolDiagnosis = {
isHealthy: true,
warnings: [],
errors: [],
selector: 'fn-theme-green',
level: 'safe',
level: PoolHealthLevel.Safe,
};
currentDiskDetails: Disk;
......@@ -228,7 +230,7 @@ export class WidgetPoolComponent extends WidgetComponent implements OnInit, Afte
}
});
this.checkVolumeHealth();
this.checkVolumeHealth(this.poolState);
}
// TODO: Helps with template type checking. To be removed when 'strict' checks are enabled.
......@@ -273,7 +275,7 @@ export class WidgetPoolComponent extends WidgetComponent implements OnInit, Afte
if (this.diskSize.charAt(this.diskSize.length - 2) === '.' || this.diskSize.charAt(this.diskSize.length - 2) === ',') {
this.diskSize = this.diskSize.concat('0');
}
this.checkVolumeHealth();
this.checkVolumeHealth(this.poolState);
}
getDiskDetails(key: string, value: string): void {
......@@ -352,57 +354,40 @@ export class WidgetPoolComponent extends WidgetComponent implements OnInit, Afte
this.title = this.currentSlide == '0' ? 'Pool' : this.poolState.name;
}
checkVolumeHealth(): void {
switch (this.poolState.status) {
case PoolStatus.Healthy:
break;
case PoolStatus.Locked:
this.updateVolumeHealth('Pool status is ' + this.poolState.status, false, 'locked');
break;
case PoolStatus.Unknown:
case PoolStatus.Offline:
this.updateVolumeHealth('Pool status is ' + this.poolState.status, false, 'unknown');
break;
case PoolStatus.Degraded:
this.updateVolumeHealth('Pool status is ' + this.poolState.status, false, 'degraded');
break;
case PoolStatus.Faulted:
case PoolStatus.Unavailable:
case PoolStatus.Removed:
this.updateVolumeHealth('Pool status is ' + this.poolState.status, true, 'faulted');
break;
}
private isStatusError(poolState: Pool): boolean {
return [
PoolStatus.Faulted,
PoolStatus.Unavailable,
PoolStatus.Removed,
].includes(poolState.status);
}
updateVolumeHealth(symptom: string, isCritical?: boolean, condition?: string): void {
if (isCritical) {
this.poolHealth.errors.push(symptom);
} else {
this.poolHealth.warnings.push(symptom);
}
if (this.poolHealth.isHealthy) {
this.poolHealth.isHealthy = false;
this.poolHealth.level = this.translate.instant('warn');
private isStatusWarning(poolState: Pool): boolean {
return [
PoolStatus.Locked,
PoolStatus.Unknown,
PoolStatus.Offline,
PoolStatus.Degraded,
].includes(poolState.status);
}
private checkVolumeHealth(poolState: Pool): void {
const isError = this.isStatusError(poolState);
const isWarning = this.isStatusWarning(poolState);
if (isError || isWarning || !poolState.healthy) {
if (this.poolHealth.isHealthy) {
this.poolHealth.isHealthy = false;
this.poolHealth.level = PoolHealthLevel.Warn;
}
}
if (this.poolHealth.errors.length > 0) {
this.poolHealth.level = this.translate.instant('error');
} else if (this.poolHealth.warnings.length > 0) {
this.poolHealth.level = this.translate.instant('warn');
} else {
this.poolHealth.level = this.translate.instant('safe');
if (isError) {
this.poolHealth.level = PoolHealthLevel.Error;
}
if (condition === 'locked') {
this.poolHealth.selector = 'fn-theme-yellow';
} else if (condition === 'unknown') {
this.poolHealth.selector = 'fn-theme-blue';
} else if (condition === 'degraded') {
this.poolHealth.selector = 'fn-theme-orange';
} else if (condition === 'faulted') {
this.poolHealth.selector = 'fn-theme-red';
} else {
this.poolHealth.selector = 'fn-theme-green';
if (isWarning) {
this.poolHealth.level = PoolHealthLevel.Warn;
}
}
......@@ -410,15 +395,4 @@ export class WidgetPoolComponent extends WidgetComponent implements OnInit, Afte
const spl = value.split('%');
return parseInt(spl[0]);
}
isErrorStatus(status: string): boolean {
switch (status) {
case PoolStatus.Online:
case PoolStatus.Healthy:
case PoolStatus.Locked:
return false;
default:
return true;
}
}
}
......@@ -4063,7 +4063,6 @@
"details": "",
"email": "",
"empty": "",
"error": "",
"everyone@": "",
"expires in": "",
"group": "",
......@@ -4097,7 +4096,6 @@
"reset": "",
"rpc.lockd(8) bind port": "",
"rpc.statd(8) bind port": "",
"safe": "",
"seconds": "",
"seconds unless SAVE CHANGES is chosen to make them permanent.": "",
"software, which is provided as-is with no warranty.": "",
......@@ -4108,7 +4106,6 @@
"users": "",
"vdev": "",
"vdev is highly discouraged and will result in data loss if it fails": "",
"warn": "",
"was successfully attached.": "",
"zle (runs of zeros)": "",
"zstd (default level, 3)": "",
......
......@@ -4063,7 +4063,6 @@
"details": "",
"email": "",
"empty": "",
"error": "",
"everyone@": "",
"expires in": "",
"group": "",
......@@ -4097,7 +4096,6 @@
"reset": "",
"rpc.lockd(8) bind port": "",
"rpc.statd(8) bind port": "",
"safe": "",
"seconds": "",
"seconds unless SAVE CHANGES is chosen to make them permanent.": "",
"software, which is provided as-is with no warranty.": "",
......@@ -4108,7 +4106,6 @@
"users": "",
"vdev": "",
"vdev is highly discouraged and will result in data loss if it fails": "",
"warn": "",
"was successfully attached.": "",
"zle (runs of zeros)": "",
"zstd (default level, 3)": "",
......
......@@ -4063,7 +4063,6 @@
"details": "",
"email": "",
"empty": "",
"error": "",
"everyone@": "",
"expires in": "",
"group": "",
......@@ -4097,7 +4096,6 @@
"reset": "",
"rpc.lockd(8) bind port": "",
"rpc.statd(8) bind port": "",
"safe": "",
"seconds": "",
"seconds unless SAVE CHANGES is chosen to make them permanent.": "",
"software, which is provided as-is with no warranty.": "",
......@@ -4108,7 +4106,6 @@
"users": "",
"vdev": "",
"vdev is highly discouraged and will result in data loss if it fails": "",
"warn": "",
"was successfully attached.": "",
"zle (runs of zeros)": "",
"zstd (default level, 3)": "",
......
......@@ -4063,7 +4063,6 @@
"details": "",
"email": "",
"empty": "",
"error": "",
"everyone@": "",
"expires in": "",
"group": "",
......@@ -4097,7 +4096,6 @@
"reset": "",
"rpc.lockd(8) bind port": "",
"rpc.statd(8) bind port": "",
"safe": "",
"seconds": "",
"seconds unless SAVE CHANGES is chosen to make them permanent.": "",
"software, which is provided as-is with no warranty.": "",
......@@ -4108,7 +4106,6 @@
"users": "",
"vdev": "",
"vdev is highly discouraged and will result in data loss if it fails": "",
"warn": "",
"was successfully attached.": "",
"zle (runs of zeros)": "",
"zstd (default level, 3)": "",
......
......@@ -4063,7 +4063,6 @@
"details": "",
"email": "",
"empty": "",
"error": "",
"everyone@": "",
"expires in": "",
"group": "",
......@@ -4097,7 +4096,6 @@
"reset": "",
"rpc.lockd(8) bind port": "",
"rpc.statd(8) bind port": "",
"safe": "",
"seconds": "",
"seconds unless SAVE CHANGES is chosen to make them permanent.": "",
"software, which is provided as-is with no warranty.": "",
......@@ -4108,7 +4106,6 @@
"users": "",
"vdev": "",
"vdev is highly discouraged and will result in data loss if it fails": "",
"warn": "",
"was successfully attached.": "",
"zle (runs of zeros)": "",
"zstd (default level, 3)": "",
......
......@@ -4063,7 +4063,6 @@
"details": "",
"email": "",
"empty": "",
"error": "",
"everyone@": "",
"expires in": "",
"group": "",
......@@ -4097,7 +4096,6 @@
"reset": "",
"rpc.lockd(8) bind port": "",
"rpc.statd(8) bind port": "",
"safe": "",
"seconds": "",
"seconds unless SAVE CHANGES is chosen to make them permanent.": "",
"software, which is provided as-is with no warranty.": "",
......@@ -4108,7 +4106,6 @@
"users": "",
"vdev": "",
"vdev is highly discouraged and will result in data loss if it fails": "",
"warn": "",
"was successfully attached.": "",
"zle (runs of zeros)": "",
"zstd (default level, 3)": "",
......
......@@ -4063,7 +4063,6 @@
"details": "",
"email": "",
"empty": "",
"error": "",
"everyone@": "",
"expires in": "",
"group": "",
......@@ -4097,7 +4096,6 @@
"reset": "",
"rpc.lockd(8) bind port": "",
"rpc.statd(8) bind port": "",
"safe": "",
"seconds": "",
"seconds unless SAVE CHANGES is chosen to make them permanent.": "",
"software, which is provided as-is with no warranty.": "",
......@@ -4108,7 +4106,6 @@
"users": "",
"vdev": "",
"vdev is highly discouraged and will result in data loss if it fails": "",
"warn": "",
"was successfully attached.": "",
"zle (runs of zeros)": "",
"zstd (default level, 3)": "",
......
......@@ -4063,7 +4063,6 @@
"details": "",
"email": "",
"empty": "",
"error": "",
"everyone@": "",
"expires in": "",
"group": "",
......@@ -4097,7 +4096,6 @@
"reset": "",
"rpc.lockd(8) bind port": "",
"rpc.statd(8) bind port": "",
"safe": "",
"seconds": "",
"seconds unless SAVE CHANGES is chosen to make them permanent.": "",
"software, which is provided as-is with no warranty.": "",
......@@ -4108,7 +4106,6 @@
"users": "",
"vdev": "",
"vdev is highly discouraged and will result in data loss if it fails": "",
"warn": "",
"was successfully attached.": "",
"zle (runs of zeros)": "",
"zstd (default level, 3)": "",
......
......@@ -4063,7 +4063,6 @@
"details": "",
"email": "",
"empty": "",
"error": "",
"everyone@": "",
"expires in": "",
"group": "",
......@@ -4097,7 +4096,6 @@
"reset": "",
"rpc.lockd(8) bind port": "",
"rpc.statd(8) bind port": "",
"safe": "",
"seconds": "",
"seconds unless SAVE CHANGES is chosen to make them permanent.": "",
"software, which is provided as-is with no warranty.": "",
......@@ -4108,7 +4106,6 @@
"users": "",
"vdev": "",
"vdev is highly discouraged and will result in data loss if it fails": "",
"warn": "",
"was successfully attached.": "",
"zle (runs of zeros)": "",
"zstd (default level, 3)": "",
......
......@@ -4063,7 +4063,6 @@
"details": "",
"email": "",
"empty": "",
"error": "",
"everyone@": "",
"expires in": "",
"group": "",
......@@ -4097,7 +4096,6 @@
"reset": "",
"rpc.lockd(8) bind port": "",
"rpc.statd(8) bind port": "",
"safe": "",
"seconds": "",
"seconds unless SAVE CHANGES is chosen to make them permanent.": "",
"software, which is provided as-is with no warranty.": "",
......@@ -4108,7 +4106,6 @@
"users": "",
"vdev": "",
"vdev is highly discouraged and will result in data loss if it fails": "",
"warn": "",
"was successfully attached.": "",
"zle (runs of zeros)": "",
"zstd (default level, 3)": "",
......
......@@ -3496,7 +3496,6 @@
"reset": "",
"rpc.lockd(8) bind port": "",
"rpc.statd(8) bind port": "",
"safe": "",
"seconds": "",
"seconds unless SAVE CHANGES is chosen to make them permanent.": "",
"software, which is provided as-is with no warranty.": "",
......@@ -3507,7 +3506,6 @@
"users": "",
"vdev": "",
"vdev is highly discouraged and will result in data loss if it fails": "",
"warn": "",
"zle (runs of zeros)": "",
"zstd (default level, 3)": "",
"zstd-5 (slow)": "",
......@@ -4169,7 +4167,6 @@
"close": "zavřít",
"days": "dní",
"empty": "prázdný",
"error": "chyba",
"expires in": "expiruje během",
"group": "skupina",
"overview": "přehled",
......
......@@ -4063,7 +4063,6 @@
"details": "",
"email": "",
"empty": "",
"error": "",
"everyone@": "",
"expires in": "",
"group": "",
......@@ -4097,7 +4096,6 @@
"reset": "",
"rpc.lockd(8) bind port": "",
"rpc.statd(8) bind port": "",
"safe": "",
"seconds": "",
"seconds unless SAVE CHANGES is chosen to make them permanent.": "",
"software, which is provided as-is with no warranty.": "",
......@@ -4108,7 +4106,6 @@
"users": "",
"vdev": "",
"vdev is highly discouraged and will result in data loss if it fails": "",
"warn": "",
"was successfully attached.": "",
"zle (runs of zeros)": "",
"zstd (default level, 3)": "",
......
......@@ -4063,7 +4063,6 @@
"details": "",
"email": "",
"empty": "",
"error": "",
"everyone@": "",
"expires in": "",
"group": "",
......@@ -4097,7 +4096,6 @@
"reset": "",
"rpc.lockd(8) bind port": "",
"rpc.statd(8) bind port": "",
"safe": "",
"seconds": "",
"seconds unless SAVE CHANGES is chosen to make them permanent.": "",
"software, which is provided as-is with no warranty.": "",
......@@ -4108,7 +4106,6 @@
"users": "",
"vdev": "",
"vdev is highly discouraged and will result in data loss if it fails": "",
"warn": "",
"was successfully attached.": "",
"zle (runs of zeros)": "",
"zstd (default level, 3)": "",
......
......@@ -4160,7 +4160,6 @@
"details": "Details",
"email": "Email",
"empty": "leer",
"error": "Fehler",
"group": "Gruppe",
"iXsystems for more information.": "iXsystems für weitere Informationen.",
"is Free and": "ist frei und",
......@@ -4169,10 +4168,8 @@
"overview": "Überblick",
"password": "Passwort",
"reset": "zurücksetzen",
"safe": "sicher",
"to set up configuration first.": ", um die Konfiguration zuerst einzurichten.",
"total available": "insgesamt verfügbar",
"users": "Benutzer",
"warn": "Warnung",
"was successfully attached.": "wurde erfolgreich hinzugefügt."
}
\ No newline at end of file
......@@ -4063,7 +4063,6 @@
"details": "",
"email": "",
"empty": "",
"error": "",
"everyone@": "",
"expires in": "",
"group": "",
......@@ -4097,7 +4096,6 @@
"reset": "",
"rpc.lockd(8) bind port": "",
"rpc.statd(8) bind port": "",
"safe": "",
"seconds": "",
"seconds unless SAVE CHANGES is chosen to make them permanent.": "",
"software, which is provided as-is with no warranty.": "",
......@@ -4108,7 +4106,6 @@
"users": "",
"vdev": "",
"vdev is highly discouraged and will result in data loss if it fails": "",
"warn": "",
"was successfully attached.": "",
"zle (runs of zeros)": "",
"zstd (default level, 3)": "",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment