/
lib
/
raider
/
Raider
/
Info
/
File Upload :
llllll
Current File: //lib/raider/Raider/Info/3ware.pm
use strict; use warnings; package Raider::Info::3ware; use base qw( Raider::Info ); use Raider::Jobs::3ware; use JSON::Tiny qw(decode_json encode_json); =head1 NAME Raider::Info::3ware - 3ware specific instructions for get-info =head1 DESCRIPTION 3ware specific methods to gather information required for populating the .info file. =head1 USAGE use Raider::Info::3ware; my $info3ware = Raider::Info::3ware->new(); =head1 METHODS =head2 get_info() Initiates all needed steps to generate a finished 3ware info file. =head2 get_disk_info(\%) Return the info of a disk. =head2 extract_LD_info(\%) Return info on a LD. =head2 get_controller_attribute(\%args) Return the specified attribute. =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/local/bin/tw_cli'; sub get_info { my $self = shift; my $opts = shift; my $jobs3ware = Raider::Jobs::3ware->new(); $jobs3ware->icmd_in_path({ icmd => "$icmd" }); my $controller_list_ref = $jobs3ware->get_controller_list(); 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 3ware 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 $controller_num = $controller; $controller_num =~ s/\D//g; # remove non-numeric characters. 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_numdrives = $self->get_controller_attribute({ controller => "$controller", attrib => 'numdrives' }); my $cntrl_numarrays = $self->get_controller_attribute({ controller => "$controller", attrib => 'numunits' }); my $cntrl_serial = $self->get_controller_attribute({ controller => $controller, attrib => 'serial' }); my $cntrl_memory; for my $line ( split /^/, `$icmd info $controller diag` ) { if ( $line =~ /^###\s+Memory\s+Installed(\s+)?:\s+(.+)/i ) { $cntrl_memory = $2; } } $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'identifier'} = "$cntrl_model\:::$cntrl_serial"; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'make'} = '3ware'; $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; # Fudge this since none of our legacy 3ware 8000 series cards have BBU... $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'bbu_present'} = 0; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'memory'} = $cntrl_memory; $storm_d_struct->{'controllers'}->{ $controller_num } = { disks => { } }; $storm_d_struct->{'controllers'}->{ $controller_num }->{'make'} = '3ware'; $storm_d_struct->{'controllers'}->{ $controller_num }->{'model'} = $cntrl_model; $storm_d_struct->{'controllers'}->{ $controller_num }->{'firmware'} = $cntrl_firmware; $storm_d_struct->{'controllers'}->{ $controller_num }->{'numdrives'} = $cntrl_numdrives; $storm_d_struct->{'controllers'}->{ $controller_num }->{'numarrays'} = $cntrl_numarrays; if ( ! defined($d_struct_map_file_new->{ "$cntrl_model\:::$cntrl_serial" }) ) { $d_struct_map_file_new = { "$cntrl_model\:::$cntrl_serial" => {} }; } my $cntrl_info = `$icmd info $controller`; my @unit_list = (); for my $line ( split /^/, $cntrl_info ) { if ( $line =~ /^(u\d+)\s+RAID-\d+/i ) { push(@unit_list, $1); } } my @phys_disk_list = (); for my $line ( split /^/, $cntrl_info ) { if ( $line =~ /^(p\d+)\s+/i ) { if ( $line !~ /NOT-PRESENT/i ) { push(@phys_disk_list, $1); } } } for my $each_unit ( @unit_list ) { my $each_unit_stripped = $each_unit; $each_unit_stripped =~ s/\D//g; # remove non-numeric characters. my @phys_disks_in_unit = (); my $unidentifiable_disks_unit = 0; # Get port(s) assigned to $each_unit. for my $line ( split /^/, $cntrl_info ) { if ( $line =~ /^(p\d+)\s+\S+\s+$each_unit\s+/i ) { my $port = $1; my ($serial,$model); for my $line ( split /^/, `$icmd /$controller/$port show all` ) { if ( $line =~ /^\S+\s+Serial\s+=\s+(\S+)/i ) { $serial = $1; } # If no serial, it's not identifiable. elsif ( $line =~ /^\S+\s+Serial\s+=.+/i ) { $unidentifiable_disks_unit++; } elsif ( $line =~ /^\S+\s+Model\s+=\s+(\S+)/i ) { $model = $1; } } if ( defined($model) && defined($serial) ) { push(@phys_disks_in_unit, "$model\:::$serial"); } } } my $health_check = `$icmd info $controller $each_unit`; my $state = $jobs3ware->array_is_ok({ health_check => $health_check }); my ($raid_level,$numdrives,$size,$block_device,$raid_state,$stripe_size,$size_unparsed) = $self->extract_LD_info({ controller => $controller, unit => $each_unit }); # We don't identify 3ware LD's by serial like we do for LSI or Adaptec because 3ware 8000 series cards (which is all our current 3ware stock) don't support # serial identification for a LD (9000 series appear to FYI). Instead, we just identify by unit number here. # --ssullivan May 6th, 2013 $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'logical_disks'}->{ $each_unit_stripped } = { identifier => "$cntrl_model\:::$cntrl_serial\:::$each_unit_stripped", numdrives => $numdrives, ld_num => $each_unit_stripped, type => 'RAID', stripe_size => $stripe_size, raidlevel => $raid_level, state => $raid_state, size_mb => $size, size_unparsed => $size_unparsed, block_device => $block_device }; # Populate arrays disks.. $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'logical_disks'}->{ $each_unit_stripped }->{'unidentifiable_disks'} = $unidentifiable_disks_unit; $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'logical_disks'}->{ $each_unit_stripped }->{physical_disks} = \@phys_disks_in_unit; $storm_d_struct->{'controllers'}->{ $controller_num }->{'arrays'}->{ $each_unit_stripped } = { numdrives => $numdrives, raidlevel => $raid_level, state => $state }; }; my $unidentifiable_disks_cntrl_total_counter = 0; for my $each_phys_disk ( @phys_disk_list ) { my $disk_num = $each_phys_disk; $disk_num =~ s/[A-z]//g; my ($disk_type,$size_mb,$port,$model,$firmware,$serial,$state,$smart_attribs, $block_device,$device_id,$size_unparsed) = $self->get_disk_info({ controller => $controller, phys_disk => $each_phys_disk }); if ( $model =~ /^\[No|unknown/i || $serial =~ /^\[No|unknown/i ) { $self->logger({ cat => 'i', msg => "PD [$disk_num] not responding to SMART inquiries." }); if ( $self->map_file_exists({ device => '3ware_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'}/3ware_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" }->{ "0\:::$port" }) ) { $model = $d_struct_map_file->{ "$cntrl_model\:::$cntrl_serial" }->{ "0\:::$port" }->{model}; $serial = $d_struct_map_file->{ "$cntrl_model\:::$cntrl_serial" }->{ "0\:::$port" }->{serial}; if ( defined($d_struct_map_file->{ "$cntrl_model\:::$cntrl_serial" }->{ "0\:::$port" }->{disk_type}) ) { $disk_type = $d_struct_map_file->{ "$cntrl_model\:::$cntrl_serial" }->{ "0\:::$port" }->{disk_type}; } $self->logger({ cat => 'i', msg => "3ware: Got model+serial from MAP file." }); } else { $self->logger({ cat => 'w', msg => "No device entry found in MAP file for [0\:::$port]." }); } } } else { $self->logger({ cat => 'w', msg => "PD [$disk_num] 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" }{ "0\:::$port" } = { model => "$model", serial => "$serial", disk_type => "$disk_type" }; # Our 3ware cards (8000 series) only have single channel, so hard code for now. $d_struct_disks->{ $opts->{disk_cnt} } = { identifier => "$model\:::$serial", type => $disk_type, size_mb => $size_mb, size_unparsed => $size_unparsed, port => $port, channel => '0', 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; } } else { # Increment unidentifiable_disks counter. $unidentifiable_disks_cntrl_total_counter++; } $storm_d_struct->{'controllers'}->{ $controller_num }->{'disks'}->{ $disk_num } = { type => $disk_type }; # Increment our passed disk counter. $opts->{disk_cnt}++; }; # Populate unidentifiable_disks. $d_struct_controllers->{ $opts->{cntrl_cnt} }->{'unidentifiable_disks'} = $unidentifiable_disks_cntrl_total_counter; # Increment our passed controller counter. $opts->{cntrl_cnt}++; }; $self->write_json({data => $storm_d_struct, device => '3ware'}); if ( defined($d_struct_map_file_new) ) { $self->write_json({data => $d_struct_map_file_new, device => '3ware_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 $num_drives = 0; my $raid_level = 'unknown'; my $block_device = 'unknown'; my $raid_state = 'unknown'; my $stripe_size = 'unknown'; my $size_unparsed = 'unknown'; my $size_value = 0; my $size_unit; my $size_mb = 0; for my $line ( split /^/, `$icmd info $opts->{controller} $opts->{unit}` ) { if ( $line =~ /^Unit\s+UnitType\s+Status\s+\S+\s+Port\s+Stripe\s+Size\((\S+)\)\s+Blocks/i ) { $size_unit = $1; } if ( $line =~ /^u\d+-\d+\s+DISK/i ) { $num_drives++; } if ( $line =~ /^u\d+\s+RAID-(\d+)\s+(\S+)\s+\S+\s+\S+\s+(\S+)\s+(\S+)/i ) { $raid_level = $1; $raid_state = $2; $stripe_size = $3; $size_value = $4; } if ( $line =~ /^u\d+\s+RAID-\d+\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)/i ) { $size_unparsed = $1; # 3ware doesn't tack unit after value $size_unparsed .= " $size_unit"; } } $size_mb = $self->convert_to_mb({ unit => $size_unit, value => $size_value }); # Find block device of our LD my $numeric_unit; if ( $opts->{unit} =~ /u(\d+)/i ) { $numeric_unit = $1; } my $disc_block_devices_ref = $self->get_block_devices(); for my $each_block_device ( @{ $disc_block_devices_ref } ) { my $smartctl_info_out = `smartctl -i /dev/$each_block_device`; if ( $smartctl_info_out =~ /3ware/ && $smartctl_info_out !~ /Device(\s+)?:\s+3ware\s+/ ) { $block_device = "/dev/$each_block_device"; } elsif ( $smartctl_info_out =~ /Device(\s+)?:\s+3ware\s+Logical\s+Disk\s+$numeric_unit\s+/i ) { $block_device = "/dev/$each_block_device"; } } return ($raid_level, $num_drives, $size_mb, $block_device, $raid_state, $stripe_size, $size_unparsed); } sub get_disk_info { my $self = shift; my $opts = shift; my $dtype = 'unknown'; my $model = 'unknown'; my $port = 'unknown'; my $firmware = 'unknown'; my $serial = 'unknown'; my $state = 'unknown'; my $size_unparsed = 'unknown'; my $size_value = 0; my $size_unit; my $size_mb = 0; for my $line ( split /^/, `$icmd /$opts->{controller}/$opts->{phys_disk} show all` ) { if ( $line =~ /^\S+\s+Model\s+=(.+)/i ) { $model = $1; $model =~ tr/ //ds; } if ( $line =~ /^\S+\s+Status\s+=\s+(\S+)/i ) { $state = $1; } if ( $line =~ /^\S+\s+Serial\s+=(.+)/i ) { $serial = $1; $serial =~ tr/ //ds; } if ( $line =~ /^\S+\s+Firmware\s+Version\s+=(.+)/i ) { $firmware = $1; $firmware =~ tr/ //ds; } if ( $line =~ /^\S+\s+Capacity\s+=\s+(\S+)\s+(\S+)/i ) { $size_value = $1; $size_unit = $2; } if ( $line =~ /^\S+\s+Capacity\s+=(.+)/i ) { $size_unparsed = $1; } if ( $line =~ /^\/c\d+\/p(\d+)/i ) { $port = $1; } } if ( $model =~ /SSD|INTEL|M4-CT/ ) { $dtype = 'SSD'; } else { $dtype = 'SATA'; } $size_mb = $self->convert_to_mb({ value => $size_value, unit => $size_unit }); my $smart_attribs = 'unsupported'; # /dev/twa0 refers to the first 9000-series controller, /dev/twa1 refers to the second 9000 series controller, and so on. # Likewise /dev/twe0 refers to the first 6/7/8000-series controller, /dev/twa1 refers to the second 6/7/8000 series # controller, and so on. my $device_prefix; if ( $model =~ /^9\d\d\d/i ) { $device_prefix = '/dev/twa'; } else { $device_prefix = '/dev/twe'; } # Verify our device exists my $controller_numeric; if ( $opts->{controller} =~ /\S(\d+)/ ) { $controller_numeric = $1; } my $device_to_query = "$device_prefix$controller_numeric"; if ( ! -e $device_to_query ) { $self->logger({ cat => 'c', msg => "Device to query ($device_to_query) doesn't exist!" }); } my $smartctl_info = `smartctl -i $device_to_query -d 3ware,$port -T permissive`; for my $line ( split /^/, $smartctl_info ) { if ( $line =~ /Serial\s+number(\s+)?:\s+(\S+)/i ) { if ( $2 eq $serial ) { $smart_attribs = $self->get_smart_attribs({ device => $device_to_query, d_flag => "3ware,$port" }); $smart_attribs = 'unsupported' if ( defined($smart_attribs->{error}) ); } } } # On 3ware, port is also device id my $device_id = $port; return ($dtype,$size_mb,$port,$model,$firmware,$serial,$state,$smart_attribs,$device_to_query,$device_id,$size_unparsed); } sub get_controller_attribute { my $self = shift; my $opts = shift; my $cntrl_attrib = `$icmd info $opts->{controller} $opts->{attrib}`; $cntrl_attrib =~ s/.*=//; $cntrl_attrib = $self->strip_whitespace({ string => $cntrl_attrib }); # If empty, set to error. $cntrl_attrib = 'error' if ( $cntrl_attrib !~ /\S/ ); return $cntrl_attrib; } sub host_supports_info { my ($self) = @_; return 1; } 1;
Copyright ©2k19 -
Hexid
|
Tex7ure