/
lib
/
raider
/
Raider
/
Info
/
File Upload :
llllll
Current File: //lib/raider/Raider/Info/MegaraidSAS.pm
use strict; use warnings; package Raider::Info::MegaraidSAS; use base qw( Raider::Info ); use JSON::Tiny qw(decode_json encode_json); =head1 NAME Raider::Info::MegaraidSAS - MegaraidSAS specific instructions for get-info =head1 DESCRIPTION MegaraidSAS specific methods to gather information required for populating the .info files. =head1 USAGE use Raider::Info::MegaraidSAS; my $megaraidsasInfo = Raider::Info::MegaraidSAS->new(); =head1 METHODS =head2 get_info() Initiates all needed steps to generate a finished MegaraidSAS info file. =head2 get_disk_info(\%args) Return the disk info. =head2 extract_LD_info(\%) Return information on the given LD. =head2 get_controller_info(\%) Return information on the given controller. =head2 host_supports_info() Given no args, return whether or not this physical host supports get-info collection. Returns: BOOL (1 or 0) =cut use Raider::Jobs::MegaraidSAS; sub get_info { my $self = shift; my $opts = shift; my $jobsMegaraidSAS = Raider::Jobs::MegaraidSAS->new(); my $icmd = $jobsMegaraidSAS->get_icmd(); $jobsMegaraidSAS->icmd_in_path({ icmd => "$icmd" }); my $controller_list_ref = $jobsMegaraidSAS->get_controller_list({ icmd => "$icmd" }); my @controller_list = @$controller_list_ref; my $d_struct_disks = { }; my $d_struct_controllers = { }; my $storm_d_struct = { controllers => { }, }; unless ($self->host_supports_info()) { $self->logger({cat => 'w', msg => "this host doesnt support get-info collection for MegaraidSAS devices; disabling"}); return ($d_struct_controllers,$d_struct_disks,$opts->{cntrl_cnt},$opts->{disk_cnt}); } my $d_struct_map_file_new; for my $controller ( @controller_list ) { my ($cntrl_numarrays,$cntrl_numdrives,$cntrl_firmware,$cntrl_model,$cntrl_serial,$bbu_present,$bbu_state,$cntrl_memory, $cntrl_mem_correctable_errors,$cntrl_mem_uncorrectable_errors) = $self->get_controller_info({ controller => $controller, icmd => $icmd }); my $cntrl_numarrays_end = $cntrl_numarrays; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'identifier'} = "$cntrl_model\:::$cntrl_serial"; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'make'} = 'LSI'; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'model'} = $cntrl_model; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'serial'} = $cntrl_serial; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'firmware'} = $cntrl_firmware; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'numdrives'} = $cntrl_numdrives; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'numlds'} = $cntrl_numarrays; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'bbu_present'} = $bbu_present; if ( $bbu_present ) { $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'bbu_state'} = $bbu_state; } $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'memory'} = $cntrl_memory; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'memory_correctable_errors'} = $cntrl_mem_correctable_errors; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'memory_uncorrectable_errors'} = $cntrl_mem_uncorrectable_errors; $storm_d_struct->{'controllers'}->{ $controller } = { disks => { } }; $storm_d_struct->{'controllers'}->{ $controller }->{'make'} = 'LSI'; $storm_d_struct->{'controllers'}->{ $controller }->{'model'} = $cntrl_model; $storm_d_struct->{'controllers'}->{ $controller }->{'firmware'} = $cntrl_firmware; $storm_d_struct->{'controllers'}->{ $controller }->{'numdrives'} = $cntrl_numdrives; $storm_d_struct->{'controllers'}->{ $controller }->{'numarrays'} = $cntrl_numarrays; $cntrl_numarrays--; ###################### ## PD Level ## ###################### my $dnum = 0; my $dcount = 0; my $d_total; for my $line ( split /^/, `$icmd -AdpAllInfo -a$controller` ) { if ( $line =~ /^\s+Disks(\s+)?:\s+(\d+)/i ) { $d_total = $2; } } my $device_id_to_model_serial_map = {}; my $unidentifiable_disks_cntrl_total_counter = 0; while ( $dcount < $d_total ) { my ($disk_type,$size_mb,$port,$channel,$model,$firmware,$serial,$state,$smart_attribs,$block_device,$device_id,$size_unparsed, $vendor_tool_serial,$vendor_tool_model,$vendor_tool_firmware) = $self->get_disk_info({ controller => $controller, controllers => \@controller_list, phys_disk => $dnum, icmd => $icmd, cntrl_firmware => $cntrl_firmware }); if ( $disk_type ) { if ( $model =~ /^\[No|unknown/i || $serial =~ /^\[No|unknown/i ) { $self->logger({ cat => 'i', msg => "PD [$dnum] not responding to SMART inquiries." }); my $map_file_success = 0; my $vendor_tool_success = 0; # MAP file fallback. if ( $self->map_file_exists({ device => 'megaraidsas_device_map' }) ) { $self->logger({ cat => 'i', msg => "RAIDER MAP entry file exists." }); # Open file, read contents. my $device_map_file = "$Raider::Base::base_conf{'data_path'}/megaraidsas_device_map.info"; open FILE, "<$device_map_file"; my $device_map_file_text = do { local $/; <FILE> }; close(FILE); # Decode. my $d_struct_map_file; eval { $d_struct_map_file = decode_json($device_map_file_text); }; if ( $@ ) { $self->logger({ cat => 'w', msg => "Invalid JSON: [$device_map_file] Cannot decode MAP file!" }); } else { # Check and see if this device is identified in our decoded MAP file. if ( defined($d_struct_map_file->{ "$cntrl_model\:::$cntrl_serial" }->{ "$channel\:::$port" }) ) { $model = $d_struct_map_file->{ "$cntrl_model\:::$cntrl_serial" }->{ "$channel\:::$port" }->{model}; $serial = $d_struct_map_file->{ "$cntrl_model\:::$cntrl_serial" }->{ "$channel\:::$port" }->{serial}; if ( defined($d_struct_map_file->{ "$cntrl_model\:::$cntrl_serial" }->{ "$channel\:::$port" }->{disk_type}) ) { $disk_type = $d_struct_map_file->{ "$cntrl_model\:::$cntrl_serial" }->{ "$channel\:::$port" }->{disk_type}; } $map_file_success = 1; $self->logger({ cat => 'i', msg => "MegaraidSAS: Got model+serial from MAP file." }); } else { $self->logger({ cat => 'w', msg => "No device entry found in MAP file for [$cntrl_model\:::$cntrl_serial -> $channel\:::$port]." }); } } } # Vendor tool fallback. if ( ! $map_file_success && $vendor_tool_serial && $vendor_tool_model) { $model = $vendor_tool_model; $serial = $vendor_tool_serial; $vendor_tool_success = 1; $self->logger({ cat => 'i', msg => "Discovered model+serial from vendor tool." }); } # No MAP file, and cannot get info from Vendor tool. if ( ! $map_file_success && ! $vendor_tool_success ) { $self->logger({ cat => 'w', msg => "PD [$dnum] not responding to SMART inquiries. No RAIDER MAP entry, and cannot get model+serial from vendor tool. Disk will not identify properly!" }); } } if ( $firmware =~ /^\[No|unknown/i ) { $firmware = $vendor_tool_firmware; } # Only add to MAP file and disks key if model-serial is valid. if ( $model !~ /^\[No|unknown/i && $serial !~ /^\[No|unknown/i ) { $d_struct_map_file_new->{ "$cntrl_model\:::$cntrl_serial" }{ "0\:::$port" } = { model => "$model", serial => "$serial", disk_type => "$disk_type" }; $d_struct_disks->{ $opts->{disk_cnt} } = { identifier => "$model\:::$serial", type => $disk_type, size_mb => $size_mb, size_unparsed => $size_unparsed, port => $port, channel => $channel, model => $model, firmware => $firmware, serial => $serial, state => $state, block_device => $block_device, device_id => $device_id }; if ( $smart_attribs ne 'unsupported' ) { $d_struct_disks->{ $opts->{disk_cnt} }->{'smart_attributes'} = $smart_attribs; } # Increment our passed disks counter. $opts->{disk_cnt}++; $device_id_to_model_serial_map->{ $device_id } = "$model\:::$serial"; } else { # Increment unidentifiable_disks counter. $unidentifiable_disks_cntrl_total_counter++; } $storm_d_struct->{'controllers'}->{ $controller }->{'disks'}->{ $dcount } = { type => $disk_type }; $dcount++; } $dnum++; }; # Populate unidentifiable_disks. $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'unidentifiable_disks'} = $unidentifiable_disks_cntrl_total_counter; ###################### ## Unit/array level ## ###################### my @unit_list = map { 0 + $_ } 0..$cntrl_numarrays; my $ldnum_serial_map = {}; for my $each_unit ( @unit_list ) { my $unidentifiable_disks_unit = 0; # Parse -CfgDsply -a$controller and determine what disks belong to $each_unit my $in_group = 0; my @phys_disks_in_unit = (); my $model_serial_key; for my $line ( split /^/, `$icmd -CfgDsply -a$controller` ) { if ( $line =~ /\(Target\s+Id(\s+)?:\s+(\d+)\)/i ) { if ( $2 == $each_unit ) { # This is our disk group, enable. $in_group = 1; next; } else { # This is not our disk group, disable. $in_group = 0; next; } } # Disk is in our unit. Record this. if ( $in_group ) { if ( $line =~ /^Device\s+Id(\s+)?:\s+(\d+)/i ) { my $device_id = $2; if ( $device_id_to_model_serial_map->{ $device_id } ){ # Any PD inside this LD will suffice for checking which block device this LD corresponds with. $model_serial_key = $device_id_to_model_serial_map->{ $device_id }; push(@phys_disks_in_unit, $device_id_to_model_serial_map->{ $device_id }); } else { $unidentifiable_disks_unit++; $self->logger({ cat => 'w', msg => "Failed to map device id [$device_id] to model-serial!" }); } } } } my $health_check = `$icmd -LDInfo -L$each_unit -a$controller`; my $state = $jobsMegaraidSAS->array_is_ok({ health_check => $health_check }); my ($raid_level,$numdrives,$size,$ld_serial,$raid_state,$ld_type,$ld_has_cachecade_enabled,$stripe_size,$size_raw, $ld_cachecade_backed_by_id,$ld_block_device,$disk_cache,$current_cache_policy,$default_cache_policy) = $self->extract_LD_info({ icmd => $icmd, controller => $controller, controllers => \@controller_list, unit => $each_unit, units => \@unit_list }); $ldnum_serial_map->{ $each_unit } = { serial => $ld_serial, ld_type => $ld_type }; # LSI controllers do not export a block device for CacheCade LD's. As a result, # we must identify CacheCade LD's with a different formula. # # --ssullivan May 08, 2013 if ( $ld_type =~ /CacheCade/i ) { $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'logical_disks'}->{ $each_unit } = { identifier => "CacheCade\:::$each_unit", ld_num => $each_unit, type => $ld_type, size_mb => $size, size_unparsed => $size_raw, state => $raid_state, raidlevel => $raid_level, unidentifiable_disks => $unidentifiable_disks_unit, physical_disks => \@phys_disks_in_unit, cachecade_backing_ldnum => $ld_cachecade_backed_by_id, cachecade_backing_ld => "$cntrl_model\:::$cntrl_serial\:::$ldnum_serial_map->{ $ld_cachecade_backed_by_id }->{serial}" }; } else { if ( ! defined($d_struct_controllers->{ $opts->{cntrl_cnt} }->{'logical_disks'}->{ $each_unit }) ) { $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'logical_disks'}->{ $each_unit } = { identifier => "$cntrl_model\:::$cntrl_serial\:::$ld_serial", ld_num => $each_unit, numdrives => $numdrives, raidlevel => $raid_level, state => $raid_state, size_mb => $size, size_unparsed => $size_raw, block_device => $ld_block_device, serial => $ld_serial, type => $ld_type, stripe_size => $stripe_size, cachecade_backed => $ld_has_cachecade_enabled, unidentifiable_disks => $unidentifiable_disks_unit, physical_disks => \@phys_disks_in_unit, disk_cache => $disk_cache, current_cache_policy => $current_cache_policy, default_cache_policy => $default_cache_policy }; } else { $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'identifier' } = "$cntrl_model\:::$cntrl_serial\:::$ld_serial"; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'ld_num' } = $each_unit; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'numdrives' } = $numdrives; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'raidlevel' } = $raid_level; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'state' } = $raid_state; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'size_mb' } = $size; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'size_unparsed' } = $size_raw; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'block_device' } = $ld_block_device; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'serial' } = $ld_serial; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'type' } = $ld_type; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'stripe_size' } = $stripe_size; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'cachecade_backed' } = $ld_has_cachecade_enabled; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'unidentifiable_disks' } = $unidentifiable_disks_unit; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'physical_disks' } = \@phys_disks_in_unit; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'disk_cache' } = $disk_cache; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'current_cache_policy' } = $current_cache_policy; $d_struct_controllers->{ $opts->{cntrl_cnt} }{'logical_disks'}{ $each_unit }{ 'default_cache_policy' } = $default_cache_policy; } } # Provisioning cannot currently handle CacheCade LD (or more than one LD # period it would appear). Solve this for now by fudging the data # structure it looks at to remove CacheCade LDs, and decrement the # numarrays counter, per CacheCade LD. # # TODO: We probably want to fix this someday. # # --ssullivan Jan, 22nd, 2014 if ( $raid_level =~ /CacheCade/i ) { $storm_d_struct->{'controllers'}->{ $controller }->{ 'numarrays' }--; } else { $storm_d_struct->{'controllers'}->{ $controller }->{'arrays'}->{ $each_unit } = { numdrives => $numdrives, raidlevel => $raid_level, state => $state }; } }; # Increment our passed controller count. $opts->{cntrl_cnt}++; }; $self->write_json({data => $storm_d_struct, device => 'megaraidSAS'}); if ( defined($d_struct_map_file_new) ) { $self->write_json({data => $d_struct_map_file_new, device => 'megaraidsas_device_map'}); } return ($d_struct_controllers,$d_struct_disks,$opts->{cntrl_cnt},$opts->{disk_cnt}); } sub extract_LD_info { my $self = shift; my $opts = shift; my ($d,$primary,$size_unit); my $ld_state = 'unknown'; my $ld_type = 'unknown'; my $stripe_size = 'unknown'; my $ld_size_raw = 'unknown'; my $ld_cachecade_backed_by_ld_num = 'unknown'; my $ld_block_device = 'unknown'; my $disk_cache = 'unknown'; my $current_cache_policy = 'unknown'; my $default_cache_policy = 'unknown'; my $ld_has_cachecade_enabled = 0; my $size_mb = 0; my $size_value = 0; for my $line ( split /^/, `$opts->{icmd} -LDInfo -L$opts->{unit} -a$opts->{controller}` ) { if ( $line =~ /^Disk\s+Cache\s+Policy(\s+)?:(\s+)(.+)/i ) { $disk_cache = $3; } if ( $line =~ /^Current\s+Cache\s+Policy(\s+)?:(\s+)(.+)/i ) { $current_cache_policy = $3; } if ( $line =~ /^Default\s+Cache\s+Policy(\s+)?:(\s+)(.+)/i ) { $default_cache_policy = $3; } if ( $line =~ /^Number\s+Of\s+Drives(\s+)?:(\s+)?(\d+)/i || $line =~ /^Number\s+Of\s+Drives\s+per\s+span(\s+)?:(\s+)?(\d+)/i ) { $d = $3; } if ( $line =~ /^RAID\s+Level(\s+)?:\s+Primary-(\d+)/i ) { $primary = $2; } # value and unit have a space between them. if ( $line =~ /^Size(\s+)?:(\s+)?(\S+)\s+(\S+)/i ) { $size_value = $3; $size_unit = $4; } # value and unit have no space between them. elsif ( $line =~ /^Size(\s+)?:(\s+)?(\S+)/i ) { my $size_dump = $3; if ( $size_dump && $size_dump =~ /([[:alpha:]]+)/i ) { $size_unit = $1; $size_dump =~ s/$size_unit//; $size_value = $size_dump; } } if ( $line =~ /^Size(\s+)?:(\s+)?(.+)/i ) { $ld_size_raw = $3; } if ( $line =~ /^State(\s+)?:\s+(.+)/i ) { $ld_state = $2; } if ( $line =~ /^Virtual\s+Drive\s+Type(\s+)?:\s+(\S+)/i ) { $ld_type = $2; } if ( $line =~ /^Cache\s+Cade\s+Type(\s+)?:\s+Read/i ) { $ld_has_cachecade_enabled = 1; } if ( $line =~ /^Strip(\S)?\s+Size(\s+)?:\s+(.+)/i ) { $stripe_size = $3; } # Could be more than one associated LD. if ( $line =~ /^Target\s+Id\s+of\s+the\s+Associated\s+LDs(\s+)?:(\s+)?(.+)/i ) { $ld_cachecade_backed_by_ld_num = $3; } } if ( $ld_type !~ /CacheCade/i ) { $ld_type = 'RAID'; } if ( $opts->{ld_type_only} ) { return $ld_type; } my $num_spans_array; my $ld_found = 0; for my $line ( split /^/, `$opts->{icmd} -LdPdInfo -a$opts->{controller}` ) { if ( $line =~ /Virtual\s+Drive:\s+(\d+)/i || $line =~ /Virtual\s+Disk:\s+(\d+)/i ) { if ( $1 == $opts->{unit} ) { $ld_found = 1; } else { $ld_found = 0; } } if ( $ld_found ) { if ( $line =~ /^Number\s+of\s+Spans(\s+)?:\s+(\d+)/i ) { $num_spans_array = $2; } } } # Drives in array my $num_drives; if ( $d ) { $num_drives = $d * $num_spans_array; } # Raid level if ( $num_spans_array > 1 ) { $primary .= 0; } $size_mb = $self->convert_to_mb({ unit => $size_unit, value => $size_value}); # CacheCade LD's do not have block devices. my $udev_info; if ( $ld_type !~ /CacheCade/i ) { $ld_block_device = $self->find_ld_block_device({ ld_num => $opts->{unit}, device => 'megaraidsas', lds_array => $opts->{units}, icmd => $opts->{icmd}, controller => $opts->{controller}, controllers => $opts->{controllers} }); if ( $ld_block_device !~ /^\/dev\//i ) { $ld_block_device = "/dev/$ld_block_device"; } my $block_device_name; if ( $ld_block_device =~ /^\/dev\/(\S+)/i ) { $block_device_name = $1; } # Get serial of passed LD block device. $udev_info = $self->get_udev_block_device_info({ block_device_name => $block_device_name }); } # MegaCli-4 doesnt support -ShowSummary. But -ShowSummary on megacli-8 and newer always shows CacheCade raid # level as 'CacheCade', so fudge it if not found (where megacli-4 is installed). my $our_ld = 0; for my $line ( split /^/, `$opts->{icmd} -ShowSummary -a$opts->{controller}` ) { if ( $line =~ /^\s+Virtual\s+drive(\s+)?:\s+Target\s+Id\s+(\d+)/i ) { if ( $2 == $opts->{unit} ) { # This is LD we should inspect $our_ld = 1; next; } else { $our_ld = 0; } } if ( $our_ld ) { if ( $line =~ /^\s+State(\s+)?:\s+(.+)/i ) { $ld_state = $2; } if ( $line =~ /^\s+RAID\s+Level(\s+)?:\s+(\S+)/i ) { $primary = $2; } } }; if ( ref($udev_info) eq 'HASH' && $ld_type =~ /CacheCade/i ) { $primary = 'CacheCade'; $udev_info->{id_serial} = 'cachecade_faked'; } my $id_serial = 'unknown'; $id_serial = $udev_info->{id_serial} if ( ref($udev_info) eq 'HASH' ); return ($primary, $num_drives, $size_mb, $id_serial, $ld_state, $ld_type, $ld_has_cachecade_enabled, $stripe_size, $ld_size_raw, $ld_cachecade_backed_by_ld_num, $ld_block_device, $disk_cache, $current_cache_policy, $default_cache_policy); } sub get_disk_info { my $self = shift; my $opts = shift; my $enclosure_id; my $size_unparsed = 'unknown'; if ( ! defined($opts->{cntrl_firmware}) ) { $self->logger({ cat => 'c', msg => "Info/MegaraidSAS: get_disk_info() called with no cntrl_firmware given!" }) } for my $line ( split /^/, `$opts->{icmd} -EncInfo -a$opts->{controller}` ) { if ( $line =~ /^\s+Device\s+ID(\s+)?:\s+(\d+)/i ) { $enclosure_id = $2; } } # If controllers firmware is 2.130.393-2551 or newer, it doesn't like a # space after PhysDrv. If a space is there, it will error. This causes a # infinite loop where we continously look for the phys_disk by incrementing # it over and over. That said, without the space is how its been since the # dawn of RAIDER, so I felt safer only taking the space out if its the # confirmed firmware version I know its broken on with the space or newer. # If its found that the space needs to go away with a firmware older than # the one specified in $base_firmware, modify that variable below to equal # the lowest known firmware version to require the space to not be there. # # --ssullivan Feb 5th, 2014 my $base_firmware = '2.130.393-2551'; $base_firmware =~ s/\D//g; $opts->{cntrl_firmware} =~ s/\D//g; my $pdInfoOut; if ( $enclosure_id ) { if ( $opts->{cntrl_firmware} >= $base_firmware ) { $pdInfoOut = `$opts->{icmd} -PDInfo -PhysDrv[$enclosure_id:$opts->{phys_disk}] -a$opts->{controller}`; } else { $pdInfoOut = `$opts->{icmd} -PDInfo -PhysDrv [$enclosure_id:$opts->{phys_disk}] -a$opts->{controller}`; } } else { if ( $opts->{cntrl_firmware} >= $base_firmware ) { $pdInfoOut = `$opts->{icmd} -PDInfo -PhysDrv[:$opts->{phys_disk}] -a$opts->{controller}`; } else { $pdInfoOut = `$opts->{icmd} -PDInfo -PhysDrv [:$opts->{phys_disk}] -a$opts->{controller}`; } } # We need to initialize dtype as null here. This way we don't increment dnum counter # if there is no physical disk found. my $dtype; my $port = 'unknown'; my $channel = 'unknown'; # Serial, firmware, and model of a disk in a LD can only be found in # the inquiry data section from megacli (or of course smartctl). my $model = 'unknown'; my $firmware = 'unknown'; my $serial = 'unknown'; my $state = 'unknown'; my $ld_block_device = 'unknown'; my $device_id; my $size_value = 0; my $size_unit; my $inq_data_line; for my $line ( split /^/, $pdInfoOut ) { if ( $line =~ /^Device\s+Id(\s+)?:\s+(\d+)/i ) { $device_id = $2; } if ( $line =~ /^PD\s+Type(\s+)?:\s+(\S+)/i ) { $dtype = $2; } if ( $line =~ /^Inquiry\s+Data(\s+)?:\s+(.+)/i ) { $inq_data_line = $line; if ( $line =~ /INTEL|KINGSTON|CRUCIAL/i ) { $dtype = 'SSD'; } } if ( $line =~ /^Raw\s+Size(\s+)?:\s+(\S+)\s+(\S+)/i ) { $size_value = $2; $size_unit = $3; } # Older megacli (version 1.x at least) is hateful and does this: # Raw Size: 572325MB [0x45dd2fb0 Sectors] # So we get to try and catch this as well. if ( $line =~ /^Raw\s+Size(\s+)?:(\s+)?\s+(\S+)\s+\[/i ) { my $size_dump = $3; if ( $size_dump && $size_dump =~ /([[:alpha:]]+)/i ) { $size_unit = $1; $size_dump =~ s/$size_unit//; $size_value = $size_dump; } else { $self->logger({ cat => 'c', msg => "Failed to extract size_dump [$size_dump] from string [$line]" }); } } if ( $line =~ /^Raw\s+Size(\s+)?:(\s+)?(.+)/i ) { $size_unparsed = $3; } if ( $line =~ /^Connected\s+Port\s+Number(\s+)?:\s+(\d+)\(path(\d+)\)/i ) { $port = $2; $channel = $3; } if ( $line =~ /^Firmware\s+state(\s+)?:\s+(.+)/i ) { $state = $2; } } # If device_id is undef, or not >= 0, not a valid device; return. return unless ( defined($device_id) && $device_id >= 0 ); # MegaCli-1.01.39 at least with a MegaRAID SAS 8704ELP doesn't show the PD Type line we # are looking for above. The result is in such a setup we would loop till we met timeout # since $dtype wasn't getting populated. So if $dtype is presently empty, check if we are # on MegaCli less than version 3. We know version 4 shows the output we expect. unless ( $dtype ) { if ( $self->get_megacli_ver({icmd => $opts->{icmd}}) <= 3 ) { # FIXME: I dont see anywhere to get the actual physical disk type if PD Type isn't returned. # Realistically, this only comes up on old MegaCli versions so for now just assume SATA in # this specific case. $dtype = 'SATA'; } else { $self->logger({ cat => 'c', msg => "Info/MegaraidSAS: Unable to detect dtype and MegaCli version is >= 4!" }); } } # -ShowSummary isn't in MegaCli-4; we won't ever get vendor or product ID on MegaCli-4... my $vendor_tool_model; my $vendor_tool_vendor_id; my $is_our_search_disk = 0; for my $line ( split /^/, `$opts->{icmd} -ShowSummary -a$opts->{controller}` ) { if ( $line =~ /\s+Connector(\s+)?:\s+Port\s+$channel\s+-\s+\S+\s+Slot\s+$port/i ) { $is_our_search_disk = 1; } # If we come across this line, but $channel-$port do not match, this isn't our disk. elsif ( $line =~ /\s+Connector(\s+)?:\s+Port\s+\d+\s+-\s+\S+\s+Slot\s+\d+/i ) { $is_our_search_disk = 0; } if ( $is_our_search_disk ) { if ( $line =~ /^\s+Product\s+Id(\s+)?:(.+)/i ) { $vendor_tool_model = $2; } if ( $line =~ /^\s+Vendor\s+Id(\s+)?:(.+)/i ) { $vendor_tool_vendor_id = $2; } } } # Filter out MegaCli-4... my ($vendor_tool_firmware,$vendor_tool_serial); if ( $vendor_tool_model && $vendor_tool_vendor_id ) { my $is_our_search_disk = 0; for my $line ( split /^/, `$opts->{icmd} -PDList -a$opts->{controller}` ) { if ( $line =~ /^Slot\s+Number(\s+)?:\s+$port/i ) { $is_our_search_disk = 1; } elsif ( $line =~ /^Slot\s+Number(\s+)?:\s+\d+/i ) { $is_our_search_disk = 0; } if ( $is_our_search_disk ) { if ( $line =~ /^Device\s+Firmware\s+Level(\s+)?:(.+)/i ) { $vendor_tool_firmware = $2; } } } # The inquiry data line is unreliable. It appears to just be a raw dump from the device, unparsed. # This means field order can and does change from device to device, and some devices dont even have # fields that others do (such as firmware). This logic attempts to account for this. # # Assumption: # vendor_tool_serial = inq_data_line - vendor_tool_vendor_id - vendor_tool_model - vendor_tool_firmware $vendor_tool_serial = $inq_data_line; if ( $vendor_tool_serial =~ /Inquiry\s+Data(\s+)?:(.+)/i ) { $vendor_tool_serial = $2; } $vendor_tool_vendor_id =~ tr/ //ds; $vendor_tool_model =~ tr/ //ds; $vendor_tool_firmware =~ tr/ //ds; $vendor_tool_serial =~ s/$vendor_tool_vendor_id//; $vendor_tool_serial =~ s/$vendor_tool_model//; $vendor_tool_serial =~ s/$vendor_tool_firmware//; $vendor_tool_serial =~ tr/ //ds; $vendor_tool_model =~ tr/ //ds; } if ( $pdInfoOut =~ /Media\s+Type(\s+)?:\s+Solid\s+State\s+Device/i ) { $dtype = 'SSD'; } my $size_mb = $self->convert_to_mb({ unit => $size_unit, value => $size_value }); # Determine a compatible block device to query. my $disc_block_devices_ref = $self->get_block_devices(); my $smart_attribs = 'unsupported'; my $failed_to_get_smart_info = 1; my @block_device_candidates = (); for my $block_device ( @{ $disc_block_devices_ref } ) { last unless ( $failed_to_get_smart_info ); $failed_to_get_smart_info = 1; for my $line ( split /^/, `smartctl -i /dev/$block_device` ) { if ( $line =~ /Vendor(\s+)?:\s+LSI\s+|megaraid|AVAGO|Device(\s+)?:\s+LSI\s+/i ) { push(@block_device_candidates, "/dev/$block_device"); } } } my $candidates_num = scalar(@block_device_candidates); if ( $candidates_num == 1 ) { $ld_block_device = $block_device_candidates[0]; } # More than one LD. else { # Find a block device that belongs to our given controller. $ld_block_device = $self->find_suitable_block_device({ candidate_block_devs => \@block_device_candidates, controller => $opts->{controller}, controllers => $opts->{controllers} }); } if ( $ld_block_device && $ld_block_device !~ /^\/dev\//i ) { $ld_block_device = "/dev/$ld_block_device"; } # Get SMART data, now that we have the block device. $smart_attribs = $self->get_smart_attribs({ device => $ld_block_device, d_flag => "sat+megaraid,$device_id", }); $smart_attribs = 'unsupported' if ( defined($smart_attribs->{error}) ); my $smart_info = $self->get_smart_info({ device => $ld_block_device, d_flag => "sat+megaraid,$device_id", }); for my $line ( split /^/, $smart_info ) { if ( $line =~ /Device\s+Model(\s+)?:(.+)/i ) { $model = $2; $model =~ tr/ //ds; $failed_to_get_smart_info = 0; } if ( $line =~ /Serial\s+Number(\s+)?:(.+)/i ) { $serial = $2; $serial =~ tr/ //ds; $failed_to_get_smart_info = 0; } if ( $line =~ /Firmware\s+Version(\s+)?:(.+)/i ) { $firmware = $2; $firmware =~ tr/ //ds; $failed_to_get_smart_info = 0; } } # If we dont have the smart info we are looking for still, attempt without # SATA specific args. if ( $failed_to_get_smart_info || $model =~ /NoInformationFound/i || $serial =~ /NoInformationFound/i ) { my $smart_info_sas = $self->get_smart_info({ device => $ld_block_device, d_flag => "megaraid,$device_id", }); # $smart_info_sas is going to look like this: # # Vendor: FUJITSU # Product: MBA3147RC # Revision: 0103 # User Capacity: 147,086,327,808 bytes [147 GB] # Logical block size: 512 bytes # Logical Unit id: 0x500000e1171561f0 # Serial number: BJA0PB10GT6W # Device type: disk # Transport protocol: SAS # Local Time is: Wed Apr 1 16:18:07 2015 CEST # Device supports SMART and is Enabled # Temperature Warning Enabled # Informational Exceptions (SMART) enabled # Temperature warning enabled for my $line ( split /^/, $smart_info_sas ) { if ( $line =~ /^Product(\s+)?:(.+)/i ) { $model = $2; $model =~ tr/ //ds; $failed_to_get_smart_info = 1; } if ( $line =~ /^Serial\s+number(\s+)?:(.+)/i ) { $serial = $2; $serial =~ tr/ //ds; $failed_to_get_smart_info = 1; } # Firmware version is not shown in this output.. $firmware = 'unknown'; } } if ( $failed_to_get_smart_info ) { $self->logger({ cat => 'w', msg => "failed to get SMART info for device id [$device_id] block device [$ld_block_device]." }); $failed_to_get_smart_info = 1; } return ($dtype,$size_mb,$port,$channel,$model,$firmware,$serial,$state,$smart_attribs,$ld_block_device,$device_id,$size_unparsed,$vendor_tool_serial,$vendor_tool_model,$vendor_tool_firmware); } sub get_megacli_ver { my $self = shift; my $opts = shift; for my $line ( split/^/, `$opts->{icmd} -v` ) { if ( $line =~ /\s+Ver\s+(\d+)\.\d+/ ) { return $1; } } $self->logger({ cat => 'c', msg => 'get_megacli_ver(); failed to detect MegaCli version' }); } sub get_controller_info { my $self = shift; my $opts = shift; my $array_count; my $disk_count; my $cntrl_firmware = 'unknown'; my $cntrl_model = 'unknown'; my $cntrl_serial = 'unknown'; my $bbu_present = 0; my $bbu_state = 'unknown'; my $cntrl_memory = 'unknown'; my $cntrl_memory_correctable_errors = 0; my $cntrl_memory_uncorrectable_errors = 0; for my $line ( split /^/, `$opts->{icmd} -AdpAllInfo -a$opts->{controller}` ) { if ( $line =~ /^Virtual\s+Drives(\s+)?:\s+(\d+)/i ) { $array_count = $2; } elsif ( $line =~ /^\s+Disks(\s+)?:\s+(\d+)/i ) { $disk_count = $2; } elsif ( $line =~ /^FW\s+Version(\s+)?:\s+(\S+)/i ) { $cntrl_firmware = $2; } elsif ( $line =~ /^Product\s+Name(\s+)?:\s+(.+)/i ) { $cntrl_model = $2; $cntrl_model =~ tr/ //ds; } elsif ( $line =~ /^Serial\s+No(\s+)?:\s+(\S+)/i ) { $cntrl_serial = $2; } elsif ( $line =~ /^BBU(\s+)?:\s+Present/i ) { $bbu_present = 1; my $bbu_check_cmd = `$opts->{icmd} -AdpBbuCmd -GetBbuStatus -a$opts->{controller}`; if ( $bbu_check_cmd =~ /Battery\s+State(\s+)?:\s+(.+)/i ) { $bbu_state = $2; } } elsif ( $line =~ /^Memory\s+Size(\s+)?:\s+(\S+)/i ) { $cntrl_memory = $2; } elsif ( $line =~ /^Memory\s+Correctable\s+Errors(\s+)?:\s+(.+)/i ) { $cntrl_memory_correctable_errors = $2; } elsif ( $line =~ /^Memory\s+Uncorrectable\s+Errors(\s+)?:\s+(.+)/i ) { $cntrl_memory_uncorrectable_errors = $2; } } $cntrl_memory_correctable_errors = $self->strip_whitespace({ string => $cntrl_memory_correctable_errors }); $cntrl_memory_uncorrectable_errors = $self->strip_whitespace({ string => $cntrl_memory_uncorrectable_errors }); # If empty, set to error. $cntrl_model = 'error' if ( $cntrl_model !~ /\S/ ); $cntrl_serial = 'error' if ( $cntrl_serial !~ /\S/ ); return ($array_count,$disk_count,$cntrl_firmware,$cntrl_model,$cntrl_serial,$bbu_present,$bbu_state,$cntrl_memory,$cntrl_memory_correctable_errors,$cntrl_memory_uncorrectable_errors); } sub host_supports_info { my ($self) = @_; return 1; } 1;
Copyright ©2k19 -
Hexid
|
Tex7ure