1 import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
3 import { I18n } from '@ngx-translate/i18n-polyfill';
4 import * as _ from 'lodash';
6 import { HostService } from '../../../shared/api/host.service';
7 import { OsdService } from '../../../shared/api/osd.service';
8 import { CdTableColumn } from '../../../shared/models/cd-table-column';
15 } from '../../../shared/models/smart';
18 selector: 'cd-smart-list',
19 templateUrl: './smart-list.component.html',
20 styleUrls: ['./smart-list.component.scss']
22 export class SmartListComponent implements OnInit, OnChanges {
26 hostname: string = null;
32 data: { [deviceId: string]: SmartDataResult | SmartErrorResult } = {};
34 smartDataColumns: CdTableColumn[];
38 private osdService: OsdService,
39 private hostService: HostService
42 isSmartError(data: any): data is SmartError {
43 return _.get(data, 'error') !== undefined;
46 isNvmeSmartData(data: any): data is NvmeSmartDataV1 {
47 return _.get(data, 'device.protocol', '').toLowerCase() === 'nvme';
50 isHddSmartData(data: any): data is HddSmartDataV1 {
51 return _.get(data, 'device.protocol', '').toLowerCase() === 'ata';
54 private fetchData(data: any) {
55 const result: { [deviceId: string]: SmartDataResult | SmartErrorResult } = {};
56 _.each(data, (smartData, deviceId) => {
57 if (this.isSmartError(smartData)) {
59 if (smartData.smartctl_error_code === -22) {
60 userMessage = this.i18n(
61 `Smartctl has received an unknown argument (error code {{code}}). \
62 You may be using an incompatible version of smartmontools. Version >= 7.0 of \
63 smartmontools is required to successfully retrieve data.`,
64 { code: smartData.smartctl_error_code }
67 userMessage = this.i18n('An error with error code {{code}} occurred.', {
68 code: smartData.smartctl_error_code
71 const _result: SmartErrorResult = {
72 error: smartData.error,
73 smartctl_error_code: smartData.smartctl_error_code,
74 smartctl_output: smartData.smartctl_output,
75 userMessage: userMessage,
76 device: smartData.dev,
77 identifier: smartData.nvme_vendor
79 result[deviceId] = _result;
83 // Prepare S.M.A.R.T data
84 if (smartData.json_format_version[0] === 1) {
86 if (this.isHddSmartData(smartData)) {
87 result[deviceId] = this.extractHddData(smartData);
88 } else if (this.isNvmeSmartData(smartData)) {
89 result[deviceId] = this.extractNvmeData(smartData);
93 this.incompatible = true;
100 private extractNvmeData(smartData: NvmeSmartDataV1): SmartDataResult {
101 const info = _.omitBy(smartData, (_value, key) =>
102 ['nvme_smart_health_information_log'].includes(key)
107 nvmeData: smartData.nvme_smart_health_information_log
109 device: smartData.device.name,
110 identifier: smartData.serial_number
114 private extractHddData(smartData: HddSmartDataV1): SmartDataResult {
115 const info = _.omitBy(smartData, (_value, key) =>
116 ['ata_smart_attributes', 'ata_smart_selective_self_test_log', 'ata_smart_data'].includes(key)
121 attributes: smartData.ata_smart_attributes,
122 data: smartData.ata_smart_data
124 device: info.device.name,
125 identifier: info.serial_number
129 private updateData() {
132 if (this.osdId !== null) {
133 this.osdService.getSmartData(this.osdId).subscribe(this.fetchData.bind(this), (error) => {
134 error.preventDefault();
136 this.loading = false;
138 } else if (this.hostname !== null) {
139 this.hostService.getSmartData(this.hostname).subscribe(this.fetchData.bind(this), (error) => {
140 error.preventDefault();
142 this.loading = false;
148 this.smartDataColumns = [
149 { prop: 'id', name: this.i18n('ID') },
150 { prop: 'name', name: this.i18n('Name') },
151 { prop: 'raw.value', name: this.i18n('Raw') },
152 { prop: 'thresh', name: this.i18n('Threshold') },
153 { prop: 'value', name: this.i18n('Value') },
154 { prop: 'when_failed', name: this.i18n('When Failed') },
155 { prop: 'worst', name: this.i18n('Worst') }
159 ngOnChanges(changes: SimpleChanges): void {
160 this.data = {}; // Clear previous data
162 this.osdId = changes.osdId.currentValue;
163 } else if (changes.hostname) {
164 this.hostname = changes.hostname.currentValue;