/
lib
/
raider
/
Raider
/
Info
/
File Upload :
llllll
Current File: //lib/raider/Raider/Info/Adaptec.pm
use strict; use warnings; package Raider::Info::Adaptec; use base qw( Raider::Info ); use Raider::Jobs::Adaptec; use JSON::Tiny qw(decode_json encode_json); =head1 NAME Raider::Info::Adaptec - Adaptec specific instructions for get-info =head1 DESCRIPTION Adaptec specific methods to gather information required for populating the .info file. =head1 USAGE use Raider::Info::Adaptec; my adaptecInfo = Raider::Info::Adaptec->new(); =head1 METHODS =head1 get_info() Initiates all needed steps to generate a finished Adaptec info file. =head2 get_disk_info(\%) Return info of a disk. =head2 extract_LD_info(\%) Return information on the given LD. =head2 get_controller_attribute(\%args) Return the specified attribute. =head2 count_arrays(\%args) Return the amount of present arrays. =head2 count_disks(\%args) Return the amount of present disks. =head2 host_supports_info() Given no args, return whether or not this physical host supports get-info collection. Returns: BOOL (1 or 0) =cut my $icmd = '/usr/StorMan/arcconf'; sub get_info { my $self = shift; my $opts = shift; my $jobsAdaptec = Raider::Jobs::Adaptec->new(); $jobsAdaptec->icmd_in_path({ icmd => "$icmd" }); my $controller_list_ref = $jobsAdaptec->get_controller_list(); my @controller_list = @$controller_list_ref; my $d_struct_controllers = { }; my $d_struct_disks = { }; my $storm_d_struct = { controllers => { }, }; unless ($self->host_supports_info()) { $self->logger({cat => 'w', msg => "this host doesnt support get-info collection for Adaptec 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_model = $self->get_controller_attribute({ controller => $controller, attrib => 'model' }); $cntrl_model =~ tr/ //ds; my $cntrl_firmware = $self->get_controller_attribute({ controller => $controller, attrib => 'firmware' }); my $cntrl_serial = $self->get_controller_attribute({ controller => $controller, attrib => 'serial' }); my $cntrl_memory = $self->get_controller_attribute({ controller => $controller, attrib => 'memory' }); my $cntrl_temp = $self->get_controller_attribute({ controller => $controller, attrib => 'temp' }); my $cntrl_numdrives = $self->count_disks({ controller => "$controller" }); my $cntrl_numarrays = $self->count_arrays({ controller => "$controller" }); $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'identifier'} = "$cntrl_model\:::$cntrl_serial"; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'make'} = 'Adaptec'; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'model'} = $cntrl_model; $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} }->{'serial'} = $cntrl_serial; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'memory'} = $cntrl_memory; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'temperature'} = $cntrl_temp; $storm_d_struct->{'controllers'}->{ $controller } = { disks => { } }; $storm_d_struct->{'controllers'}->{ $controller }->{'make'} = 'Adaptec'; $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; my $serial_map_to_model = {}; my ($bbu_present,$bbu_status) = $self->controller_bbu_present({ controller => $controller }); $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'bbu_present'} = $bbu_present; if ( $bbu_present ) { $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'bbu_state'} = $bbu_status; } ## Disk Info ################################ my $unidentifiable_disks_cntrl_total_counter = 0; my $dnum = 1; my $d_total = $self->count_disks({ controller => $controller }); while ( $dnum <= $d_total ) { my ($disk_type,$size_mb,$port,$channel,$model,$firmware,$serial,$state,$smart_attribs,$block_device,$size_unparsed,$write_cache) = $self->get_disk_info({ controller => $controller, phys_disk => $dnum }); if ( $model =~ /^\[No|unknown/i || $serial =~ /^\[No|unknown/i ) { $self->logger({ cat => 'i', msg => "PD [$dnum] not responding to SMART inquiries." }); if ( $self->map_file_exists({ device => 'adaptec_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'}/adaptec_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}; } $self->logger({ cat => 'i', msg => "Adaptec: 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]." }); } } } else { $self->logger({ cat => 'w', msg => "PD [$dnum] not responding to SMART inquiries, and no RAIDER MAP entry. Disk will not identify properly!" }); } } # 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" }{ "$channel\:::$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, write_cache => $write_cache }; if ( $smart_attribs ne 'unsupported' ) { $d_struct_disks->{ $opts->{disk_cnt} }->{'smart_attributes'} = $smart_attribs; } # Increment our passed disk count. $opts->{disk_cnt}++; } else { # Increment unidentifiable_disks counter. $unidentifiable_disks_cntrl_total_counter++; } $storm_d_struct->{'controllers'}->{ $controller }->{'disks'}->{ $dnum } = { type => $disk_type }; $serial_map_to_model->{ $serial } = { model => $model }; $dnum++; }; # Populate unidentifiable_disks. $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'unidentifiable_disks'} = $unidentifiable_disks_cntrl_total_counter; ## Array Info ################################ my $unit_list_ref = $jobsAdaptec->get_array_list({ c => $controller }); my @unit_list = @{ $unit_list_ref }; for my $each_unit ( @unit_list ) { my $unidentifiable_disks_unit = 0; my $health_check = `$icmd getconfig $controller LD $each_unit`; my $state = $jobsAdaptec->array_is_ok({ health_check => $health_check }); my ($raid_level,$numdrives,$size,$block_device,$serial,$raid_state, $ld_type,$stripe_size,$size_unparsed,$read_cache,$write_cache) = $self->extract_LD_info({ controller => $controller, controllers => \@controller_list, unit => $each_unit, units => \@unit_list }); if ( ! defined($raid_level) ) { next; } $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'logical_disks'}->{ $each_unit } = { identifier => "$cntrl_model\:::$cntrl_serial\:::$serial", ld_num => $each_unit, numdrives => $numdrives, raidlevel => $raid_level, state => $raid_state, size_mb => $size, size_unparsed => $size_unparsed, stripe_size => $stripe_size, block_device => $block_device, serial => $serial, type => $ld_type, read_cache => $read_cache, write_cache => $write_cache }; $storm_d_struct->{'controllers'}->{ $controller }->{'arrays'}->{ $each_unit } = { numdrives => $numdrives, raidlevel => $raid_level, state => $state }; # Record PD serials in this unit where possible. If the disk is bad, it won't show the serial. # As a result, if that scenario is found we increase the unit level unidentifiable_disks counter. my @disks_in_unit_serials = (); for my $line ( split /^/, `$icmd getconfig $controller LD $each_unit` ) { if ( $line =~ /Segment.+\)\s+(\S+)/i ) { push(@disks_in_unit_serials, $1); } elsif ( $line =~ /Segment\s+(\d+)(\s+)?:.+/i ) { $unidentifiable_disks_unit++; } } # Populate arrays disks.. my @phys_disks_in_unit = (); for my $search_serial ( @disks_in_unit_serials ) { if ( $serial_map_to_model->{ $search_serial } ) { my $phys_disk_model = $serial_map_to_model->{ $search_serial }->{model}; push(@phys_disks_in_unit, "$phys_disk_model\:::$search_serial"); } else { $self->logger({ cat => 'c', msg => "Cannot find model for search serial [$search_serial]" }); } } $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; }; # Incrememt passed controller count. $opts->{cntrl_cnt}++; }; $self->write_json({data => $storm_d_struct, device => 'adaptec'}); if ( defined($d_struct_map_file_new) ) { $self->write_json({data => $d_struct_map_file_new, device => 'adaptec_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 ($udev_info,$raid_level,$num_drives,$size_unparsed,$size_value,$size_unit,$block_device_name); my $block_device = 'unknown'; my $raid_state = 'unknown'; my $ld_type = 'unknown'; my $write_cache = 'unknown'; my $read_cache = 'unknown'; # RAID 1's don't have stripe size my $stripe_size = 'N/A'; my $size_mb = 0; for my $line ( split /^/, `$icmd getconfig $opts->{controller} LD $opts->{unit}` ) { if ( $line =~ /Segment\s+\d+\s+:/i ) { $num_drives++; } if ( $line =~ /RAID\s+level\s+:\s+(\S+)/i ) { $raid_level = $1; $ld_type = 'RAID'; } if ( $line =~ /^\s+Size(\s+)?:(\s+)?(\d+)\s+(\S+)/i ) { $size_value = $3; $size_unit = $4; } if ( $line =~ /^\s+Size(\s+)?:(\s+)?(.+)/i ) { $size_unparsed = $3; } if ( $line =~ /Stripe-unit\s+size(\s+)?:(\s+)?(.+)/i ) { $stripe_size = $3; } if ( $line =~ /Status\s+of\s+logical\s+device(\s+)?:\s+(\S+)/i ) { $raid_state = $2; } if ( $line =~ /Read-cache\s+setting(\s+)?:(\s+)?(.+)/i ) { $read_cache = $3; } if ( $line =~ /Write-cache\s+setting(\s+)?:(\s+)?(.+)/i ) { $write_cache = $3; } } if ( defined($size_mb) && defined($size_unit) ) { $size_mb = $self->convert_to_mb({ unit => $size_unit, value => $size_value }); } # Find block device of our LD if ( defined($raid_level) ) { $block_device = $self->find_ld_block_device({ ld_num => $opts->{unit}, device => 'adaptec', lds_array => $opts->{units}, icmd => $icmd, controller => $opts->{controller}, controllers => $opts->{controllers} }); if ( $block_device !~ /^\/dev\//i ) { $block_device = "/dev/$block_device"; } $block_device_name = $block_device; $block_device_name =~ s/\/dev\///g; # Get serial of our LD $udev_info = $self->get_udev_block_device_info({ block_device_name => $block_device_name }); } my $id_serial = 'unknown'; $id_serial = $udev_info->{id_serial} if ( ref($udev_info) eq 'HASH' ); return ($raid_level,$num_drives,$size_mb,$block_device,$id_serial,$raid_state,$ld_type,$stripe_size,$size_unparsed,$read_cache,$write_cache); } sub get_disk_info { my $self = shift; my $opts = shift; my $dtype = 'unknown'; my $vendor = 'unknown'; my $model = 'unknown'; my $port = 'unknown'; my $channel = 'unknown'; my $firmware = 'unknown'; my $serial = 'unknown'; my $state = 'unknown'; my $block_device = 'unknown'; my $size_unit = 'unknown'; my $size_unparsed = 'unknown'; my $ssd_check = 'No'; my $write_cache = 'unknown'; my $size = 0; my $size_mb = 0; my $disk_match_count = 0; for my $line ( split /^/, `$icmd getconfig $opts->{controller} PD` ) { if ( $line =~ /^\s+State/ ) { $disk_match_count++; } # Only collect our data if the passthrough is for the physdisk. if ( $opts->{phys_disk} == $disk_match_count ) { if ( $line =~ /^\s+Write\s+Cache(\s+)?:\s+(.+)/i ) { $write_cache = $2; } if ( $line =~ /^\s+Transfer\s+Speed\s+:\s+([A-z]+)/i ) { $dtype = $1; } if ( $line =~ /^\s+Vendor\s+:\s+([A-z]+)/i ) { $vendor = $1; } if ( $line =~ /^\s+SSD\s+:\s+([A-z]+)/i ) { $ssd_check = $1; } if ( $line =~ /^\s+Model(\s+)?:(.+)/i ) { $model = $2; $model =~ tr/ //ds; } if ( $line =~ /^\s+Firmware(\s+)?:(.+)/i ) { $firmware = $2; $firmware =~ tr/ //ds; } if ( $line =~ /^\s+Serial\s+Number(\s+)?:(.+)/i ) { $serial = $2; $serial =~ tr/ //ds; } if ( $line =~ /^\s+State(\s+)?:\s+(\S+)/i ) { $state = $2; } # arrconf B20618 (and newer?) have 'Total' in the front here.. if ( $line =~ /^\s+Size(\s+)?:\s+(\d+)\s+(\S+)/i || $line =~ /^\s+Total\s+Size(\s+)?:\s+(\d+)\s+(\S+)/i ) { $size = $2; $size_unit = $3; } # arrconf B20618 (and newer?) have 'Total' in the front here.. if ( $line =~ /^\s+Size(\s+)?:(\s+)?(.+)/i || $line =~ /^\s+Total\s+Size(\s+)?:(\s+)?(.+)/i ) { $size_unparsed = $3; } if ( $line =~ /\s+Reported\s+Location(\s+)?:\s+Connector\s+(\d+),\s+Device\s+(\d+)/i ) { $channel = $2; $port = $3; } } } $size_mb = $self->convert_to_mb({ unit => $size_unit, value => $size }); if ( $vendor =~ /intel|crucial|kingston/i || $ssd_check =~ /Yes/i || $model =~ /M4-CT|SSD|KINGSTON|C300-/i ) { $dtype = 'SSD'; } my $smart_attribs = 'unsupported'; for my $disc_sg_device ( @{ $self->get_sg_devices() } ) { if ( ! -e "/dev/sg$disc_sg_device" ) { $self->logger({ cat => 'c', msg => "Discovered sg device (/dev/sg$disc_sg_device) does not exist!" }); } my $d_sat_success = 0; for my $line ( split /^/, `smartctl -d sat -i /dev/sg$disc_sg_device -T permissive` ) { if ( $line =~ /Serial\s+number(\s+)?:\s+(\S+)/i ) { if ( $2 eq $serial ) { $block_device = "/dev/sg$disc_sg_device"; $smart_attribs = $self->get_smart_attribs({ device => $block_device, d_flag => 'sat' }); $d_sat_success = 1; $smart_attribs = 'unsupported' if ( defined($smart_attribs->{error}) ); } } } unless ( $d_sat_success ) { for my $line ( split /^/, `smartctl -i /dev/sg$disc_sg_device -T permissive` ) { if ( $line =~ /Serial\s+number(\s+)?:\s+(\S+)/i ) { if ( $2 eq $serial ) { $block_device = "/dev/sg$disc_sg_device"; $smart_attribs = $self->get_smart_attribs({ device => $block_device, d_flag => 'sat' }); $smart_attribs = 'unsupported' if ( defined($smart_attribs->{error}) ); } } } } } return ($dtype, $size_mb, $port, $channel, $model, $firmware, $serial, $state, $smart_attribs, $block_device, $size_unparsed, $write_cache); } sub get_sg_devices { my $self = shift; my $opts = shift; my @sg_devices; for my $line ( split /^/, `sginfo -l` ) { if ( $line =~ /\/dev\/sg(\d+)\s+/i ) { push(@sg_devices, $1); } } return \@sg_devices; } sub get_controller_attribute { my $self = shift; my $opts = shift; my $cntrl_attrib; for my $line ( split /^/, `$icmd getconfig $opts->{controller} AD` ) { if ( $opts->{attrib} eq 'model' ) { if ( $line =~ /Controller\s+Model(\s+)?:(.+)/i ) { $cntrl_attrib = $2; } } elsif ( $opts->{attrib} eq 'firmware' ) { if ( $line =~ /Firmware(\s+)?:(.+)/i ) { $cntrl_attrib = $2; } } elsif ( $opts->{attrib} eq 'serial' ) { if ( $line =~ /Controller\s+Serial\s+Number(\s+)?:(.+)/i ) { $cntrl_attrib = $2; } } elsif ( $opts->{attrib} eq 'memory' ) { if ( $line =~ /Installed\s+Memory(\s+)?:(.+)/i ) { $cntrl_attrib = $2; } } elsif ( $opts->{attrib} eq 'temp' ) { if ( $line =~ /Temperature(\s+)?:(.+)/i ) { $cntrl_attrib = $2; } } } $cntrl_attrib = $self->strip_whitespace({ string => $cntrl_attrib }); # If empty, set to error. $cntrl_attrib = 'error' if ( $cntrl_attrib !~ /\S/ ); return $cntrl_attrib; } sub count_disks { my $self = shift; my $opts = shift; # Turns out, the assumption an entry for Device\s+#\d+ equals a physical # device is not valid. We can have entries like this: # # Device #8 # Device is an Enclosure services device # # Account for this by not incrementing disk_count if the PD section has the # above string. # ~ssullivan June 9th, 2015 my $disk_count = 0; my @ctrl_pds = split(/Device\s+#\d+/, `$icmd getconfig $opts->{controller} PD` ); for my $entry ( @ctrl_pds ) { # Skip the first bogus entry in slot 0. next if ( $entry =~ /controllers\s+found/i ); # Increment disk_count unless its an enclosure. $disk_count++ unless ( $entry =~ /Device\s+is\s+an\s+Enclosure/i ); } return $disk_count; } sub count_arrays { my $self = shift; my $opts = shift; my $utotal = 0; my $lg_device_num; for my $line ( split /^/, `$icmd getconfig $opts->{controller} LD` ) { if ( $line =~ /Logical\s+device\s+number\s+(\d+)/i ) { $utotal++; $lg_device_num = $1; } } if ( $utotal == 1 && $lg_device_num != 0 ) { return $lg_device_num; } else { return $utotal; } } sub controller_bbu_present { my ($self,$opts) = @_; my $bbu_check_cmd = `$icmd getconfig $opts->{controller} AD`; # if ZMM information shows up there is no BBU if ($bbu_check_cmd !~ /\s+Status(\s+)?:\s+Not\s+Installed/i && $bbu_check_cmd !~ /Controller\s+ZMM\s+Information/i) { for my $line ( split /^/, $bbu_check_cmd ) { if ( $line =~ /^\s+Status(\s+)?:\s+(.+)/i ) { return (1,$2); } } } return (0,'unknown'); } sub host_supports_info { my ($self) = @_; return 1; } 1;
Copyright ©2k19 -
Hexid
|
Tex7ure