MgrModulesModule,
TypeaheadModule.forRoot(),
TimepickerModule.forRoot(),
+ BsDatepickerModule.forRoot(),
NgBootstrapFormValidationModule,
CephSharedModule
],
CephModule,
ReactiveFormsModule,
RouterTestingModule,
- CoreModule
+ CoreModule,
+ RouterTestingModule
],
declarations: [],
providers: [
import { SharedModule } from '../../shared/shared.module';
import { DeviceListComponent } from './device-list/device-list.component';
import { SmartListComponent } from './smart-list/smart-list.component';
-
@NgModule({
imports: [CommonModule, DataTableModule, SharedModule, TabsModule],
exports: [DeviceListComponent, SmartListComponent],
--- /dev/null
+{
+ "WDC_WD1003FBYX-01Y7B1_WD-WCAW11111111": {
+ "ata_sct_capabilities": {
+ "data_table_supported": true,
+ "error_recovery_control_supported": true,
+ "feature_control_supported": true,
+ "value": 12351
+ },
+ "ata_smart_attributes": {
+ "revision": 16,
+ "table": [
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": true,
+ "event_count": false,
+ "performance": true,
+ "prefailure": true,
+ "string": "POSR-K ",
+ "updated_online": true,
+ "value": 47
+ },
+ "id": 1,
+ "name": "Raw_Read_Error_Rate",
+ "raw": {
+ "string": "1",
+ "value": 1
+ },
+ "thresh": 51,
+ "value": 200,
+ "when_failed": "",
+ "worst": 200
+ },
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": false,
+ "event_count": false,
+ "performance": true,
+ "prefailure": true,
+ "string": "POS--K ",
+ "updated_online": true,
+ "value": 39
+ },
+ "id": 3,
+ "name": "Spin_Up_Time",
+ "raw": {
+ "string": "4250",
+ "value": 4250
+ },
+ "thresh": 21,
+ "value": 175,
+ "when_failed": "",
+ "worst": 172
+ },
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": false,
+ "event_count": true,
+ "performance": false,
+ "prefailure": false,
+ "string": "-O--CK ",
+ "updated_online": true,
+ "value": 50
+ },
+ "id": 4,
+ "name": "Start_Stop_Count",
+ "raw": {
+ "string": "1657",
+ "value": 1657
+ },
+ "thresh": 0,
+ "value": 99,
+ "when_failed": "",
+ "worst": 99
+ },
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": false,
+ "event_count": true,
+ "performance": false,
+ "prefailure": true,
+ "string": "PO--CK ",
+ "updated_online": true,
+ "value": 51
+ },
+ "id": 5,
+ "name": "Reallocated_Sector_Ct",
+ "raw": {
+ "string": "0",
+ "value": 0
+ },
+ "thresh": 140,
+ "value": 200,
+ "when_failed": "",
+ "worst": 200
+ },
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": true,
+ "event_count": false,
+ "performance": true,
+ "prefailure": false,
+ "string": "-OSR-K ",
+ "updated_online": true,
+ "value": 46
+ },
+ "id": 7,
+ "name": "Seek_Error_Rate",
+ "raw": {
+ "string": "0",
+ "value": 0
+ },
+ "thresh": 0,
+ "value": 200,
+ "when_failed": "",
+ "worst": 200
+ },
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": false,
+ "event_count": true,
+ "performance": false,
+ "prefailure": false,
+ "string": "-O--CK ",
+ "updated_online": true,
+ "value": 50
+ },
+ "id": 9,
+ "name": "Power_On_Hours",
+ "raw": {
+ "string": "15807",
+ "value": 15807
+ },
+ "thresh": 0,
+ "value": 79,
+ "when_failed": "",
+ "worst": 79
+ },
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": false,
+ "event_count": true,
+ "performance": false,
+ "prefailure": false,
+ "string": "-O--CK ",
+ "updated_online": true,
+ "value": 50
+ },
+ "id": 10,
+ "name": "Spin_Retry_Count",
+ "raw": {
+ "string": "0",
+ "value": 0
+ },
+ "thresh": 0,
+ "value": 100,
+ "when_failed": "",
+ "worst": 100
+ },
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": false,
+ "event_count": true,
+ "performance": false,
+ "prefailure": false,
+ "string": "-O--CK ",
+ "updated_online": true,
+ "value": 50
+ },
+ "id": 11,
+ "name": "Calibration_Retry_Count",
+ "raw": {
+ "string": "0",
+ "value": 0
+ },
+ "thresh": 0,
+ "value": 100,
+ "when_failed": "",
+ "worst": 100
+ },
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": false,
+ "event_count": true,
+ "performance": false,
+ "prefailure": false,
+ "string": "-O--CK ",
+ "updated_online": true,
+ "value": 50
+ },
+ "id": 12,
+ "name": "Power_Cycle_Count",
+ "raw": {
+ "string": "1370",
+ "value": 1370
+ },
+ "thresh": 0,
+ "value": 99,
+ "when_failed": "",
+ "worst": 99
+ },
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": false,
+ "event_count": true,
+ "performance": false,
+ "prefailure": false,
+ "string": "-O--CK ",
+ "updated_online": true,
+ "value": 50
+ },
+ "id": 192,
+ "name": "Power-Off_Retract_Count",
+ "raw": {
+ "string": "111",
+ "value": 111
+ },
+ "thresh": 0,
+ "value": 200,
+ "when_failed": "",
+ "worst": 200
+ },
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": false,
+ "event_count": true,
+ "performance": false,
+ "prefailure": false,
+ "string": "-O--CK ",
+ "updated_online": true,
+ "value": 50
+ },
+ "id": 193,
+ "name": "Load_Cycle_Count",
+ "raw": {
+ "string": "1545",
+ "value": 1545
+ },
+ "thresh": 0,
+ "value": 200,
+ "when_failed": "",
+ "worst": 200
+ },
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": false,
+ "event_count": false,
+ "performance": false,
+ "prefailure": false,
+ "string": "-O---K ",
+ "updated_online": true,
+ "value": 34
+ },
+ "id": 194,
+ "name": "Temperature_Celsius",
+ "raw": {
+ "string": "47",
+ "value": 47
+ },
+ "thresh": 0,
+ "value": 100,
+ "when_failed": "",
+ "worst": 89
+ },
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": false,
+ "event_count": true,
+ "performance": false,
+ "prefailure": false,
+ "string": "-O--CK ",
+ "updated_online": true,
+ "value": 50
+ },
+ "id": 196,
+ "name": "Reallocated_Event_Count",
+ "raw": {
+ "string": "0",
+ "value": 0
+ },
+ "thresh": 0,
+ "value": 200,
+ "when_failed": "",
+ "worst": 200
+ },
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": false,
+ "event_count": true,
+ "performance": false,
+ "prefailure": false,
+ "string": "-O--CK ",
+ "updated_online": true,
+ "value": 50
+ },
+ "id": 197,
+ "name": "Current_Pending_Sector",
+ "raw": {
+ "string": "0",
+ "value": 0
+ },
+ "thresh": 0,
+ "value": 200,
+ "when_failed": "",
+ "worst": 200
+ },
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": false,
+ "event_count": true,
+ "performance": false,
+ "prefailure": false,
+ "string": "----CK ",
+ "updated_online": false,
+ "value": 48
+ },
+ "id": 198,
+ "name": "Offline_Uncorrectable",
+ "raw": {
+ "string": "0",
+ "value": 0
+ },
+ "thresh": 0,
+ "value": 200,
+ "when_failed": "",
+ "worst": 200
+ },
+ {
+ "flags": {
+ "auto_keep": true,
+ "error_rate": false,
+ "event_count": true,
+ "performance": false,
+ "prefailure": false,
+ "string": "-O--CK ",
+ "updated_online": true,
+ "value": 50
+ },
+ "id": 199,
+ "name": "UDMA_CRC_Error_Count",
+ "raw": {
+ "string": "0",
+ "value": 0
+ },
+ "thresh": 0,
+ "value": 200,
+ "when_failed": "",
+ "worst": 200
+ },
+ {
+ "flags": {
+ "auto_keep": false,
+ "error_rate": true,
+ "event_count": false,
+ "performance": false,
+ "prefailure": false,
+ "string": "---R-- ",
+ "updated_online": false,
+ "value": 8
+ },
+ "id": 200,
+ "name": "Multi_Zone_Error_Rate",
+ "raw": {
+ "string": "0",
+ "value": 0
+ },
+ "thresh": 0,
+ "value": 200,
+ "when_failed": "",
+ "worst": 200
+ }
+ ]
+ },
+ "ata_smart_data": {
+ "capabilities": {
+ "attribute_autosave_enabled": true,
+ "conveyance_self_test_supported": true,
+ "error_logging_supported": true,
+ "exec_offline_immediate_supported": true,
+ "gp_logging_supported": true,
+ "offline_is_aborted_upon_new_cmd": false,
+ "offline_surface_scan_supported": true,
+ "selective_self_test_supported": true,
+ "self_tests_supported": true,
+ "values": [
+ 123,
+ 3
+ ]
+ },
+ "offline_data_collection": {
+ "completion_seconds": 16500,
+ "status": {
+ "string": "was suspended by an interrupting command from host",
+ "value": 132
+ }
+ },
+ "self_test": {
+ "polling_minutes": {
+ "conveyance": 5,
+ "extended": 162,
+ "short": 2
+ },
+ "status": {
+ "passed": true,
+ "string": "completed without error",
+ "value": 0
+ }
+ }
+ },
+ "ata_smart_error_log": {
+ "summary": {
+ "count": 0,
+ "revision": 1
+ }
+ },
+ "ata_smart_selective_self_test_log": {
+ "flags": {
+ "remainder_scan_enabled": false,
+ "value": 0
+ },
+ "power_up_scan_resume_minutes": 0,
+ "revision": 1,
+ "table": [
+ {
+ "lba_max": 0,
+ "lba_min": 0,
+ "status": {
+ "string": "Not_testing",
+ "value": 0
+ }
+ },
+ {
+ "lba_max": 0,
+ "lba_min": 0,
+ "status": {
+ "string": "Not_testing",
+ "value": 0
+ }
+ },
+ {
+ "lba_max": 0,
+ "lba_min": 0,
+ "status": {
+ "string": "Not_testing",
+ "value": 0
+ }
+ },
+ {
+ "lba_max": 0,
+ "lba_min": 0,
+ "status": {
+ "string": "Not_testing",
+ "value": 0
+ }
+ },
+ {
+ "lba_max": 0,
+ "lba_min": 0,
+ "status": {
+ "string": "Not_testing",
+ "value": 0
+ }
+ }
+ ]
+ },
+ "ata_smart_self_test_log": {
+ "standard": {
+ "count": 0,
+ "revision": 1
+ }
+ },
+ "ata_version": {
+ "major_value": 510,
+ "minor_value": 0,
+ "string": "ATA8-ACS (minor revision not indicated)"
+ },
+ "device": {
+ "info_name": "/dev/sde [SAT]",
+ "name": "/dev/sde",
+ "protocol": "ATA",
+ "type": "sat"
+ },
+ "firmware_version": "01.01V02",
+ "in_smartctl_database": true,
+ "interface_speed": {
+ "current": {
+ "bits_per_unit": 100000000,
+ "sata_value": 2,
+ "string": "3.0 Gb/s",
+ "units_per_second": 30
+ },
+ "max": {
+ "bits_per_unit": 100000000,
+ "sata_value": 6,
+ "string": "3.0 Gb/s",
+ "units_per_second": 30
+ }
+ },
+ "json_format_version": [
+ 1,
+ 0
+ ],
+ "local_time": {
+ "asctime": "Mon Sep 2 12:39:01 2019 UTC",
+ "time_t": 1567427941
+ },
+ "logical_block_size": 512,
+ "model_family": "Western Digital RE4",
+ "model_name": "WDC WD1003FBYX-01Y7B1",
+ "nvme_smart_health_information_add_log_error": "nvme returned an error: sudo: exit status: 1",
+ "nvme_smart_health_information_add_log_error_code": -22,
+ "nvme_vendor": "wdc_wd1003fbyx-01y7b1",
+ "physical_block_size": 512,
+ "power_cycle_count": 1370,
+ "power_on_time": {
+ "hours": 15807
+ },
+ "rotation_rate": 7200,
+ "sata_version": {
+ "string": "SATA 3.0",
+ "value": 63
+ },
+ "serial_number": "WD-WCAW11111111",
+ "smart_status": {
+ "passed": true
+ },
+ "smartctl": {
+ "argv": [
+ "smartctl",
+ "-a",
+ "/dev/sde",
+ "--json"
+ ],
+ "build_info": "(SUSE RPM)",
+ "exit_status": 0,
+ "platform_info": "x86_64-linux-5.0.0-25-generic",
+ "svn_revision": "4917",
+ "version": [
+ 7,
+ 0
+ ]
+ },
+ "temperature": {
+ "current": 47
+ },
+ "user_capacity": {
+ "blocks": 1953525168,
+ "bytes": 1000204886016
+ },
+ "wwn": {
+ "id": 11601695629,
+ "naa": 5,
+ "oui": 5358
+ }
+ }
+}
--- /dev/null
+{
+ "Samsung_SSD_970_EVO_Plus_1TB_S4EXXXXXXXXXXXX": {
+ "device": {
+ "info_name": "/dev/nvme0n1",
+ "name": "/dev/nvme0n1",
+ "protocol": "NVMe",
+ "type": "nvme"
+ },
+ "firmware_version": "1B2QEXM7",
+ "json_format_version": [1, 0],
+ "local_time": { "asctime": "Thu Oct 24 10:17:06 2019 CEST", "time_t": 1571905026 },
+ "logical_block_size": 512,
+ "model_name": "Samsung SSD 970 EVO Plus 1TB",
+ "nvme_controller_id": 4,
+ "nvme_ieee_oui_identifier": 9528,
+ "nvme_namespaces": [
+ {
+ "capacity": { "blocks": 1953525168, "bytes": 1000204886016 },
+ "eui64": { "ext_id": 367510189547, "oui": 9528 },
+ "formatted_lba_size": 512,
+ "id": 1,
+ "size": { "blocks": 1953525168, "bytes": 1000204886016 },
+ "utilization": { "blocks": 102347056, "bytes": 52401692672 }
+ }
+ ],
+ "nvme_number_of_namespaces": 1,
+ "nvme_pci_vendor": { "id": 5197, "subsystem_id": 5197 },
+ "nvme_smart_health_information_add_log_error": "nvme returned an error: sudo: exit status: 231",
+ "nvme_smart_health_information_add_log_error_code": -22,
+ "nvme_smart_health_information_log": {
+ "available_spare": 100,
+ "available_spare_threshold": 10,
+ "controller_busy_time": 29,
+ "critical_comp_time": 0,
+ "critical_warning": 0,
+ "data_units_read": 28800,
+ "data_units_written": 558814,
+ "host_reads": 480163,
+ "host_writes": 2340561,
+ "media_errors": 0,
+ "num_err_log_entries": 2,
+ "percentage_used": 0,
+ "power_cycles": 4,
+ "power_on_hours": 13,
+ "temperature": 42,
+ "temperature_sensors": [42, 46],
+ "unsafe_shutdowns": 2,
+ "warning_temp_time": 0
+ },
+ "nvme_total_capacity": 1000204886016,
+ "nvme_unallocated_capacity": 0,
+ "nvme_vendor": "samsung",
+ "power_cycle_count": 4,
+ "power_on_time": { "hours": 13 },
+ "serial_number": "S4EXXXXXXXXXXXX",
+ "smart_status": { "nvme": { "value": 0 }, "passed": true },
+ "smartctl": {
+ "argv": ["smartctl", "-a", "--json=o", "/dev/nvme0n1"],
+ "build_info": "(local build)",
+ "exit_status": 0,
+ "output": [
+ "smartctl 7.0 2018-12-30 r4883 [x86_64-linux-5.0.0-32-generic] (local build)",
+ "Copyright (C) 2002-18, Bruce Allen, Christian Franke, www.smartmontools.org",
+ "",
+ "=== START OF INFORMATION SECTION ===",
+ "Model Number: Samsung SSD 970 EVO Plus 1TB",
+ "Serial Number: S4EXXXXXXXXXXXX",
+ "Firmware Version: 1B2QEXM7",
+ "PCI Vendor/Subsystem ID: 0x144d",
+ "IEEE OUI Identifier: 0x002538",
+ "Total NVM Capacity: 1.000.204.886.016 [1,00 TB]",
+ "Unallocated NVM Capacity: 0",
+ "Controller ID: 4",
+ "Number of Namespaces: 1",
+ "Namespace 1 Size/Capacity: 1.000.204.886.016 [1,00 TB]",
+ "Namespace 1 Utilization: 52.401.692.672 [52,4 GB]",
+ "Namespace 1 Formatted LBA Size: 512",
+ "Namespace 1 IEEE EUI-64: 002538 55915075eb",
+ "Local Time is: Thu Oct 24 10:17:06 2019 CEST",
+ "Firmware Updates (0x16): 3 Slots, no Reset required",
+ "Optional Admin Commands (0x0017): Security Format Frmw_DL Self_Test",
+ "Optional NVM Commands (0x005f): Comp Wr_Unc DS_Mngmt Wr_Zero Sav/Sel_Feat Timestmp",
+ "Maximum Data Transfer Size: 512 Pages",
+ "Warning Comp. Temp. Threshold: 85 Celsius",
+ "Critical Comp. Temp. Threshold: 85 Celsius",
+ "",
+ "Supported Power States",
+ "St Op Max Active Idle RL RT WL WT Ent_Lat Ex_Lat",
+ " 0 + 7.80W - - 0 0 0 0 0 0",
+ " 1 + 6.00W - - 1 1 1 1 0 0",
+ " 2 + 3.40W - - 2 2 2 2 0 0",
+ " 3 - 0.0700W - - 3 3 3 3 210 1200",
+ " 4 - 0.0100W - - 4 4 4 4 2000 8000",
+ "",
+ "Supported LBA Sizes (NSID 0x1)",
+ "Id Fmt Data Metadt Rel_Perf",
+ " 0 + 512 0 0",
+ "",
+ "=== START OF SMART DATA SECTION ===",
+ "SMART overall-health self-assessment test result: PASSED",
+ "",
+ "SMART/Health Information (NVMe Log 0x02)",
+ "Critical Warning: 0x00",
+ "Temperature: 42 Celsius",
+ "Available Spare: 100%",
+ "Available Spare Threshold: 10%",
+ "Percentage Used: 0%",
+ "Data Units Read: 28.800 [14,7 GB]",
+ "Data Units Written: 558.814 [286 GB]",
+ "Host Read Commands: 480.163",
+ "Host Write Commands: 2.340.561",
+ "Controller Busy Time: 29",
+ "Power Cycles: 4",
+ "Power On Hours: 13",
+ "Unsafe Shutdowns: 2",
+ "Media and Data Integrity Errors: 0",
+ "Error Information Log Entries: 2",
+ "Warning Comp. Temperature Time: 0",
+ "Critical Comp. Temperature Time: 0",
+ "Temperature Sensor 1: 42 Celsius",
+ "Temperature Sensor 2: 46 Celsius",
+ "",
+ "Error Information (NVMe Log 0x01, max 64 entries)",
+ "No Errors Logged",
+ ""
+ ],
+ "platform_info": "x86_64-linux-5.0.0-32-generic",
+ "svn_revision": "4883",
+ "version": [7, 0]
+ },
+ "temperature": { "current": 42 },
+ "user_capacity": { "blocks": 1953525168, "bytes": 1000204886016 }
+ }
+}
+++ /dev/null
-{
- "WDC_WD1003FBYX-01Y7B1_WD-WCAW11111111": {
- "ata_sct_capabilities": {
- "data_table_supported": true,
- "error_recovery_control_supported": true,
- "feature_control_supported": true,
- "value": 12351
- },
- "ata_smart_attributes": {
- "revision": 16,
- "table": [
- {
- "flags": {
- "auto_keep": true,
- "error_rate": true,
- "event_count": false,
- "performance": true,
- "prefailure": true,
- "string": "POSR-K ",
- "updated_online": true,
- "value": 47
- },
- "id": 1,
- "name": "Raw_Read_Error_Rate",
- "raw": {
- "string": "1",
- "value": 1
- },
- "thresh": 51,
- "value": 200,
- "when_failed": "",
- "worst": 200
- },
- {
- "flags": {
- "auto_keep": true,
- "error_rate": false,
- "event_count": false,
- "performance": true,
- "prefailure": true,
- "string": "POS--K ",
- "updated_online": true,
- "value": 39
- },
- "id": 3,
- "name": "Spin_Up_Time",
- "raw": {
- "string": "4250",
- "value": 4250
- },
- "thresh": 21,
- "value": 175,
- "when_failed": "",
- "worst": 172
- },
- {
- "flags": {
- "auto_keep": true,
- "error_rate": false,
- "event_count": true,
- "performance": false,
- "prefailure": false,
- "string": "-O--CK ",
- "updated_online": true,
- "value": 50
- },
- "id": 4,
- "name": "Start_Stop_Count",
- "raw": {
- "string": "1657",
- "value": 1657
- },
- "thresh": 0,
- "value": 99,
- "when_failed": "",
- "worst": 99
- },
- {
- "flags": {
- "auto_keep": true,
- "error_rate": false,
- "event_count": true,
- "performance": false,
- "prefailure": true,
- "string": "PO--CK ",
- "updated_online": true,
- "value": 51
- },
- "id": 5,
- "name": "Reallocated_Sector_Ct",
- "raw": {
- "string": "0",
- "value": 0
- },
- "thresh": 140,
- "value": 200,
- "when_failed": "",
- "worst": 200
- },
- {
- "flags": {
- "auto_keep": true,
- "error_rate": true,
- "event_count": false,
- "performance": true,
- "prefailure": false,
- "string": "-OSR-K ",
- "updated_online": true,
- "value": 46
- },
- "id": 7,
- "name": "Seek_Error_Rate",
- "raw": {
- "string": "0",
- "value": 0
- },
- "thresh": 0,
- "value": 200,
- "when_failed": "",
- "worst": 200
- },
- {
- "flags": {
- "auto_keep": true,
- "error_rate": false,
- "event_count": true,
- "performance": false,
- "prefailure": false,
- "string": "-O--CK ",
- "updated_online": true,
- "value": 50
- },
- "id": 9,
- "name": "Power_On_Hours",
- "raw": {
- "string": "15807",
- "value": 15807
- },
- "thresh": 0,
- "value": 79,
- "when_failed": "",
- "worst": 79
- },
- {
- "flags": {
- "auto_keep": true,
- "error_rate": false,
- "event_count": true,
- "performance": false,
- "prefailure": false,
- "string": "-O--CK ",
- "updated_online": true,
- "value": 50
- },
- "id": 10,
- "name": "Spin_Retry_Count",
- "raw": {
- "string": "0",
- "value": 0
- },
- "thresh": 0,
- "value": 100,
- "when_failed": "",
- "worst": 100
- },
- {
- "flags": {
- "auto_keep": true,
- "error_rate": false,
- "event_count": true,
- "performance": false,
- "prefailure": false,
- "string": "-O--CK ",
- "updated_online": true,
- "value": 50
- },
- "id": 11,
- "name": "Calibration_Retry_Count",
- "raw": {
- "string": "0",
- "value": 0
- },
- "thresh": 0,
- "value": 100,
- "when_failed": "",
- "worst": 100
- },
- {
- "flags": {
- "auto_keep": true,
- "error_rate": false,
- "event_count": true,
- "performance": false,
- "prefailure": false,
- "string": "-O--CK ",
- "updated_online": true,
- "value": 50
- },
- "id": 12,
- "name": "Power_Cycle_Count",
- "raw": {
- "string": "1370",
- "value": 1370
- },
- "thresh": 0,
- "value": 99,
- "when_failed": "",
- "worst": 99
- },
- {
- "flags": {
- "auto_keep": true,
- "error_rate": false,
- "event_count": true,
- "performance": false,
- "prefailure": false,
- "string": "-O--CK ",
- "updated_online": true,
- "value": 50
- },
- "id": 192,
- "name": "Power-Off_Retract_Count",
- "raw": {
- "string": "111",
- "value": 111
- },
- "thresh": 0,
- "value": 200,
- "when_failed": "",
- "worst": 200
- },
- {
- "flags": {
- "auto_keep": true,
- "error_rate": false,
- "event_count": true,
- "performance": false,
- "prefailure": false,
- "string": "-O--CK ",
- "updated_online": true,
- "value": 50
- },
- "id": 193,
- "name": "Load_Cycle_Count",
- "raw": {
- "string": "1545",
- "value": 1545
- },
- "thresh": 0,
- "value": 200,
- "when_failed": "",
- "worst": 200
- },
- {
- "flags": {
- "auto_keep": true,
- "error_rate": false,
- "event_count": false,
- "performance": false,
- "prefailure": false,
- "string": "-O---K ",
- "updated_online": true,
- "value": 34
- },
- "id": 194,
- "name": "Temperature_Celsius",
- "raw": {
- "string": "47",
- "value": 47
- },
- "thresh": 0,
- "value": 100,
- "when_failed": "",
- "worst": 89
- },
- {
- "flags": {
- "auto_keep": true,
- "error_rate": false,
- "event_count": true,
- "performance": false,
- "prefailure": false,
- "string": "-O--CK ",
- "updated_online": true,
- "value": 50
- },
- "id": 196,
- "name": "Reallocated_Event_Count",
- "raw": {
- "string": "0",
- "value": 0
- },
- "thresh": 0,
- "value": 200,
- "when_failed": "",
- "worst": 200
- },
- {
- "flags": {
- "auto_keep": true,
- "error_rate": false,
- "event_count": true,
- "performance": false,
- "prefailure": false,
- "string": "-O--CK ",
- "updated_online": true,
- "value": 50
- },
- "id": 197,
- "name": "Current_Pending_Sector",
- "raw": {
- "string": "0",
- "value": 0
- },
- "thresh": 0,
- "value": 200,
- "when_failed": "",
- "worst": 200
- },
- {
- "flags": {
- "auto_keep": true,
- "error_rate": false,
- "event_count": true,
- "performance": false,
- "prefailure": false,
- "string": "----CK ",
- "updated_online": false,
- "value": 48
- },
- "id": 198,
- "name": "Offline_Uncorrectable",
- "raw": {
- "string": "0",
- "value": 0
- },
- "thresh": 0,
- "value": 200,
- "when_failed": "",
- "worst": 200
- },
- {
- "flags": {
- "auto_keep": true,
- "error_rate": false,
- "event_count": true,
- "performance": false,
- "prefailure": false,
- "string": "-O--CK ",
- "updated_online": true,
- "value": 50
- },
- "id": 199,
- "name": "UDMA_CRC_Error_Count",
- "raw": {
- "string": "0",
- "value": 0
- },
- "thresh": 0,
- "value": 200,
- "when_failed": "",
- "worst": 200
- },
- {
- "flags": {
- "auto_keep": false,
- "error_rate": true,
- "event_count": false,
- "performance": false,
- "prefailure": false,
- "string": "---R-- ",
- "updated_online": false,
- "value": 8
- },
- "id": 200,
- "name": "Multi_Zone_Error_Rate",
- "raw": {
- "string": "0",
- "value": 0
- },
- "thresh": 0,
- "value": 200,
- "when_failed": "",
- "worst": 200
- }
- ]
- },
- "ata_smart_data": {
- "capabilities": {
- "attribute_autosave_enabled": true,
- "conveyance_self_test_supported": true,
- "error_logging_supported": true,
- "exec_offline_immediate_supported": true,
- "gp_logging_supported": true,
- "offline_is_aborted_upon_new_cmd": false,
- "offline_surface_scan_supported": true,
- "selective_self_test_supported": true,
- "self_tests_supported": true,
- "values": [
- 123,
- 3
- ]
- },
- "offline_data_collection": {
- "completion_seconds": 16500,
- "status": {
- "string": "was suspended by an interrupting command from host",
- "value": 132
- }
- },
- "self_test": {
- "polling_minutes": {
- "conveyance": 5,
- "extended": 162,
- "short": 2
- },
- "status": {
- "passed": true,
- "string": "completed without error",
- "value": 0
- }
- }
- },
- "ata_smart_error_log": {
- "summary": {
- "count": 0,
- "revision": 1
- }
- },
- "ata_smart_selective_self_test_log": {
- "flags": {
- "remainder_scan_enabled": false,
- "value": 0
- },
- "power_up_scan_resume_minutes": 0,
- "revision": 1,
- "table": [
- {
- "lba_max": 0,
- "lba_min": 0,
- "status": {
- "string": "Not_testing",
- "value": 0
- }
- },
- {
- "lba_max": 0,
- "lba_min": 0,
- "status": {
- "string": "Not_testing",
- "value": 0
- }
- },
- {
- "lba_max": 0,
- "lba_min": 0,
- "status": {
- "string": "Not_testing",
- "value": 0
- }
- },
- {
- "lba_max": 0,
- "lba_min": 0,
- "status": {
- "string": "Not_testing",
- "value": 0
- }
- },
- {
- "lba_max": 0,
- "lba_min": 0,
- "status": {
- "string": "Not_testing",
- "value": 0
- }
- }
- ]
- },
- "ata_smart_self_test_log": {
- "standard": {
- "count": 0,
- "revision": 1
- }
- },
- "ata_version": {
- "major_value": 510,
- "minor_value": 0,
- "string": "ATA8-ACS (minor revision not indicated)"
- },
- "device": {
- "info_name": "/dev/sde [SAT]",
- "name": "/dev/sde",
- "protocol": "ATA",
- "type": "sat"
- },
- "firmware_version": "01.01V02",
- "in_smartctl_database": true,
- "interface_speed": {
- "current": {
- "bits_per_unit": 100000000,
- "sata_value": 2,
- "string": "3.0 Gb/s",
- "units_per_second": 30
- },
- "max": {
- "bits_per_unit": 100000000,
- "sata_value": 6,
- "string": "3.0 Gb/s",
- "units_per_second": 30
- }
- },
- "json_format_version": [
- 1,
- 0
- ],
- "local_time": {
- "asctime": "Mon Sep 2 12:39:01 2019 UTC",
- "time_t": 1567427941
- },
- "logical_block_size": 512,
- "model_family": "Western Digital RE4",
- "model_name": "WDC WD1003FBYX-01Y7B1",
- "nvme_smart_health_information_add_log_error": "nvme returned an error: sudo: exit status: 1",
- "nvme_smart_health_information_add_log_error_code": -22,
- "nvme_vendor": "wdc_wd1003fbyx-01y7b1",
- "physical_block_size": 512,
- "power_cycle_count": 1370,
- "power_on_time": {
- "hours": 15807
- },
- "rotation_rate": 7200,
- "sata_version": {
- "string": "SATA 3.0",
- "value": 63
- },
- "serial_number": "WD-WCAW11111111",
- "smart_status": {
- "passed": true
- },
- "smartctl": {
- "argv": [
- "smartctl",
- "-a",
- "/dev/sde",
- "--json"
- ],
- "build_info": "(SUSE RPM)",
- "exit_status": 0,
- "platform_info": "x86_64-linux-5.0.0-25-generic",
- "svn_revision": "4917",
- "version": [
- 7,
- 0
- ]
- },
- "temperature": {
- "current": 47
- },
- "user_capacity": {
- "blocks": 1953525168,
- "bytes": 1000204886016
- },
- "wwn": {
- "id": 11601695629,
- "naa": 5,
- "oui": 5358
- }
- }
-}
<ng-container *ngIf="!loading; else isLoading">
<ng-container *ngIf="incompatible; else isCompatible">
- <cd-alert-panel type="warning"
+ <cd-alert-panel id="alert-wrong-format"
+ type="warning"
i18n>The data received has the JSON format version 2.x and is currently incompatible with the dashboard.</cd-alert-panel>
</ng-container>
<ng-template #isCompatible>
<tabset *ngFor="let device of data | keyvalue">
<tab [heading]="device.value.device + ' (' + device.value.identifier + ')'">
<ng-container *ngIf="device.value.error; else noError">
- <cd-alert-panel type="warning">{{ device.value.userMessage }}</cd-alert-panel>
+ <cd-alert-panel id="alert-error"
+ type="warning">{{ device.value.userMessage }}</cd-alert-panel>
</ng-container>
<ng-template #noError>
- <ng-container *ngIf="device.value.smart.data.self_test.status.passed; else selfTestFailed">
- <cd-alert-panel
- size="slim"
- type="info"
- i18n-title
- title="SMART overall-health self-assessment test result">
- {{ device.value.smart.data.self_test.status.string }}
- </cd-alert-panel>
+ <!-- HDD/NVMe self test -->
+ <ng-container *ngIf="device.value.info.smart_status.passed; else selfTestFailed">
+ <cd-alert-panel id="alert-self-test-passed"
+ size="slim"
+ type="info"
+ i18n-title
+ title="SMART overall-health self-assessment test result"
+ i18n>passed</cd-alert-panel>
</ng-container>
<ng-template #selfTestFailed>
- <cd-alert-panel
- size="slim"
- type="warning"
- i18n-title
- title="SMART overall-health self-assessment test result">
- {{ device.value.smart.data.self_test.status.string }}
- </cd-alert-panel>
+ <cd-alert-panel id="alert-self-test-failed"
+ size="slim"
+ type="warning"
+ i18n-title
+ title="SMART overall-health self-assessment test result"
+ i18n>failed</cd-alert-panel>
</ng-template>
+
<tabset>
<tab i18n-heading
heading="Device Information">
</tab>
<tab i18n-heading
- heading="S.M.A.R.T">
- <cd-table [data]="device.value.smart.attributes.table"
+ heading="SMART">
+ <cd-table *ngIf="device.value.smart.attributes"
+ [data]="device.value.smart.attributes.table"
updateSelectionOnRefresh="never"
- [columns]="columns"></cd-table>
+ [columns]="smartDataColumns"></cd-table>
+ <cd-table-key-value *ngIf="device.value.smart.nvmeData"
+ [renderObjects]="true"
+ [data]="device.value.smart.nvmeData"
+ updateSelectionOnRefresh="never"></cd-table-key-value>
+ <cd-alert-panel *ngIf="!device.value.smart.attributes && !device.value.smart.nvmeData"
+ type="info"
+ i18n>No SMART data available for this device.</cd-alert-panel>
</tab>
</tabset>
</ng-template>
</ng-template>
</ng-container>
<ng-template #isLoading>
- <cd-loading-panel i18n>S.M.A.R.T data is loading.</cd-loading-panel>
+ <cd-loading-panel i18n>SMART data is loading.</cd-loading-panel>
</ng-template>
import { By } from '@angular/platform-browser';
import { TabsetComponent, TabsetConfig, TabsModule } from 'ngx-bootstrap/tabs';
-import _ = require('lodash');
+import * as _ from 'lodash';
import { of } from 'rxjs';
import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
import { OsdService } from '../../../shared/api/osd.service';
+import { HddSmartDataV1, NvmeSmartDataV1, SmartDataResult } from '../../../shared/models/smart';
import { SharedModule } from '../../../shared/shared.module';
import { SmartListComponent } from './smart-list.component';
let fixture: ComponentFixture<SmartListComponent>;
let osdService: OsdService;
- const SMART_DATA_VERSION_1_0 = require('./fixtures/smart_data_version_1_0_response.json');
-
- const spyOnGetSmartData = (fn: (id: number) => any) =>
- spyOn(osdService, 'getSmartData').and.callFake(fn);
-
- /**
- * Initializes the component after it spied upon the `getSmartData()` method of `OsdService`.
- * @param data The data to be used to return when `getSmartData()` is called.
- * @param simpleChanges (optional) The changes to be used for `ngOnChanges()` method.
- */
- const initializeComponentWithData = (data?: any, simpleChanges?: SimpleChanges) => {
- spyOnGetSmartData(() => of(data || SMART_DATA_VERSION_1_0));
- component.ngOnInit();
- const changes: SimpleChanges = simpleChanges || {
- osdId: new SimpleChange(null, 0, true)
- };
- component.ngOnChanges(changes);
- };
+ const SMART_DATA_HDD_VERSION_1_0: HddSmartDataV1 = require('./fixtures/smart_data_version_1_0_hdd_response.json');
+ const SMART_DATA_NVME_VERSION_1_0: NvmeSmartDataV1 = require('./fixtures/smart_data_version_1_0_nvme_response.json');
/**
* Sets attributes for _all_ returned devices according to the given path. The syntax is the same
*/
const patchData = (path: string, newValue: any): any => {
return _.reduce(
- _.cloneDeep(SMART_DATA_VERSION_1_0),
+ _.cloneDeep(SMART_DATA_HDD_VERSION_1_0),
(result, dataObj, deviceId) => {
- result[deviceId] = _.set(dataObj, path, newValue);
+ result[deviceId] = _.set<any>(dataObj, path, newValue);
return result;
},
{}
);
};
+ /**
+ * Initializes the component after it spied upon the `getSmartData()` method
+ * of `OsdService`. Determines which data is returned.
+ */
+ const initializeComponentWithData = (
+ dataType: 'hdd_v1' | 'nvme_v1',
+ patch: { [path: string]: any } = null,
+ simpleChanges?: SimpleChanges
+ ) => {
+ let data = null;
+ switch (dataType) {
+ case 'hdd_v1':
+ data = SMART_DATA_HDD_VERSION_1_0;
+ break;
+ case 'nvme_v1':
+ data = SMART_DATA_NVME_VERSION_1_0;
+ break;
+ }
+
+ if (_.isObject(patch)) {
+ _.each(patch, (replacement, path) => {
+ data = patchData(path, replacement);
+ });
+ }
+
+ spyOn(osdService, 'getSmartData').and.callFake(() => of(data));
+ component.ngOnInit();
+ const changes: SimpleChanges = simpleChanges || {
+ osdId: new SimpleChange(null, 0, true)
+ };
+ component.ngOnChanges(changes);
+ };
+
configureTestBed({
declarations: [SmartListComponent],
imports: [TabsModule, SharedModule, HttpClientTestingModule],
expect(component).toBeTruthy();
});
- describe('tests version 1.x', () => {
- beforeEach(() => initializeComponentWithData());
+ describe('tests HDD version 1.x', () => {
+ beforeEach(() => initializeComponentWithData('hdd_v1'));
it('should return with proper keys', () => {
_.each(component.data, (smartData, _deviceId) => {
'ata_smart_selective_self_test_log',
'ata_smart_data'
];
+ _.each(component.data, (smartData: SmartDataResult, _deviceId) => {
+ _.each(excludes, (exclude) => expect(smartData.info[exclude]).toBeUndefined());
+ });
+ });
+ });
+
+ describe('tests NVMe version 1.x', () => {
+ beforeEach(() => initializeComponentWithData('nvme_v1'));
+
+ it('should return with proper keys', () => {
_.each(component.data, (smartData, _deviceId) => {
+ expect(_.keys(smartData)).toEqual(['info', 'smart', 'device', 'identifier']);
+ });
+ });
+
+ it('should not contain excluded keys in `info`', () => {
+ const excludes = ['nvme_smart_health_information_log'];
+ _.each(component.data, (smartData: SmartDataResult, _deviceId) => {
_.each(excludes, (exclude) => expect(smartData.info[exclude]).toBeUndefined());
});
});
});
it('should not work for version 2.x', () => {
- initializeComponentWithData(patchData('json_format_version', [2, 0]));
+ initializeComponentWithData('nvme_v1', { json_format_version: [2, 0] });
expect(component.data).toEqual({});
expect(component.incompatible).toBeTruthy();
});
it('should display info panel for passed self test', () => {
- initializeComponentWithData();
+ initializeComponentWithData('hdd_v1');
fixture.detectChanges();
- const alertPanel = fixture.debugElement.query(By.css('cd-alert-panel'));
+ const alertPanel = fixture.debugElement.query(By.css('cd-alert-panel#alert-self-test-passed'));
expect(component.incompatible).toBe(false);
expect(component.loading).toBe(false);
expect(alertPanel.attributes.size).toBe('slim');
});
it('should display warning panel for failed self test', () => {
- initializeComponentWithData(patchData('ata_smart_data.self_test.status.passed', false));
+ initializeComponentWithData('hdd_v1', { 'smart_status.passed': false });
fixture.detectChanges();
- const alertPanel = fixture.debugElement.query(By.css('cd-alert-panel'));
+ const alertPanel = fixture.debugElement.query(By.css('cd-alert-panel#alert-self-test-failed'));
expect(component.incompatible).toBe(false);
expect(component.loading).toBe(false);
expect(alertPanel.attributes.size).toBe('slim');
import { I18n } from '@ngx-translate/i18n-polyfill';
import * as _ from 'lodash';
import { HostService } from '../../../shared/api/host.service';
-import {
- OsdService,
- SmartAttribute,
- SmartDataV1,
- SmartError
-} from '../../../shared/api/osd.service';
+import { OsdService } from '../../../shared/api/osd.service';
import { CdTableColumn } from '../../../shared/models/cd-table-column';
+import {
+ HddSmartDataV1,
+ NvmeSmartDataV1,
+ SmartDataResult,
+ SmartError,
+ SmartErrorResult
+} from '../../../shared/models/smart';
@Component({
selector: 'cd-smart-list',
loading = false;
incompatible = false;
- data: {
- [deviceId: string]: {
- info: { [key: string]: number | string | boolean };
- smart: {
- revision: number;
- table: SmartAttribute[];
- };
- };
- } = {};
+ data: { [deviceId: string]: SmartDataResult | SmartErrorResult } = {};
- columns: CdTableColumn[];
+ smartDataColumns: CdTableColumn[];
constructor(
private i18n: I18n,
private hostService: HostService
) {}
- private isSmartError(data: SmartDataV1 | SmartError): data is SmartError {
- return (data as SmartError).error !== undefined;
+ isSmartError(data: any): data is SmartError {
+ return _.get(data, 'error') !== undefined;
+ }
+
+ isNvmeSmartData(data: any): data is NvmeSmartDataV1 {
+ return _.get(data, 'device.protocol', '').toLowerCase() === 'nvme';
+ }
+
+ isHddSmartData(data: any): data is HddSmartDataV1 {
+ return _.get(data, 'device.protocol', '').toLowerCase() === 'ata';
}
private fetchData(data) {
- const result = {};
+ const result: { [deviceId: string]: SmartDataResult | SmartErrorResult } = {};
_.each(data, (smartData, deviceId) => {
if (this.isSmartError(smartData)) {
let userMessage = '';
code: smartData.smartctl_error_code
});
}
- result[deviceId] = {
+ const _result: SmartErrorResult = {
error: smartData.error,
smartctl_error_code: smartData.smartctl_error_code,
smartctl_output: smartData.smartctl_output,
device: smartData.dev,
identifier: smartData.nvme_vendor
};
+ result[deviceId] = _result;
return;
}
// Prepare S.M.A.R.T data
if (smartData.json_format_version[0] === 1) {
// Version 1.x
- const excludes = [
- 'ata_smart_attributes',
- 'ata_smart_selective_self_test_log',
- 'ata_smart_data'
- ];
- const info = _.pickBy(smartData, (_value, key) => !excludes.includes(key));
- // Build result
- result[deviceId] = {
- info: info,
- smart: {
- attributes: smartData.ata_smart_attributes,
- data: smartData.ata_smart_data
- },
- device: info.device.name,
- identifier: info.serial_number
- };
+ if (this.isHddSmartData(smartData)) {
+ result[deviceId] = this.extractHddData(smartData);
+ } else if (this.isNvmeSmartData(smartData)) {
+ result[deviceId] = this.extractNvmeData(smartData);
+ }
+ return;
} else {
this.incompatible = true;
}
this.loading = false;
}
+ private extractNvmeData(smartData: NvmeSmartDataV1): SmartDataResult {
+ const info = _.omitBy(smartData, (_value, key) =>
+ ['nvme_smart_health_information_log'].includes(key)
+ );
+ return {
+ info: info,
+ smart: {
+ nvmeData: smartData.nvme_smart_health_information_log
+ },
+ device: smartData.device.name,
+ identifier: smartData.serial_number
+ };
+ }
+
+ private extractHddData(smartData: HddSmartDataV1): SmartDataResult {
+ const info = _.omitBy(smartData, (_value, key) =>
+ ['ata_smart_attributes', 'ata_smart_selective_self_test_log', 'ata_smart_data'].includes(key)
+ );
+ return {
+ info: info,
+ smart: {
+ attributes: smartData.ata_smart_attributes,
+ data: smartData.ata_smart_data
+ },
+ device: info.device.name,
+ identifier: info.serial_number
+ };
+ }
+
private updateData() {
this.loading = true;
}
ngOnInit() {
- this.columns = [
+ this.smartDataColumns = [
{ prop: 'id', name: this.i18n('ID') },
{ prop: 'name', name: this.i18n('Name') },
{ prop: 'raw.value', name: this.i18n('Raw') },
import { map } from 'rxjs/operators';
import { CdDevice } from '../models/devices';
+import { SmartDataResponseV1 } from '../models/smart';
import { DeviceService } from '../services/device.service';
import { ApiModule } from './api.module';
}
getSmartData(hostname) {
- return this.http.get(`${this.baseURL}/${hostname}/smart`);
+ return this.http.get<SmartDataResponseV1>(`${this.baseURL}/${hostname}/smart`);
}
}
import { map } from 'rxjs/operators';
import { CdDevice } from '../models/devices';
+import { SmartDataResponseV1 } from '../models/smart';
import { DeviceService } from '../services/device.service';
import { ApiModule } from './api.module';
-export interface SmartAttribute {
- flags: {
- auto_keep: boolean;
- error_rate: boolean;
- event_count: boolean;
- performance: boolean;
- prefailure: boolean;
- string: string;
- updated_online: boolean;
- value: number;
- };
- id: number;
- name: string;
- raw: { string: string; value: number };
- thresh: number;
- value: number;
- when_failed: string;
- worst: number;
-}
-
-export interface SmartError {
- dev: string;
- error: string;
- nvme_smart_health_information_add_log_error: string;
- nvme_smart_health_information_add_log_error_code: number;
- nvme_vendor: string;
- smartctl_error_code: number;
- smartctl_output: string;
-}
-
-export interface SmartDataV1 {
- ata_sct_capabilities: {
- data_table_supported: boolean;
- error_recovery_control_supported: boolean;
- feature_control_supported: boolean;
- value: number;
- };
- ata_smart_attributes: {
- revision: number;
- table: SmartAttribute[];
- };
- ata_smart_data: {
- capabilities: {
- attribute_autosave_enabled: boolean;
- conveyance_self_test_supported: boolean;
- error_logging_supported: boolean;
- exec_offline_immediate_supported: boolean;
- gp_logging_supported: boolean;
- offline_is_aborted_upon_new_cmd: boolean;
- offline_surface_scan_supported: boolean;
- selective_self_test_supported: boolean;
- self_tests_supported: boolean;
- values: number[];
- };
- offline_data_collection: {
- completion_seconds: number;
- status: { string: string; value: number };
- };
- self_test: {
- polling_minutes: { conveyance: number; extended: number; short: number };
- status: { passed: boolean; string: string; value: number };
- };
- };
- ata_smart_error_log: { summary: { count: number; revision: number } };
- ata_smart_selective_self_test_log: {
- flags: { remainder_scan_enabled: boolean; value: number };
- power_up_scan_resume_minutes: number;
- revision: number;
- table: {
- lba_max: number;
- lba_min: number;
- status: { string: string; value: number };
- }[];
- };
- ata_smart_self_test_log: { standard: { count: number; revision: number } };
- ata_version: { major_value: number; minor_value: number; string: string };
- device: { info_name: string; name: string; protocol: string; type: string };
- firmware_version: string;
- in_smartctl_database: boolean;
- interface_speed: {
- current: {
- bits_per_unit: number;
- sata_value: number;
- string: string;
- units_per_second: number;
- };
- max: {
- bits_per_unit: number;
- sata_value: number;
- string: string;
- units_per_second: number;
- };
- };
- json_format_version: number[];
- local_time: { asctime: string; time_t: number };
- logical_block_size: number;
- model_family: string;
- model_name: string;
- nvme_smart_health_information_add_log_error: string;
- nvme_smart_health_information_add_log_error_code: number;
- nvme_vendor: string;
- physical_block_size: number;
- power_cycle_count: number;
- power_on_time: { hours: number };
- rotation_rate: number;
- sata_version: { string: string; value: number };
- serial_number: string;
- smart_status: { passed: boolean };
- smartctl: {
- argv: string[];
- build_info: string;
- exit_status: number;
- output: string[];
- platform_info: string;
- svn_revision: string;
- version: number[];
- };
- temperature: { current: number };
- user_capacity: { blocks: number; bytes: number };
- wwn: { id: number; naa: number; oui: number };
-}
-
@Injectable({
providedIn: ApiModule
})
* @param id OSD ID
*/
getSmartData(id: number) {
- return this.http.get<{ [deviceId: string]: SmartDataV1 | SmartError }>(
- `${this.path}/${id}/smart`
- );
+ return this.http.get<SmartDataResponseV1>(`${this.path}/${id}/smart`);
}
scrub(id, deep) {
--- /dev/null
+export interface SmartAttribute {
+ flags: {
+ auto_keep: boolean;
+ error_rate: boolean;
+ event_count: boolean;
+ performance: boolean;
+ prefailure: boolean;
+ string: string;
+ updated_online: boolean;
+ value: number;
+ };
+ id: number;
+ name: string;
+ raw: { string: string; value: number };
+ thresh: number;
+ value: number;
+ when_failed: string;
+ worst: number;
+}
+
+/**
+ * The error structure returned from the back-end if SMART data couldn't be
+ * retrieved.
+ */
+export interface SmartError {
+ dev: string;
+ error: string;
+ nvme_smart_health_information_add_log_error: string;
+ nvme_smart_health_information_add_log_error_code: number;
+ nvme_vendor: string;
+ smartctl_error_code: number;
+ smartctl_output: string;
+}
+
+/**
+ * Common smartctl output structure.
+ */
+interface SmartCtlOutput {
+ argv: string[];
+ build_info: string;
+ exit_status: number;
+ output: string[];
+ platform_info: string;
+ svn_revision: string;
+ version: number[];
+}
+
+/**
+ * Common smartctl device structure.
+ */
+interface SmartCtlDevice {
+ info_name: string;
+ name: string;
+ protocol: string;
+ type: string;
+}
+
+/**
+ * smartctl data structure shared among HDD/NVMe.
+ */
+interface SmartCtlBaseDataV1 {
+ device: SmartCtlDevice;
+ firmware_version: string;
+ json_format_version: number[];
+ local_time: { asctime: string; time_t: number };
+ logical_block_size: number;
+ model_name: string;
+ nvme_smart_health_information_add_log_error: string;
+ nvme_smart_health_information_add_log_error_code: number;
+ nvme_vendor: string;
+ power_cycle_count: number;
+ power_on_time: { hours: number };
+ serial_number: string;
+ smart_status: { passed: boolean; nvme?: { value: number } };
+ smartctl: SmartCtlOutput;
+ temperature: { current: number };
+ user_capacity: { blocks: number; bytes: number };
+}
+
+/**
+ * Result structure of `smartctl` applied on an HDD. Returned by the back-end.
+ */
+export interface HddSmartDataV1 extends SmartCtlBaseDataV1 {
+ ata_sct_capabilities: {
+ data_table_supported: boolean;
+ error_recovery_control_supported: boolean;
+ feature_control_supported: boolean;
+ value: number;
+ };
+ ata_smart_attributes: {
+ revision: number;
+ table: SmartAttribute[];
+ };
+ ata_smart_data: {
+ capabilities: {
+ attribute_autosave_enabled: boolean;
+ conveyance_self_test_supported: boolean;
+ error_logging_supported: boolean;
+ exec_offline_immediate_supported: boolean;
+ gp_logging_supported: boolean;
+ offline_is_aborted_upon_new_cmd: boolean;
+ offline_surface_scan_supported: boolean;
+ selective_self_test_supported: boolean;
+ self_tests_supported: boolean;
+ values: number[];
+ };
+ offline_data_collection: {
+ completion_seconds: number;
+ status: { string: string; value: number };
+ };
+ self_test: {
+ polling_minutes: { conveyance: number; extended: number; short: number };
+ status: { passed: boolean; string: string; value: number };
+ };
+ };
+ ata_smart_error_log: { summary: { count: number; revision: number } };
+ ata_smart_selective_self_test_log: {
+ flags: { remainder_scan_enabled: boolean; value: number };
+ power_up_scan_resume_minutes: number;
+ revision: number;
+ table: {
+ lba_max: number;
+ lba_min: number;
+ status: { string: string; value: number };
+ }[];
+ };
+ ata_smart_self_test_log: { standard: { count: number; revision: number } };
+ ata_version: { major_value: number; minor_value: number; string: string };
+ in_smartctl_database: boolean;
+ interface_speed: {
+ current: {
+ bits_per_unit: number;
+ sata_value: number;
+ string: string;
+ units_per_second: number;
+ };
+ max: {
+ bits_per_unit: number;
+ sata_value: number;
+ string: string;
+ units_per_second: number;
+ };
+ };
+ model_family: string;
+ physical_block_size: number;
+ rotation_rate: number;
+ sata_version: { string: string; value: number };
+ smart_status: { passed: boolean };
+ smartctl: SmartCtlOutput;
+ wwn: { id: number; naa: number; oui: number };
+}
+
+/**
+ * Result structure of `smartctl` returned by Ceph and then back-end applied on
+ * an NVMe.
+ */
+export interface NvmeSmartDataV1 extends SmartCtlBaseDataV1 {
+ nvme_controller_id: number;
+ nvme_ieee_oui_identifier: number;
+ nvme_namespaces: {
+ capacity: { blocks: number; bytes: number };
+ eui64: { ext_id: number; oui: number };
+ formatted_lba_size: number;
+ id: number;
+ size: { blocks: number; bytes: number };
+ utilization: { blocks: number; bytes: number };
+ }[];
+ nvme_number_of_namespaces: number;
+ nvme_pci_vendor: { id: number; subsystem_id: number };
+ nvme_smart_health_information_log: {
+ available_spare: number;
+ available_spare_threshold: number;
+ controller_busy_time: number;
+ critical_comp_time: number;
+ critical_warning: number;
+ data_units_read: number;
+ data_units_written: number;
+ host_reads: number;
+ host_writes: number;
+ media_errors: number;
+ num_err_log_entries: number;
+ percentage_used: number;
+ power_cycles: number;
+ power_on_hours: number;
+ temperature: number;
+ temperature_sensors: number[];
+ unsafe_shutdowns: number;
+ warning_temp_time: number;
+ };
+ nvme_total_capacity: number;
+ nvme_unallocated_capacity: number;
+}
+
+/**
+ * The shared fields each result has after it has been processed by the front-end.
+ */
+interface SmartBasicResult {
+ device: string;
+ identifier: string;
+}
+
+/**
+ * The SMART data response structure of the back-end. Per device it will either
+ * contain the structure for a HDD, NVMe or an error.
+ */
+export interface SmartDataResponseV1 {
+ [deviceId: string]: HddSmartDataV1 | NvmeSmartDataV1 | SmartError;
+}
+
+/**
+ * The SMART data result after it has been processed by the front-end.
+ */
+export interface SmartDataResult extends SmartBasicResult {
+ info: { [key: string]: any };
+ smart: {
+ attributes?: any;
+ data?: any;
+ nvmeData?: any;
+ };
+}
+
+/**
+ * The SMART error result after is has been processed by the front-end. If SMART
+ * data couldn't be retrieved, this is the structure which is returned.
+ */
+export interface SmartErrorResult extends SmartBasicResult {
+ error: string;
+ smartctl_error_code: number;
+ smartctl_output: string;
+ userMessage: string;
+}
from __future__ import absolute_import
import json
import logging
-from six.moves import reduce
import rados
raise SendCommandError(outs, prefix, argdict, r)
try:
- return json.loads(outb)
+ return json.loads(outb or outs)
except Exception: # pylint: disable=broad-except
return outb
@staticmethod
- def get_smart_data_by_device(device):
- dev_id = device['devid']
+ def _get_smart_data_by_device(device):
if 'daemons' in device and device['daemons']:
daemons = [daemon for daemon in device['daemons'] if daemon.startswith('osd')]
if daemons:
svc_type, svc_id = daemons[0].split('.')
- dev_smart_data = CephService.send_command(svc_type, 'smart', svc_id, devid=dev_id)
+ dev_smart_data = CephService.send_command(
+ svc_type, 'smart', svc_id, devid=device['devid'])
for dev_id, dev_data in dev_smart_data.items():
if 'error' in dev_data:
logger.warning(
'[SMART] error retrieving smartctl data for device ID "%s": %s', dev_id,
dev_data)
return dev_smart_data
- logger.warning('[SMART] no OSD service found for device ID "%s"', dev_id)
+ logger.warning('[SMART] no OSD service found for device ID "%s"', device['devid'])
return {}
- logger.warning('[SMART] key "daemon" not found for device ID "%s"', dev_id)
+ logger.warning('[SMART] key "daemon" not found for device ID "%s"', device['devid'])
return {}
@staticmethod
@staticmethod
def get_smart_data_by_host(hostname):
# type: (str) -> dict
- return reduce(lambda a, b: a.update(b) or a, [
- CephService.get_smart_data_by_device(device)
- for device in CephService.get_devices_by_host(hostname)
- ], {})
+ devices = CephService.get_devices_by_host(hostname)
+ smart_data = {}
+ if devices:
+ for device in devices:
+ if device['devid'] not in smart_data:
+ smart_data.update(CephService._get_smart_data_by_device(device))
+ return smart_data
@staticmethod
def get_smart_data_by_daemon(daemon_type, daemon_id):
# type: (str, str) -> dict
smart_data = CephService.send_command(daemon_type, 'smart', daemon_id)
- for _, dev_data in smart_data.items():
- if 'error' in dev_data:
- logger.warning('[SMART] Error retrieving smartctl data for daemon "%s.%s"',
- daemon_type, daemon_id)
- return smart_data
+ if smart_data:
+ for _, dev_data in smart_data.items():
+ if 'error' in dev_data:
+ logger.warning('[SMART] Error retrieving smartctl data for daemon "%s.%s"',
+ daemon_type, daemon_id)
+ return smart_data or {}
@classmethod
def get_rates(cls, svc_type, svc_name, path):