From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id F2D166D5FF for ; Thu, 1 Apr 2021 15:44:00 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id F05F21C5EE for ; Thu, 1 Apr 2021 15:44:00 +0200 (CEST) Received: from gaia.proxmox.com (unknown [94.136.29.99]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id 0C7831C5E5 for ; Thu, 1 Apr 2021 15:43:58 +0200 (CEST) Received: from gaia.proxmox.com (localhost.localdomain [127.0.0.1]) by gaia.proxmox.com (8.15.2/8.15.2/Debian-14~deb10u1) with ESMTP id 131Df3lg701754; Thu, 1 Apr 2021 15:41:03 +0200 Received: (from oguz@localhost) by gaia.proxmox.com (8.15.2/8.15.2/Submit) id 131Df3Z6701753; Thu, 1 Apr 2021 15:41:03 +0200 From: Oguz Bektas To: pve-devel@lists.proxmox.com Date: Thu, 1 Apr 2021 15:40:55 +0200 Message-Id: <20210401134055.701355-2-o.bektas@proxmox.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210401134055.701355-1-o.bektas@proxmox.com> References: <20210401134055.701355-1-o.bektas@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 2 AWL 0.050 Adjusted score from AWL reputation of From: address KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods NO_DNS_FOR_FROM 0.379 Envelope sender has no MX or A DNS records RDNS_NONE 1.274 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [diskmanage.pm, disks.pm] Subject: [pve-devel] [PATCH storage 2/2] smartctl: use json parsing X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 01 Apr 2021 13:44:01 -0000 adapt the smartctl endpoint to run smartctl with the --json or -j flag to parse it more reasonably. also add the $format parameter to assist in switching to the new json parsed output for nvme devices in PVE 7.0 (until 7.0 removing the 'text' field completely would be a breaking change, so we still default to the text field but with the parsed "key : value" pairs instead of raw smartctl output) for the unit tests from now we need to collect the smartctl outputs with the json flag. the current tests cover ssd_smart and nvme_smart cases. Signed-off-by: Oguz Bektas ---- RFC -> PATCH: * split patch for removing old tests * incorporate stefan's and thomas' recommendations & nits (thanks!!) * fix issue with array fields not being parsed * add array element in nvme unit test (temperature_sensor) PVE/API2/Disks.pm | 9 +- PVE/Diskmanage.pm | 120 +++--- test/disk_tests/nvme_smart/disklist | 1 + .../nvme_smart/disklist_expected.json | 16 + test/disk_tests/nvme_smart/nvme0/model | 1 + test/disk_tests/nvme_smart/nvme0_smart | 65 ++++ test/disk_tests/nvme_smart/nvme0n1/device | 1 + .../nvme_smart/nvme0n1/queue/rotational | 1 + test/disk_tests/nvme_smart/nvme0n1/size | 1 + .../nvme_smart/nvme0n1_smart_expected.json | 6 + test/disk_tests/nvme_smart/nvme0n1_udevadm | 18 + test/disk_tests/ssd_smart/disklist | 1 + .../ssd_smart/disklist_expected.json | 16 + test/disk_tests/ssd_smart/sda/device/vendor | 1 + .../disk_tests/ssd_smart/sda/queue/rotational | 1 + test/disk_tests/ssd_smart/sda/size | 1 + test/disk_tests/ssd_smart/sda_smart | 352 ++++++++++++++++++ .../ssd_smart/sda_smart_expected.json | 146 ++++++++ test/disk_tests/ssd_smart/sda_udevadm | 11 + test/disklist_test.pm | 4 +- 20 files changed, 714 insertions(+), 58 deletions(-) create mode 100644 test/disk_tests/nvme_smart/disklist create mode 100644 test/disk_tests/nvme_smart/disklist_expected.json create mode 100644 test/disk_tests/nvme_smart/nvme0/model create mode 100644 test/disk_tests/nvme_smart/nvme0_smart create mode 120000 test/disk_tests/nvme_smart/nvme0n1/device create mode 100644 test/disk_tests/nvme_smart/nvme0n1/queue/rotational create mode 100644 test/disk_tests/nvme_smart/nvme0n1/size create mode 100644 test/disk_tests/nvme_smart/nvme0n1_smart_expected.json create mode 100644 test/disk_tests/nvme_smart/nvme0n1_udevadm create mode 100644 test/disk_tests/ssd_smart/disklist create mode 100644 test/disk_tests/ssd_smart/disklist_expected.json create mode 100644 test/disk_tests/ssd_smart/sda/device/vendor create mode 100644 test/disk_tests/ssd_smart/sda/queue/rotational create mode 100644 test/disk_tests/ssd_smart/sda/size create mode 100644 test/disk_tests/ssd_smart/sda_smart create mode 100644 test/disk_tests/ssd_smart/sda_smart_expected.json create mode 100644 test/disk_tests/ssd_smart/sda_udevadm diff --git a/PVE/API2/Disks.pm b/PVE/API2/Disks.pm index 33bca76..a453efc 100644 --- a/PVE/API2/Disks.pm +++ b/PVE/API2/Disks.pm @@ -195,6 +195,12 @@ __PACKAGE__->register_method ({ description => "If true returns only the health status", optional => 1, }, + format => { + description => "Return json or text", + type => 'string', + enum => ['text', 'json'], + optional => 1, + }, }, }, returns => { @@ -204,6 +210,7 @@ __PACKAGE__->register_method ({ type => { type => 'string', optional => 1 }, attributes => { type => 'array', optional => 1}, text => { type => 'string', optional => 1 }, + json => { type => 'string', optional => 1 }, }, }, code => sub { @@ -211,7 +218,7 @@ __PACKAGE__->register_method ({ my $disk = PVE::Diskmanage::verify_blockdev_path($param->{disk}); - my $result = PVE::Diskmanage::get_smart_data($disk, $param->{healthonly}); + my $result = PVE::Diskmanage::get_smart_data($disk, $param->{healthonly}, $param->{format}); $result->{health} = 'UNKNOWN' if !defined $result->{health}; $result = { health => $result->{health} } if $param->{healthonly}; diff --git a/PVE/Diskmanage.pm b/PVE/Diskmanage.pm index 64bb813..3f433fb 100644 --- a/PVE/Diskmanage.pm +++ b/PVE/Diskmanage.pm @@ -81,11 +81,12 @@ sub disk_is_used { } sub get_smart_data { - my ($disk, $healthonly) = @_; + my ($disk, $healthonly, $format) = @_; assert_blockdev($disk); my $smartdata = {}; my $type; + $format //= 'text'; my $returncode = 0; @@ -95,70 +96,79 @@ sub get_smart_data { or die "failed to get nvme controller device for $disk\n"); } - my $cmd = [$SMARTCTL, '-H']; - push @$cmd, '-A', '-f', 'brief' if !$healthonly; + my $cmd = [$SMARTCTL, '-j', '-H']; + push @$cmd, '-Afbrief' if !$healthonly; push @$cmd, $disk; + my $smart_result = ''; eval { - $returncode = run_command($cmd, noerr => 1, outfunc => sub{ - my ($line) = @_; + $returncode = run_command($cmd, noerr => 1, outfunc => sub { $smart_result .= shift }); + }; + my $err = $@; -# ATA SMART attributes, e.g.: -# ID# ATTRIBUTE_NAME FLAGS VALUE WORST THRESH FAIL RAW_VALUE -# 1 Raw_Read_Error_Rate POSR-K 100 100 000 - 0 -# -# SAS and NVME disks, e.g.: -# Data Units Written: 5,584,952 [2.85 TB] -# Accumulated start-stop cycles: 34 - - if (defined($type) && $type eq 'ata' && $line =~ m/^([ \d]{2}\d)\s+(\S+)\s+(\S{6})\s+(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(.*)$/) { - my $entry = {}; - - $entry->{name} = $2 if defined $2; - $entry->{flags} = $3 if defined $3; - # the +0 makes a number out of the strings - $entry->{value} = $4+0 if defined $4; - $entry->{worst} = $5+0 if defined $5; - # some disks report the default threshold as --- instead of 000 - if (defined($6) && $6 eq '---') { - $entry->{threshold} = 0; - } else { - $entry->{threshold} = $6+0 if defined $6; - } - $entry->{fail} = $7 if defined $7; - $entry->{raw} = $8 if defined $8; - $entry->{id} = $1 if defined $1; - push @{$smartdata->{attributes}}, $entry; - } elsif ($line =~ m/(?:Health Status|self\-assessment test result): (.*)$/ ) { - $smartdata->{health} = $1; - } elsif ($line =~ m/Vendor Specific SMART Attributes with Thresholds:/) { - $type = 'ata'; - delete $smartdata->{text}; - } elsif ($line =~ m/=== START OF (READ )?SMART DATA SECTION ===/) { - $type = 'text'; - } elsif (defined($type) && $type eq 'text') { - $smartdata->{text} = '' if !defined $smartdata->{text}; - $smartdata->{text} .= "$line\n"; - # extract wearout from nvme/sas text, allow for decimal values - if ($line =~ m/Percentage Used(?: endurance indicator)?:\s*(\d+(?:\.\d+)?)\%/i) { - $smartdata->{wearout} = 100 - $1; + my $json_result = decode_json($smart_result); + + my $smart_health = $json_result->{smart_status}->{passed}; + if (JSON::is_bool($smart_health)) { + $smart_health = $smart_health ? "PASSED" : "FAILED"; + } else { + $smart_health = 'UNKNOWN'; + } + + $smartdata->{health} = $smart_health; + + $type = $json_result->{device}->{type}; + if ($type eq 'nvme') { + $smartdata->{type} = $format; # text or json but FIXME: remove in PVE 7.0 and use json + + my $nvme_info = $json_result->{nvme_smart_health_information_log}; + + if (!$healthonly) { + $smartdata->{wearout} = 100.0 - $nvme_info->{percentage_used}; + } + + my $add_key = sub { + my ($key, $value) = @_; + if ($format eq 'text') { + $smartdata->{text} .= "$key : $value\n"; + } + }; + + foreach my $key (sort keys %{$nvme_info}) { + my $value = $nvme_info->{$key}; + # some fields can also be arrays + # e.g. temperature_sensor + if (ref($value) eq 'ARRAY') { + while (my $index = each(@$value)) { + $add_key->("${key}_${index}", $value->[$index]); } - } elsif ($line =~ m/SMART Disabled/) { - $smartdata->{health} = "SMART Disabled"; + } else { + $add_key->($key, $value); } - }); - }; - my $err = $@; + } + delete $smartdata->{attributes}; # this is for ata disks only + } else { + $smartdata->{type} = 'ata'; + foreach my $attribute (@{$json_result->{ata_smart_attributes}->{table}}) { + # we need to override or delete some fields to fit expected json schema of unit tests + my $flags_string = $attribute->{flags}->{string}; + $flags_string =~ s/\s+$//; + $attribute->{flags} = $flags_string; + $attribute->{raw} = $attribute->{raw}->{string}; + $attribute->{threshold} = delete $attribute->{thresh}; + $attribute->{fail} = ${attribute}->{when_failed} eq "" ? "-" : ${attribute}->{when_failed}; + delete ${attribute}->{when_failed}; + + push @{$smartdata->{attributes}}, $attribute; + } + my @sorted_attributes = sort { $a->{id} <=> $b->{id} } @{$smartdata->{attributes}}; + @{$smartdata->{attributes}} = @sorted_attributes; + } - # bit 0 and 1 mark an severe smartctl error - # all others are for disk status, so ignore them - # see smartctl(8) - if ((defined($returncode) && ($returncode & 0b00000011)) || $err) { + if ($returncode & 0b00000011 || $err) { die "Error getting S.M.A.R.T. data: Exit code: $returncode\n"; } - $smartdata->{type} = $type; - return $smartdata; } diff --git a/test/disk_tests/nvme_smart/disklist b/test/disk_tests/nvme_smart/disklist new file mode 100644 index 0000000..d00b90e --- /dev/null +++ b/test/disk_tests/nvme_smart/disklist @@ -0,0 +1 @@ +nvme0n1 diff --git a/test/disk_tests/nvme_smart/disklist_expected.json b/test/disk_tests/nvme_smart/disklist_expected.json new file mode 100644 index 0000000..4d1c92f --- /dev/null +++ b/test/disk_tests/nvme_smart/disklist_expected.json @@ -0,0 +1,16 @@ +{ + "nvme0n1" : { + "wearout" : 69, + "vendor" : "unknown", + "size" : 512000, + "health" : "PASSED", + "serial" : "unknown", + "model" : "NVME MODEL 1", + "rpm" : 0, + "osdid" : -1, + "devpath" : "/dev/nvme0n1", + "gpt" : 0, + "wwn" : "unknown", + "type" : "nvme" + } +} diff --git a/test/disk_tests/nvme_smart/nvme0/model b/test/disk_tests/nvme_smart/nvme0/model new file mode 100644 index 0000000..9bd6eba --- /dev/null +++ b/test/disk_tests/nvme_smart/nvme0/model @@ -0,0 +1 @@ +NVME MODEL 1 diff --git a/test/disk_tests/nvme_smart/nvme0_smart b/test/disk_tests/nvme_smart/nvme0_smart new file mode 100644 index 0000000..3f3c799 --- /dev/null +++ b/test/disk_tests/nvme_smart/nvme0_smart @@ -0,0 +1,65 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 2 + ], + "svn_revision": "5155", + "platform_info": "x86_64-linux-5.11.7-1-pve", + "build_info": "(local build)", + "argv": [ + "smartctl", + "-j", + "-H", + "-Afbrief", + "/dev/nvme0" + ], + "exit_status": 0 + }, + "device": { + "name": "/dev/nvme0", + "info_name": "/dev/nvme0", + "type": "nvme", + "protocol": "NVMe" + }, + "smart_status": { + "passed": true, + "nvme": { + "value": 0 + } + }, + "nvme_smart_health_information_log": { + "critical_warning": 0, + "temperature": 35, + "available_spare": 100, + "available_spare_threshold": 10, + "percentage_used": 31, + "data_units_read": 4546105, + "data_units_written": 16623231, + "host_reads": 154011524, + "host_writes": 282144186, + "controller_busy_time": 355, + "power_cycles": 514, + "power_on_hours": 2491, + "unsafe_shutdowns": 38, + "media_errors": 0, + "num_err_log_entries": 0, + "warning_temp_time": 0, + "critical_comp_time": 0, + "temperature_sensors": [ + 36, + 34 + ] + }, + "temperature": { + "current": 35 + }, + "power_cycle_count": 514, + "power_on_time": { + "hours": 2491 + } +} diff --git a/test/disk_tests/nvme_smart/nvme0n1/device b/test/disk_tests/nvme_smart/nvme0n1/device new file mode 120000 index 0000000..e890f3e --- /dev/null +++ b/test/disk_tests/nvme_smart/nvme0n1/device @@ -0,0 +1 @@ +../nvme0 \ No newline at end of file diff --git a/test/disk_tests/nvme_smart/nvme0n1/queue/rotational b/test/disk_tests/nvme_smart/nvme0n1/queue/rotational new file mode 100644 index 0000000..573541a --- /dev/null +++ b/test/disk_tests/nvme_smart/nvme0n1/queue/rotational @@ -0,0 +1 @@ +0 diff --git a/test/disk_tests/nvme_smart/nvme0n1/size b/test/disk_tests/nvme_smart/nvme0n1/size new file mode 100644 index 0000000..83b33d2 --- /dev/null +++ b/test/disk_tests/nvme_smart/nvme0n1/size @@ -0,0 +1 @@ +1000 diff --git a/test/disk_tests/nvme_smart/nvme0n1_smart_expected.json b/test/disk_tests/nvme_smart/nvme0n1_smart_expected.json new file mode 100644 index 0000000..e3f0ce0 --- /dev/null +++ b/test/disk_tests/nvme_smart/nvme0n1_smart_expected.json @@ -0,0 +1,6 @@ +{ + "text" : "available_spare : 100\navailable_spare_threshold : 10\ncontroller_busy_time : 355\ncritical_comp_time : 0\ncritical_warning : 0\ndata_units_read : 4546105\ndata_units_written : 16623231\nhost_reads : 154011524\nhost_writes : 282144186\nmedia_errors : 0\nnum_err_log_entries : 0\npercentage_used : 31\npower_cycles : 514\npower_on_hours : 2491\ntemperature : 35\ntemperature_sensors_0 : 36\ntemperature_sensors_1 : 34\nunsafe_shutdowns : 38\nwarning_temp_time : 0\n", + "health" : "PASSED", + "type" : "text", + "wearout": 69 +} diff --git a/test/disk_tests/nvme_smart/nvme0n1_udevadm b/test/disk_tests/nvme_smart/nvme0n1_udevadm new file mode 100644 index 0000000..36c78ce --- /dev/null +++ b/test/disk_tests/nvme_smart/nvme0n1_udevadm @@ -0,0 +1,18 @@ + +P: /devices/pci0000:00/0000:00:01.1/0000:02:00.0/nvme/nvme0/nvme0n1 +N: nvme0n1 +S: disk/by-id/lvm-pv-uuid-Py4eod-qfzj-i8Q3-Dxu6-xf0Q-H3Wr-w5Fo8V +E: DEVLINKS=/dev/disk/by-id/lvm-pv-uuid-Py4eod-qfzj-i8Q3-Dxu6-xf0Q-H3Wr-w5Fo8V +E: DEVNAME=/dev/nvme0n1 +E: DEVPATH=/devices/pci0000:00/0000:00:01.1/0000:02:00.0/nvme/nvme0/nvme0n1 +E: DEVTYPE=disk +E: ID_FS_TYPE=LVM2_member +E: ID_FS_USAGE=raid +E: ID_FS_UUID=Py4eod-qfzj-i8Q3-Dxu6-xf0Q-H3Wr-w5Fo8V +E: ID_FS_UUID_ENC=Py4eod-qfzj-i8Q3-Dxu6-xf0Q-H3Wr-w5Fo8V +E: ID_FS_VERSION=LVM2 001 +E: MAJOR=259 +E: MINOR=0 +E: SUBSYSTEM=block +E: TAGS=:systemd: +E: USEC_INITIALIZED=3842 diff --git a/test/disk_tests/ssd_smart/disklist b/test/disk_tests/ssd_smart/disklist new file mode 100644 index 0000000..9191c61 --- /dev/null +++ b/test/disk_tests/ssd_smart/disklist @@ -0,0 +1 @@ +sda diff --git a/test/disk_tests/ssd_smart/disklist_expected.json b/test/disk_tests/ssd_smart/disklist_expected.json new file mode 100644 index 0000000..3681cc8 --- /dev/null +++ b/test/disk_tests/ssd_smart/disklist_expected.json @@ -0,0 +1,16 @@ +{ + "sda" : { + "serial" : "000000000000", + "vendor" : "ATA", + "rpm" : 0, + "gpt" : 1, + "health" : "PASSED", + "wearout" : "98", + "osdid" : -1, + "size" : 512000, + "type" : "ssd", + "devpath" : "/dev/sda", + "model" : "Samsung_SSD_860_EVO_1TB", + "wwn" : "0x0000000000000000" + } +} diff --git a/test/disk_tests/ssd_smart/sda/device/vendor b/test/disk_tests/ssd_smart/sda/device/vendor new file mode 100644 index 0000000..531030d --- /dev/null +++ b/test/disk_tests/ssd_smart/sda/device/vendor @@ -0,0 +1 @@ +ATA diff --git a/test/disk_tests/ssd_smart/sda/queue/rotational b/test/disk_tests/ssd_smart/sda/queue/rotational new file mode 100644 index 0000000..573541a --- /dev/null +++ b/test/disk_tests/ssd_smart/sda/queue/rotational @@ -0,0 +1 @@ +0 diff --git a/test/disk_tests/ssd_smart/sda/size b/test/disk_tests/ssd_smart/sda/size new file mode 100644 index 0000000..83b33d2 --- /dev/null +++ b/test/disk_tests/ssd_smart/sda/size @@ -0,0 +1 @@ +1000 diff --git a/test/disk_tests/ssd_smart/sda_smart b/test/disk_tests/ssd_smart/sda_smart new file mode 100644 index 0000000..907e7da --- /dev/null +++ b/test/disk_tests/ssd_smart/sda_smart @@ -0,0 +1,352 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 2 + ], + "svn_revision": "5155", + "platform_info": "x86_64-linux-5.11.7-1-pve", + "build_info": "(local build)", + "argv": [ + "smartctl", + "-j", + "-H", + "-Afbrief", + "/dev/sda" + ], + "exit_status": 0 + }, + "device": { + "name": "/dev/sda", + "info_name": "/dev/sda [SAT]", + "type": "sat", + "protocol": "ATA" + }, + "smart_status": { + "passed": true + }, + "ata_smart_attributes": { + "revision": 1, + "table": [ + { + "id": 5, + "name": "Reallocated_Sector_Ct", + "value": 100, + "worst": 100, + "thresh": 10, + "when_failed": "", + "flags": { + "value": 51, + "string": "PO--CK ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 9, + "name": "Power_On_Hours", + "value": 99, + "worst": 99, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 2463, + "string": "2463" + } + }, + { + "id": 12, + "name": "Power_Cycle_Count", + "value": 99, + "worst": 99, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 499, + "string": "499" + } + }, + { + "id": 177, + "name": "Wear_Leveling_Count", + "value": 98, + "worst": 98, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 19, + "string": "PO--C- ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 20, + "string": "20" + } + }, + { + "id": 179, + "name": "Used_Rsvd_Blk_Cnt_Tot", + "value": 100, + "worst": 100, + "thresh": 10, + "when_failed": "", + "flags": { + "value": 19, + "string": "PO--C- ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 181, + "name": "Program_Fail_Cnt_Total", + "value": 100, + "worst": 100, + "thresh": 10, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 182, + "name": "Erase_Fail_Count_Total", + "value": 100, + "worst": 100, + "thresh": 10, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 183, + "name": "Runtime_Bad_Block", + "value": 100, + "worst": 100, + "thresh": 10, + "when_failed": "", + "flags": { + "value": 19, + "string": "PO--C- ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 187, + "name": "Uncorrectable_Error_Cnt", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 190, + "name": "Airflow_Temperature_Cel", + "value": 73, + "worst": 45, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 27, + "string": "27" + } + }, + { + "id": 195, + "name": "ECC_Error_Rate", + "value": 200, + "worst": 200, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 26, + "string": "-O-RC- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": true, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 199, + "name": "CRC_Error_Count", + "value": 99, + "worst": 99, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 62, + "string": "-OSRCK ", + "prefailure": false, + "updated_online": true, + "performance": true, + "error_rate": true, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 1, + "string": "1" + } + }, + { + "id": 235, + "name": "POR_Recovery_Count", + "value": 99, + "worst": 99, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 18, + "string": "-O--C- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 39, + "string": "39" + } + }, + { + "id": 241, + "name": "Total_LBAs_Written", + "value": 99, + "worst": 99, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 19999585737, + "string": "19999585737" + } + } + ] + }, + "power_on_time": { + "hours": 2515 + }, + "power_cycle_count": 508, + "temperature": { + "current": 29 + } +} diff --git a/test/disk_tests/ssd_smart/sda_smart_expected.json b/test/disk_tests/ssd_smart/sda_smart_expected.json new file mode 100644 index 0000000..36da71e --- /dev/null +++ b/test/disk_tests/ssd_smart/sda_smart_expected.json @@ -0,0 +1,146 @@ +{ + "attributes" : [ + { + "fail" : "-", + "flags" : "PO--CK", + "id" : 5, + "name" : "Reallocated_Sector_Ct", + "raw" : "0", + "threshold" : 10, + "value" : 100, + "worst" : 100 + }, + { + "fail" : "-", + "flags" : "-O--CK", + "id" : 9, + "name" : "Power_On_Hours", + "raw" : "2463", + "threshold" : 0, + "value" : 99, + "worst" : 99 + }, + { + "fail" : "-", + "flags" : "-O--CK", + "id" : 12, + "name" : "Power_Cycle_Count", + "raw" : "499", + "threshold" : 0, + "value" : 99, + "worst" : 99 + }, + { + "fail" : "-", + "flags" : "PO--C-", + "id" : 177, + "name" : "Wear_Leveling_Count", + "raw" : "20", + "threshold" : 0, + "value" : 98, + "worst" : 98 + }, + { + "fail" : "-", + "flags" : "PO--C-", + "id" : 179, + "name" : "Used_Rsvd_Blk_Cnt_Tot", + "raw" : "0", + "threshold" : 10, + "value" : 100, + "worst" : 100 + }, + { + "fail" : "-", + "flags" : "-O--CK", + "id" : 181, + "name" : "Program_Fail_Cnt_Total", + "raw" : "0", + "threshold" : 10, + "value" : 100, + "worst" : 100 + }, + { + "fail" : "-", + "flags" : "-O--CK", + "id" : 182, + "name" : "Erase_Fail_Count_Total", + "raw" : "0", + "threshold" : 10, + "value" : 100, + "worst" : 100 + }, + { + "fail" : "-", + "flags" : "PO--C-", + "id" : 183, + "name" : "Runtime_Bad_Block", + "raw" : "0", + "threshold" : 10, + "value" : 100, + "worst" : 100 + }, + { + "fail" : "-", + "flags" : "-O--CK", + "id" : 187, + "name" : "Uncorrectable_Error_Cnt", + "raw" : "0", + "threshold" : 0, + "value" : 100, + "worst" : 100 + }, + { + "fail" : "-", + "flags" : "-O--CK", + "id" : 190, + "name" : "Airflow_Temperature_Cel", + "raw" : "27", + "threshold" : 0, + "value" : 73, + "worst" : 45 + }, + { + "fail" : "-", + "flags" : "-O-RC-", + "id" : 195, + "name" : "ECC_Error_Rate", + "raw" : "0", + "threshold" : 0, + "value" : 200, + "worst" : 200 + }, + { + "fail" : "-", + "flags" : "-OSRCK", + "id" : 199, + "name" : "CRC_Error_Count", + "raw" : "1", + "threshold" : 0, + "value" : 99, + "worst" : 99 + }, + { + "fail" : "-", + "flags" : "-O--C-", + "id" : 235, + "name" : "POR_Recovery_Count", + "raw" : "39", + "threshold" : 0, + "value" : 99, + "worst" : 99 + }, + { + "fail" : "-", + "flags" : "-O--CK", + "id" : 241, + "name" : "Total_LBAs_Written", + "raw" : "19999585737", + "threshold" : 0, + "value" : 99, + "worst" : 99 + } + ], + "health" : "PASSED", + "type" : "ata" +} diff --git a/test/disk_tests/ssd_smart/sda_udevadm b/test/disk_tests/ssd_smart/sda_udevadm new file mode 100644 index 0000000..f662221 --- /dev/null +++ b/test/disk_tests/ssd_smart/sda_udevadm @@ -0,0 +1,11 @@ +E: DEVNAME=/dev/sda +E: DEVTYPE=disk +E: ID_ATA_ROTATION_RATE_RPM=0 +E: ID_BUS=ata +E: ID_MODEL=Samsung_SSD_860_EVO_1TB +E: ID_PART_TABLE_TYPE=gpt +E: ID_SERIAL=Samsung_SSD_860_EVO_1TB_000000000000000 +E: ID_SERIAL_SHORT=000000000000 +E: ID_TYPE=disk +E: ID_WWN=0x0000000000000000 + diff --git a/test/disklist_test.pm b/test/disklist_test.pm index 7f0e0be..727fb44 100644 --- a/test/disklist_test.pm +++ b/test/disklist_test.pm @@ -34,10 +34,10 @@ sub mocked_run_command { my $dev; my $type; if (@$cmd > 3) { - $dev = $cmd->[5]; + $dev = $cmd->[4]; $type = 'smart'; } else { - $dev = $cmd->[2]; + $dev = $cmd->[3]; $type = 'health'; } $dev =~ s|/dev/||; -- 2.20.1