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 UTF8SMTPS id 81F867AC7A for ; Mon, 10 May 2021 14:21:17 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with UTF8SMTP id 7E96318486 for ; Mon, 10 May 2021 14:21:17 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (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 UTF8SMTPS id 4BEBF18478 for ; Mon, 10 May 2021 14:21:15 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with UTF8SMTP id 2341E459E3; Mon, 10 May 2021 14:21:15 +0200 (CEST) Message-ID: <6fbe66e5-0ecb-6f21-57e6-89f9b6828571@proxmox.com> Date: Mon, 10 May 2021 14:21:12 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:89.0) Gecko/20100101 Thunderbird/89.0 Content-Language: en-US To: Proxmox VE development discussion , Oguz Bektas References: <20210401134055.701355-1-o.bektas@proxmox.com> <20210401142402.819548-1-o.bektas@proxmox.com> From: Dominik Csapak In-Reply-To: <20210401142402.819548-1-o.bektas@proxmox.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.131 Adjusted score from AWL reputation of From: address KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment NICE_REPLY_A -0.001 Looks like a legit reply (A) POISEN_SPAM_PILL 0.1 Meta: its spam POISEN_SPAM_PILL_1 0.1 random spam to be learned in bayes POISEN_SPAM_PILL_3 0.1 random spam to be learned in bayes SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: Re: [pve-devel] [PATCH v2 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: Mon, 10 May 2021 12:21:17 -0000 some comments inline On 4/1/21 16:24, Oguz Bektas wrote: > adapt the smartctl endpoint to run smartctl with the --json or -j flag > to parse it more reasonably. > > additionally 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 old json fields but with the parsed key:value pairs in the 'text' > field 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 > --- > v1->v2: > * fixed bug with --format json not showing anything... > > > PVE/API2/Disks.pm | 9 +- > PVE/Diskmanage.pm | 119 +++--- > 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(+), 57 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..2fe70bc 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,80 @@ 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; any particular reason to change this line? i think it makes it harder to read what flags we give (-Afbrief vs -A -f brief) > 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 = $@; > + > + 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}; > + } > > -# 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; > + my $add_key = sub { > + my ($key, $value) = @_; > + $smartdata->{text} .= "$key : $value\n"; > + }; > + > + if ($format eq 'text') { > + 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]); > + } while this is ok, we probably could also do a 'pretty-print' json output here in case $value is not a scalar that way we would also catch (potential) objects, not only arrays (though i do not know if that can happen) > } 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; > + $add_key->($key, $value); > } > - } elsif ($line =~ m/SMART Disabled/) { > - $smartdata->{health} = "SMART Disabled"; > } > - }); > - }; > - my $err = $@; > + } else { > + $smartdata->{properties} = $nvme_info; > + } > + } 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) { again, any reason to change this? especially the comment about the return code ? > 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/||; >