[pve-devel] [PATCH v2 storage 2/2] smartctl: use json parsing
Dominik Csapak
d.csapak at proxmox.com
Mon May 10 14:21:12 CEST 2021
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 <o.bektas at proxmox.com>
> ---
> 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/||;
>
More information about the pve-devel
mailing list