[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