# # Copyright (c) 2001-2013 NetApp, Inc., All Rights Reserved # Any use, modification, or distribution is prohibited # without prior written consent from NetApp, Inc. # ## @summary RaidGroup Task Module ## @author dl-nacl-dev@netapp.com dl-raid-qa ## @status shared ## @burt 516200 [ For tracking the RaidGroup task] ## @pod here package NACL::STask::RaidGroup; use strict; use warnings; use NACL::ComponentUtils qw(Dumper _ontap_ci_validate_spec); use base qw(NACL::C::Component NACL::STask::STask); use NATE::Log qw(log_global); my $Log = log_global(); my $may_enter = $Log->may_enter(); my $may_exit = $Log->may_exit(); use Params::Validate qw(validate OBJECT SCALAR ARRAYREF UNDEF); use NATE::BaseException(); use NACL::APISet::Exceptions::InvalidParamValueException qw(:try); use NATE::Exceptions::Argument(); =head1 NAME NACL::STask::RaidGroup =head1 DESCRIPTION C provides a number of well-defined but potentially complex or multi-step methods related to RaidGroup in ONTAP. NACL::STask::RaidGroup helps to get all the attributes of raid group and user can get the information of raidgroups on the basis of certain number of parameters. =head1 METHODS =head2 list my $raid_groups = NACL::STask::RaidGroup->list( command_interface => $command_interface, %optional_filter ); #Get the properties of the filtered raid-groups foreach ( keys( %{$raid_groups} ) ) { $Log->comment( "parent_state of raid-group $raid_groups->{$_}->{raid_name} is " . "$raid_groups->{$_}->{parent_state}" ); } Where %optional_filter has key-value pairs from fields in "raid_config info listgroup" command. (Class method) List the all properties of raid group names as reference to a hash of hashes on the basis of given filters else return all the raid groups if properties were not given by user. The filters are from 'raid_config info listgroup' command. =over =item Options =over =item C<< command_interface => $command_interface >> (Required) See NACL::C::Component::command_interface =item C<< raid_name => $raid_name >> (Optional) Fully qualified disk name in following format: //// =item C<< fsm_state => $fsm_state >> (Optional) Finite state machine status of disks. Possible values - failed, inuse, zeroed, zeroing, nonzeroed. These values are not case-sensitive. =item C<< raid_size => $raid_size >> (Optional) size of the raid group =item C<< tree => $tree >> (Optional) Raid-tree name of disk. It also represents aggregate name for given disk =item C<< parent_state => $parent_state >> (Optional) parent state of raid group =item C<< parent_type => $parent_type >> (Optional) parent type of raid group =item C<< parent_id => $parent_id >> (Optional) parent id of raid group. =item C<< type => $type >> (Optional) type of raid group =item C<< disk_copy_source_id => $disk_copy_source_id >> (Optional) Id of source disk to copy =item C<< disk_copy_target_id => $disk_copy_target_id >> (Optional) Id of target disk to copy =item C<< recons_disabled => $recons_disabled >> (Optional) Status of recons disable/enable (0 or 1) =item C<< recons_progress => $recons_progress >> (Optional) Status of reconstruction progress =item C<< recons_suspended_block => $recons_suspended_block >> (Optional) Status of suspended recons block =item C<< reparity_progress => $reparity_progress >> (Optional) Status of reparity progress =item C<< scrub_progress => $scrub_progress >> (Optional) Status of scrub progress =item C<< scrub_suspended_block => $scrub_suspended_block >> (Optional) Status of suspended scrub progress =item C<< context_scrub => $context_scrub >> (Optional) context_scrub value =item C<< context_parity_protected => $context_parity_protected >> (Optional) Status of protected context parity =item C<< lw_scrub => $lw_scrub >> (Optional) Status of lost write scrub =item C<< lw_scrub_protected => $lw_scrub_protected >> (Optional) Status of protected lost write scrub =item C<< scrub_media_err => $scrub_media_err >> (Optional) Value of scrub media error =item C<< scrub_cksum_err => $scrub_cksum_err >> (Optional) Value of scrub checksum error =back Returns the hash reference of all properties of raid group names on the basis of given filters else return hash reference of all properties of all the raid groups if no filters were given by user. =back =over =item Exceptions =over =item C This type of exception is thrown an attempt is made to call 'list' method as instance method. =item C This type of exception is thrown when no raid group found with given attributes. =back =cut sub list { $Log->enter() if $may_enter; my $pkg = shift; if ( ref($pkg) ) { NATE::BaseException->throw( "NACL::STask::RaidGroup::list: This method is not an instance " . "method" ); } my %opts = $pkg->_common_validate_with( params => \@_, additional_spec => { command_interface => { type => OBJECT, isa => 'NACL::C::CommandInterface' }, raid_name => { type => ARRAYREF | UNDEF, optional => 1 }, raid_size => { type => SCALAR | UNDEF, optional => 1 }, fsm_state => { type => SCALAR | UNDEF, optional => 1 }, tree => { type => SCALAR | UNDEF, optional => 1 }, parent_state => { type => SCALAR | UNDEF, optional => 1 }, parent_type => { type => SCALAR | UNDEF, optional => 1 }, parent_id => { type => SCALAR | UNDEF, optional => 1 }, type => { type => SCALAR | UNDEF, optional => 1 }, disk_copy_source_id => { type => SCALAR | UNDEF, optional => 1 }, disk_copy_target_id => { type => SCALAR | UNDEF, optional => 1 }, recons_disabled => { type => SCALAR | UNDEF, optional => 1 }, recons_progress => { type => SCALAR | UNDEF, optional => 1 }, recons_suspended_block => { type => SCALAR | UNDEF, optional => 1 }, reparity_progress => { type => SCALAR | UNDEF, optional => 1 }, scrub_progress => { type => SCALAR | UNDEF, optional => 1 }, scrub_suspended_block => { type => SCALAR | UNDEF, optional => 1 }, context_scrub => { type => SCALAR | UNDEF, optional => 1 }, context_parity_protected => { type => SCALAR | UNDEF, optional => 1 }, lw_scrub => { type => SCALAR | UNDEF, optional => 1 }, lw_scrub_protected => { type => SCALAR | UNDEF, optional => 1 }, scrub_pi => { type => SCALAR | UNDEF, optional => 1 }, scrub_media_err => { type => SCALAR | UNDEF, optional => 1 }, scrub_cksum_err => { type => SCALAR | UNDEF, optional => 1 }, }, ); my %key_opts = %opts; $pkg->_hash_move( source => \%key_opts, move => [ keys( %{ $pkg->_common_validate_spec() } ) ] ); my $command_interface = $opts{command_interface}; my $raid_groups = $opts{raid_name}; my @keys = keys(%key_opts); # Get the properties of all or given raid groups my $attributes = $pkg->properties( command_interface => $command_interface, raid_name => $raid_groups ); $Log->debug( "NACL::STask::RaidGroup::list : Getting raid group list " . "for attributes - @keys" ); $Log->debug( "NACL::STask::RaidGroup::list : Required raid group attributes - " . Dumper( \%opts ) ); my @arguments; if ( ref $raid_groups eq "ARRAY" ) { foreach my $args (@$raid_groups) { push @arguments, $args; } } else { push @arguments, $raid_groups; } if ( defined $opts{raid_name} ) { foreach my $var (@arguments) { if (@keys) { foreach my $parameter (@keys) { my @attributes_intermediate = (); foreach my $attribute (@$attributes) { $Log->debug( "NACL::STask::RaidGroup::list : Values for $parameter, " . "Expected - " . $var . ", Actual - $attribute->{$parameter}" ); if ( exists $attribute->{$parameter} ) { if ( $var eq $attribute->{$parameter} ) { push( @attributes_intermediate, $attribute ); } } } ## end foreach my $attribute (@$attributes) $attributes = \@attributes_intermediate; } ## end foreach my $parameter (@keys) } ## end if (@keys) } ## end foreach my $var (@arguments) } else { if (@keys) { foreach my $parameter (@keys) { my @attributes_intermediate = (); foreach my $attribute (@$attributes) { $Log->debug( "Options are \n" . Dumper( $opts{$parameter} ) ); $Log->debug( "NACL::STask::RaidGroup::list : Values for $parameter, " . "Expected - $opts{$parameter}, Actual - $attribute->{$parameter}" ); if ( exists $attribute->{$parameter} ) { if ( $opts{$parameter} eq $attribute->{$parameter} ) { push( @attributes_intermediate, $attribute ); } } } ## end foreach my $attribute (@$attributes) $attributes = \@attributes_intermediate; } ## end foreach my $parameter (@keys) } ## end if (@keys) } ## end else [ if ( defined $opts{raid_name...})] my %raid_group = (); foreach my $attr (@$attributes) { $raid_group{ $attr->{raid_name} } = $attr; } if ( scalar( keys %raid_group ) == 0 ) { $Log->exit() if $may_exit; NATE::Exceptions::Argument->throw( "No Raid Group found for given attributes."); } $Log->debug( "raid_group are :" . Dumper( \%raid_group ) ); $Log->exit() if $may_exit; return \%raid_group; } ## end sub list =head2 properties my $raid_obj = NACL::STask::RaidGroup->properties( command_interface => $command_interface, raid_group => \@raidgroups, ); $Log->comment("All properties of raid groups are :" . Dumper($raid_obj) ); Output format - { 'tree' => 'aggr1', 'recons_progress' => '-1', 'group_raid_lw_scrub' => 'DONE', 'raid_size' => '216969024', 'scrub_suspended_block' => '-1', 'context_scrub' => '0', 'raid_name' => '/aggr1/plex0/rg0', 'parent_id' => '35947', 'disk_copy_source_id' => '-1', 'parent_type' => 'plex', 'raid_type' => 'raid4', 'disk_copy_target_id' => '-1', 'scrub_media_err' => '0', 'recons_suspended_block' => '-1', 'scrub_lw_err' => '0', 'reparity_progress' => '-1', 'id' => '35948', 'parent_state' => 'ACTIVE', 'scrub_pi' => '0', 'checksum_type' => 'block', 'scrub_progress' => '51', 'fsm_state' => 'NORMAL', 'context_parity_protected' => '1', 'recons_disabled' => '0', 'scrub_cksum_err' => '0', 'type' => 'group' } (Class method) This methods returns all attributes of Raid groups. =over =item Options =over =item C<< raid_name =>\@raidgroups >> (Required) Raid group names. =back Return the all properties of the given raid-name, if raid-name is undef, it will returns all the properties of all raid-groups. =item command_interface, apiset_must, apiset_should, method-timeout, comment etc. =back =cut sub properties { $Log->enter() if $may_enter; my $pkg = shift; my %opts = $pkg->_common_validate_with( params => \@_, additional_spec => { command_interface => { type => OBJECT, isa => 'NACL::C::CommandInterface' }, raid_name => { type => ARRAYREF | UNDEF, default => undef }, }, allow_extra => 1, ); my $command_interface = $opts{command_interface}; my @raidgroups = @{ $opts{raid_name} } if ( defined( $opts{raid_name} ) ); my $nodescope_apiset = $command_interface->get_7m_or_nodescope_apiset(); my $attributes = []; if ( scalar(@raidgroups) > 0 ) { foreach my $raid_grp_name (@raidgroups) { my $response = $nodescope_apiset->raid_config( info => "listgroup $raid_grp_name" ); my $parsed_output = $response->get_parsed_output(); push( @$attributes, $parsed_output->[0] ); } ## end foreach my $raid_grp_name (...) } else { my $response = $nodescope_apiset->raid_config( info => "listgroup" ); $attributes = $response->get_parsed_output(); } $Log->exit() if $may_exit; return $attributes; } ## end sub properties =head2 exits my $exists = NACL::STask::RaidGroup->exists( command_interface => $command_interface, group_name => $scalar ); (Class method) This subroutine checks if given raidgroup exists. If the given raid_group is found, it returns 1 else 0. =over =item Options =over =item C<< group_name => $scalar >> (Required) Raid group names. =back =item command_interface, apiset_must, apiset_should, method-timeout etc. =back =over =item Exceptions =over =item C This type of exception is thrown when invalid parameter value is passed. =back =cut sub exists { $Log->enter() if $may_enter; my $pkg = shift; my %opts = $pkg->_common_validate_with( params => \@_, additional_spec => { command_interface => { type => OBJECT, isa => 'NACL::C::CommandInterface::ONTAP' }, group_name => { type => SCALAR }, }, ); my $exists = 1; $opts{'raid_name'} = [ delete $opts{'group_name'} ]; try { $pkg->properties(%opts); } catch NACL::APISet::Exceptions::InvalidParamValueException with { my $ex = shift; my $error = $ex->text(); if ( $error =~ /not\sfound/i ) { $exists = 0; } else { $Log->exit() if $may_exit; $ex->throw(); } }; $Log->exit() if $may_exit; return $exists; } ## end sub exists =head2 check_state my $exists = NACL::STask::RaidGroup->check_state( command_interface => $command_interface, group_name => $scalar property => $scalar ); (Class method) This subroutine checks if given raidgroup meets set of defined attributes values for a specific property provided. Criteria for the property is explained below. =over =item Options =over =item C<< group_name => $scalar >> (Required) Raid group name. =back =item C<< property => $scalar >> (Required) The property for which the state of a RaidGroup is being checked against. Possible values for "property" are, =over =item running_context_scrub =item Criteria: =over =item context_scrub eq "1" =item context_parity_protected eq "0" =item scrub_progress ne "-1" =item scrub_suspended_block ne "-1" =back =item recons_in_progress =item Criteria: =over =item fsm_state =~ /RECONS/ =item recons_progress ne -1 =item recons_suspended_block eq -1 =back =item recons_is_suspend =item Criteria: =over =item fsm_state =~ /RECONS/ =item recons_suspended_block ne -1 =back =item reparity_in_progress =item Criteria =item reparity_progress ne -1 =back =item scrub_in_progress =item Criteria: =over =item scrub_progress ne -1 =item scrub_suspended_block eq -1 =back =item scrub_in_suspend =item Criteria: =over =item scrub_progress ne -1 =item scrub_suspended_block ne -1 =back =back =over =item command_interface, apiset_must, apiset_should, method-timeout etc. =back =over =item Exceptions =over =item C This type of exception is thrown when an invalid value is passed for the property attribute. =back =cut sub check_state { $Log->enter() if $may_enter; my $pkg = shift; my %opts = $pkg->_common_validate_with( params => \@_, additional_spec => { command_interface => _ontap_ci_validate_spec(), group_name => { type => SCALAR }, property => { type => SCALAR }, }, ); my $property = delete $opts{property}; $opts{'raid_name'} = [ delete $opts{'group_name'} ]; my $raid_group_obj = $pkg->properties(%opts)->[0]; my %criteria = ( "running_context_scrub" => { "must_match" => { "context_scrub" => 1, "context_parity_protected" => 0, "scrub_suspended_block" => -1 }, "must_not_match" => { "scrub_progress" => -1, } }, "recons_in_progress" => { "must_match" => { "fsm_state" => "RECONS", "recons_suspended_block" => -1 }, "must_not_match" => { "recons_progress" => -1, } }, "recons_is_suspend" => { "must_match" => { "fsm_state" => "RECONS" }, "must_not_match" => { "recons_suspended_block" => -1 } }, "reparity_in_progress" => { "must_not_match" => { "reparity_progress" => -1 } }, "scrub_in_progress" => { "must_match" => { "scrub_suspended_block" => -1 }, "must_not_match" => { "scrub_progress" => -1 } }, "scrub_in_suspend" => { "must_not_match" => { "scrub_progress" => -1, "scrub_suspended_block" => -1 } }, ); if ( !defined $criteria{$property} ) { $Log->exit() if $may_exit; NATE::Exceptions::Argument->throw( "$property is invalid value for the attribute : property"); } my $validate_rg_attribs = sub { foreach my $match_type ( keys %{ $criteria{$property} } ) { foreach my $attrib ( keys %{ $criteria{$property}->{$match_type} } ) { my $obj_value = $raid_group_obj->{$attrib}; my $criteria_value = $criteria{$property}->{$match_type}{$attrib}; my $regex; if ( $criteria_value =~ /^[+-]?\d+$/ ) { $regex = qr/^$criteria_value$/; } else { $regex = qr/$criteria_value/; } if ( $match_type eq "must_match" ) { ( $obj_value =~ /$regex/ ) || return 0; } else { ( $obj_value =~ /^(?!$regex)/ ) || return 0; } } ## end foreach my $attrib ( keys %...) } ## end foreach my $match_type ( keys...) return 1; }; my $state = $validate_rg_attribs->(); $Log->exit() if $may_exit; return $state; } ## end sub check_state 1;