# # Copyright (c) 2001-2016 NetApp, Inc., All Rights Reserved # Any use, modification, or distribution is prohibited # without prior written consent from NetApp, Inc. # ## @summary StorageAggregateRelocation Task Module ## @author dl-nacl-dev@netapp.com ## @status Public ## @pod here package NACL::STask::StorageAggregateRelocation; use strict; use warnings; use base qw(NACL::C::StorageAggregateRelocation NACL::STask::STask); use NACL::C::Volume; 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_with SCALAR ARRAYREF HASHREF BOOLEAN); use NACL::ComponentUtils qw(Dumper _optional_scalars); use NACL::STask::Exceptions::AggregateRelocationFailure qw(:try); use NACL::Exceptions::UnexpectedState qw(:try); use constant PER_AGGR_RELOCATE_DEBUG => 300; use constant PER_AGGR_RELOCATE_NON_DEBUG => 120; use constant ONE_MIN => 60; use constant POLL_DELTA => 5; use constant POLL_STATUS => 2; use Class::MethodMaker [ scalar => 'node', scalar => 'destination', array => 'aggregate_list', hash => 'aggr_vol_list', scalar => '_aggr_migration_timeout' ]; =head1 NAME NACL::STask::StorageAggregateRelocation =head1 DESCRIPTION C provides a number of well-defined but potentially complex or multi-step methods related to Storage Aggregate Relocation task on ONTAP. It builds on top of, and is a derived class of C, and so it also provides methods that are more in the scope of individual StorageAggregateRelocation-related commands. See C for details. This also means that a C object may generally be used in place of a component object. =head1 ATTRIBUTES =head2 command_interface (Required) As C. A component object that represents the host to which to send commands. =head2 node (Required) As C. The name of the node from which the aggregate(s) will be relocated . =head2 destination (Required) Name of the destination node to which the aggregate (s) will be relocated. =head2 aggregate_list (Required) As C. The list of aggregates which will be relocated . =head2 aggr_vol_list (Required) As C. Hash of volumes and vservers available under each aggregate, provided in the aggregate_list . For Example : 'aggr_1' => { 'vol_1' => {vserver=>'vs0', state => 'online'}, 'vol_2' => {vserver=>'vs0', state => 'online'}, } 'aggr_2' => { 'vol_3' => {vserver=>'vs1', state => 'online'}, 'vol_4' => {vserver=>'vs1', state => 'online'}, } =head1 METHODS =head2 start my $Arl = NACL::STask::StorageAggregateRelocation->start( command_interface => $command_interface, node => $node, destination => $destination_node, 'aggregate-list' => $aggr_list, nacltask_wait => $boolean, #default '1', %other_options ); (Class method) start a Aggregate Relocation Operation. This method provides additional services beyond what's inherent to the product's Aggregate Relocation commands, as controlled and described by the new C option. =over =item Options =over =item C<< nacltask_wait => 0|1 >> (Optional) If 1 (the default), verify that the aggregate relocation has successfully completed. If 0, do not verify. =item B<< "nacltask_verify_all_attributes" => 0|1 >> (Optional) Default is 1. This option should be provided as 0/1 only when nacltask_wait = 1. If this option is provided as 1,while nacltask_wait=1, then the following verifications are done : (i) the relocation_status of all the aggregates goes to 'Done' (ii) if the aggregates are all online after relocation to destination. (iii) if the state of all volumes under each aggregate is same as before relocation. (iv) if the home node and current node fields of all the aggregates are appropriate. If this option is set to 0, while nacltask_wait = 1, then taskverify_relocate just ensures that 'relocation_status' of all the aggregates in aggregate-list goes to Done and it happens within PER_AGGREGATE_RELOCATE time in seconds for each aggregate . =item C<< nacltask_reverse_controller_upgrade => 0|1 >> (Optional) Default is 0. This option should be provided as 1 only when performing controller upgrade in reverse direction. ( controller from Node A to Node B is already completed, and if aggregates has to returned back to the source node using -nod-controller-upgrade option then nacltask_reverse_controller_upgrade should be 1 ) =item command_interface, apiset_must, apiset_should, method-timeout, node, destination,aggregate-list,ndo-controller-upgrade,override-destination-checks, relocate-to-higher-version etc., All of the other various options to L<< NACL::C::StorageAggregateRelocation->start | lib-NACL-C-StorageAggregateRelocation-pm/start >> =back =back =over =item Exceptions =over =item C This type of exception is thrown when verification fails in any of the below mentioned steps. (i) Check whether relocation status for all the aggregates is done. (ii) Check whether the aggregates are all online after relocation to destination. (iii) Check whether the state of all volumes under each aggregate is same as before relocation. (iv) Check whether owner nodename has changed to the destination nodename for all the aggregates after relocation. =back =back =cut sub start { $Log->enter() if $may_enter; my ( $pkg, @args ) = @_; # validate the parameters my %opts = $pkg->_common_validate_with( params => \@args, additional_spec => { node => { type => SCALAR }, destination => { type => SCALAR }, 'aggregate-list' => { type => ARRAYREF }, nacltask_wait => { type => SCALAR, default => 1 }, nacltask_verify_all_attributes => { type => BOOLEAN, default => 1 }, nacltask_reverse_controller_upgrade => { type => SCALAR, default => 0 }, }, allow_extra => 1, ); my $wait = delete $opts{nacltask_wait}; my $verify_all = delete $opts{nacltask_verify_all_attributes}; my $timeout = delete $opts{'method-timeout'} || $pkg->_reloc_timeout_based_on_build_arch( command_interface => $opts{command_interface} ); my %volumes_aggr; my $aggregate_list = $opts{'aggregate-list'}; my $controller_upgrade = $opts{'ndo-controller-upgrade'}; my $reverse_controller_upgrade = delete $opts{nacltask_reverse_controller_upgrade}; $Log->debug( sub { "capturing Volume state information for all volumes in the aggregate list"; } ); foreach my $aggr (@$aggregate_list) { my @aggr_vol = NACL::CS::Volume->fetch( command_interface => $opts{command_interface}, filter => { aggregate => $aggr }, requested_fields => [qw(volume vserver state type)], is_system_vol => 0, allow_empty => 1 ); foreach my $av (@aggr_vol) { my $volume = $av->volume(); if ( $av->type() ne 'DEL') { $volumes_aggr{$aggr}{$volume}{'vserver'} = $av->vserver(); $volumes_aggr{$aggr}{$volume}{'state'} = $av->state(); } } } $Log->debug( sub { "Start aggregate relocation for the given list of aggregates"; } ); my @stasks = $pkg->SUPER::start(%opts); foreach my $task (@stasks) { $task->destination( $opts{destination} ); $task->aggregate_list( @{ $opts{'aggregate-list'} } ); $task->aggr_vol_list(%volumes_aggr); } if ($wait) { my %wait_for_relocate_opts; $pkg->_hash_copy( source => \%opts, copy => [ qw( node destination aggregate-list command_interface apiset_must apiset_should ) ], target => \%wait_for_relocate_opts ); %wait_for_relocate_opts = ( %wait_for_relocate_opts, 'method-timeout' => $timeout, 'aggregate-vol-details' => \%volumes_aggr, 'nacltask_verify_all_attributes' => $verify_all ); if ( defined $controller_upgrade && $controller_upgrade eq 'true' ) { if ($reverse_controller_upgrade) { $wait_for_relocate_opts{'nacltask_arl_type'} = "ReverseControllerUpgrade"; } else { $wait_for_relocate_opts{'nacltask_arl_type'} = "ControllerUpgrade"; } } $Log->debug( sub { "wait_for_relocate_opts Dumper " . Dumper( \%wait_for_relocate_opts ); } ); $Log->comment("Option nacltask_wait = 1, wait for ARL to complete "); $pkg->taskverify_relocate(%wait_for_relocate_opts); } $Log->exit() if $may_exit; return wantarray ? @stasks : $stasks[0]; } ## end sub start =head2 taskverify_relocate $arl_task_obj->taskverify_relocate( "method-timeout" => $timeout, aggregate-vol-details => $aggr_vol_list, nacltask_polling_interval => $poll_delta, %wait_options ); or NACL::STask::StorageAggregateRelocation->taskverify_relocate( command_interface => $node, node => $node_name, destination => $destination_node, aggregate-list => $aggr_list, aggregate-vol-details => $aggr_vol_list, "method-timeout" => $timeout, nacltask_polling_interval => $poll_delta, nacltask_arl_type => $type, %wait_options ); (class or instance method) This method verifies whether the given list of aggregates have been successfully relocated to the given destination node. =over =item Options =over =item B<< "method-timeout"=> $scalar >> (Optional) Timeout to be used per aggregate relocate . Default value is 60 seconds. If an aggregate takes more than 60 seconds a AggregateRelocationFailure exception is thrown by the method. =item B<< "nacltask_polling_interval"=> $scalar >> (Optional) The polling time interval value for waiting for relocation to complete. default 5 sec =item B<< "nacltask_verify_all_attributes" => $scalar >> (Optional) Default is 1. If this option is provided as 1, then the following verifications are done : (i) if the aggregates are all online after relocation to destination. (ii) if the state of all volumes under each aggregate is same as before relocation. (iii) if the home node and current node fields of all the aggregates are appropriate. =item B<< "nacltask_arl_type" => $scalar >> (Required for static call, Optional for instance call) This option is used to specify the type of ARL that has occured . It defaults to 'ARL'. The valid values for this option are - 'ARL' - which implies that this aggregate relocate operation was explicitly started by 'aggregate relocation start' command. In the verification step, the method checks that home-node = destination node and current-node = destination node. 'TakeOver' - which implies that the ARL was initiated by a TakeOver operation. In the verification step, the method checks that home-node = source node and current-node = destination node. 'ControllerUpgrade' - which implies that the ARL was initiated with special options -ndo-controller-upgrade true In the verification step, the method checks that home-node = source node and current-node = destination node. 'ReverseControllerUpgrade' - which implies that the ARL was initiated with special options -ndo-controller-upgrade true from destination to source In the verification step, the method checks that home-node = source node and current-node = source node. 'GiveBack' - This is a placeholder for the timebeing. Will be filled in the near future. In case of instance call it is implicit that this ARL was initiated explicitly via the start command. Hence it defaults to 'ARL' and the verification is done appropriately. =item B<< node => $node >> (Required for class method , not required for instance calls) The name of the node from which the aggregate(s) is relocated . =item B<< destination => $destination_node >> (Required for class method , not required for instance calls) The name of the destination node to which the aggregate is relocated =item B<< 'aggregate-list' => $aggr_list >> (Required for class method , not required for instance calls) List of aggregates which will be verified for relocation =item B<< 'aggregate-vol-details' => $aggr_vol_list >> (Required for class method , not required for instance calls) This is a hash of hash containing the details of the aggregates and volumes belonging to each aggregate . The data is expected to be provided in the following format. 'aggr_1' => { 'vol_1' => {vserver=>'vs0', state => 'online'}, 'vol_2' => {vserver=>'vs0', state => 'online'}, } 'aggr_2' => { 'vol_3' => {vserver=>'vs1', state => 'online'}, 'vol_4' => {vserver=>'vs1', state => 'online'}, } =back =back =over =item Exceptions =over =item C This type of exception is thrown when verification fails in any of the below mentioned steps. (i) Check whether the aggregates are online after relocation to destination. (ii) Check whether the state of all volumes under each aggregate is same as before relocation. (iii)Check whether owner nodename has changed to the destination nodename for all the aggregates after relocation. =back =back =cut sub taskverify_relocate { $Log->enter() if $may_enter; my ( $pkg_or_obj, @args ) = @_; # validate the parameters my %opts = $pkg_or_obj->_common_validate_with( params => \@args, additional_spec => { destination => { type => SCALAR, optional => 1 }, 'aggregate-list' => { type => ARRAYREF, optional => 1 }, 'aggregate-vol-details' => { type => HASHREF, optional => 1 }, nacltask_verify_all_attributes => { type => BOOLEAN, default => 1 }, nacltask_arl_type => { type => SCALAR, default => 'ARL', }, _optional_scalars(qw(nacltask_polling_interval )) }, allow_extra => 1, ); my $pkg; $pkg = ref($pkg_or_obj) ? ref($pkg_or_obj) : $pkg_or_obj; my $command_interface = $opts{command_interface} || $pkg_or_obj->command_interface(); my $node = $opts{node} || $pkg_or_obj->node(); my $destination = $opts{destination} || $pkg_or_obj->destination(); $node = $node->name if (ref $node); $destination = $destination->name if (ref $destination); my @aggregate_list = $opts{'aggregate-list'} ? @{ $opts{'aggregate-list'} } : $pkg_or_obj->aggregate_list(); my $aggregate_vol_list = $opts{'aggregate-vol-details'} || $pkg_or_obj->aggr_vol_list(); my $arl_type = $opts{'nacltask_arl_type'}; $Log->comment( "This is the aggregate_list " . Dumper( \@aggregate_list ) ); my %aggr_vol = %$aggregate_vol_list; my $timeout = delete $opts{"method-timeout"} || $pkg->_reloc_timeout_based_on_build_arch( command_interface => $opts{command_interface} ); my $polling_interval = delete $opts{nacltask_polling_interval} || POLL_DELTA; my $verify_attributes = delete $opts{nacltask_verify_all_attributes}; my @unexpected_results; my $exception_member; my $last_aggregate = $aggregate_list[-1]; foreach my $aggregate (@aggregate_list) { $Log->comment("This is the aggregate $aggregate "); my $arl_failed = 0; my $start_time = time(); my $end_time = time() + $timeout; # This step is not applicable for TO/GB if ( $arl_type eq 'ARL' || $arl_type eq 'ControllerUpgrade' || $arl_type eq 'ReverseControllerUpgrade' ) { try { #"wait for the relocation status to become 'Done' for aggr $aggregate"; # when ARL is triggered with the -headupgrade parameter, it will add a # sixty second pause after last relocation. storage aggregate relocation # show command will display relocation of last aggregate is in progress # during this window if (( $aggregate eq $last_aggregate ) && ( $arl_type eq 'ControllerUpgrade' || $arl_type eq 'ReverseControllerUpgrade' ) ) { $timeout = $timeout + ONE_MIN; } $pkg->wait_for_arl_status( command_interface => $command_interface, node => $node, destination => $destination, aggregate => $aggregate, expected_relocation_status => 'Done', 'method-timeout' => $timeout ); # If the previous step passes, it means that this verification # has already passed. So need to go to the next verification loop } catch NACL::Exceptions::Timeout with { my $exception = shift; $Log->debug( sub { "Exception text received in taskverify_relocate " . $exception->text(); } ); $exception_member->{'aggregate'} = $aggregate; $exception_member->{'text'} = $exception->text(); push @unexpected_results, $exception_member; $arl_failed = 1; }; } if ( !$arl_failed && $verify_attributes ) { my $home_name; if ( $arl_type =~ /ARL/i || $arl_type =~ /ReverseControllerUpgrade/i ) { $home_name = $destination; } elsif ( $arl_type =~ /TakeOver/i || $arl_type =~ /ControllerUpgrade/i ) { $home_name = $node; } try { $Log->comment( "Verify that state=online, owner-name=$destination " . "home-name=$home_name, for aggr $aggregate" ); NACL::C::StorageAggregate->wait_on_attributes( aggregate => $aggregate, command_interface => $command_interface, attributes => [ { attribute_to_check => 'state', till_value => 'online', }, { attribute_to_check => 'owner-name', till_value => $destination, }, { attribute_to_check => 'home-name', till_value => $home_name, } ], 'method-timeout' => $timeout ); if ( defined $aggr_vol{$aggregate} ) { my %vol_details = %{ $aggr_vol{$aggregate} }; while ( my ( $key, $value ) = each %vol_details ) { $Log->comment( "Verifying that state=" . $value->{state} . " for volume $key in aggr $aggregate" ); $pkg->_check_moved_volume_state( command_interface => $command_interface, volume => $key, vserver => $value->{'vserver'}, aggregate => $aggregate, state => $value->{'state'}, 'method-timeout' => $timeout, polling_interval => $polling_interval ); } } } catch NACL::Exceptions::Timeout with { my $exception = shift; $Log->debug( sub { "Exception text received in taskverify_relocate " . $exception->text(); } ); my $error_message = "After waiting for $timeout seconds the relocated " . "Aggregate attributes\nowner_name,home_name,state," . "volumes' state do not have expected values for " . "aggregate $aggregate"; $Log->debug( sub {$error_message} ); $exception_member->{'aggregate'} = $aggregate; $exception_member->{'text'} = $exception->text(); push @unexpected_results, $exception_member; $arl_failed = 1; }; } ## end if if ( !$arl_failed ) { my $finish_time = time(); my $elapsed_time = $finish_time - $start_time; my $max_time = $end_time - $start_time; if (( $aggregate eq $last_aggregate ) && ( $arl_type eq 'ControllerUpgrade' || $arl_type eq 'ReverseControllerUpgrade' ) ) { $max_time = $max_time + ONE_MIN; } if ( $elapsed_time > $max_time ) { $exception_member->{'aggregate'} = $aggregate; $exception_member->{'text'} = "ARL did not occur in " . $max_time . "seconds "; push @unexpected_results, $exception_member; } } } ## foreach ends here if ( scalar @unexpected_results ) { my $text = join "\n", map {"$_->{aggregate} : $_->{text}"} @unexpected_results; $Log->exit() if $may_exit; NACL::STask::Exceptions::AggregateRelocationFailure->throw( "List of failures in the AggregateRelocation are as follows\n$text\n", unexpected_results => \@unexpected_results ); } $Log->exit() if $may_exit; } ## end sub taskverify_relocate =head2 check_arl_status NACL::STask::StorageAggregateRelocation->check_arl_status( command_interface => $node, node => $node_name, destination => $destination_node, aggregate => $aggregate, expected_relocation_status => $exp_rel_status, "method-timeout" => $timeout, %other_options ); (class method) This method verifies whether the given aggregate has reached a certain relocation_status =over =item Options =over =item B<< "method-timeout"=> $scalar >> (Optional) Timeout to be used per aggregate relocate . Default value is 60 seconds. If an aggregate takes more than 60 seconds NACL::Exceptions::UnexpectedState exception is thrown by the method. =item B<< node => $node >> (Required) The name of the node from which the aggregate(s) is relocated . =item B<< destination => $destination_node >> (Required) The name of the destination node to which the aggregate is relocated =item B<< 'aggregate' => $aggr_name >> (Required) An aggregate whose relocation_status would be verified using the given parameters =item B<< 'expected_relocation_status' => $expected_rel_status or ["state1","state2"] >> (Required) A relocation_status expected for the storage aggregate relocation operation initiated on the aggregate. Value type can be Scaler or ArrayRef. The method returns successfully if any item of list matches the status. If the method finds that the relocation_status of the given aggregate is same as expected then it silently returns successfully. But if it finds that the status is not the same as expected then it throws an exception NACL::Exceptions::UnexpectedState containing the information regarding the unexpected state in which the aggregate is available. =back =back =over =item Exceptions =over =item C This type of exception is thrown when relocation status of an aggregate is not as same as expected or when an aggregate has not reached an certain relocation status even after $timeout seconds. =back =back =cut sub check_arl_status { $Log->enter() if $may_enter; my ( $pkg, @args ) = @_; # validate the parameters my %opts = $pkg->_common_validate_with( params => \@args, additional_spec => { aggregate => { type => SCALAR }, destination => { type => SCALAR }, expected_relocation_status => { type => SCALAR|ARRAYREF } }, ); my @expected_status_list = ref $opts{expected_relocation_status} eq "ARRAY" ? @{$opts{expected_relocation_status}} : qq ($opts{expected_relocation_status}) ; my $CS = $pkg->get_CS_package_name(); my $state = $CS->fetch( command_interface => $opts{command_interface}, filter => { aggregate => $opts{aggregate}, destination => $opts{destination}, node => $opts{node} }, requested_fields => [qw(aggregate relocation-status)] ); my $relocation_status = $state->relocation_status(); if ( $relocation_status ne "Done" ) { $relocation_status =~ s/"//g; } my $msg; if ( !grep (/$relocation_status$/,@expected_status_list)) { $msg = "relocation_status of the aggregate " . $opts{aggregate} . " is not the same as any of expected: " . "@expected_status_list"; $Log->debug("$msg"); $Log->exit() if $may_exit; NACL::Exceptions::UnexpectedState->throw( $msg, monitoring_fields => ['relocation-status'], 'relocation-status' => $relocation_status ); } $msg = "relocation_status ($relocation_status) of the aggregate " . $opts{aggregate} . " is one of expected: " . "@expected_status_list"; $Log->debug("$msg"); $Log->exit() if $may_exit; } ## end sub check_arl_status =head2 wait_for_arl_status NACL::STask::StorageAggregateRelocation->wait_for_arl_status( command_interface => $node, node => $node_name, destination => $destination_node, expected_relocation_status => $exp_rel_status, nacltask_poll_interval => '15', aggregate => $aggregate, "method-timeout" => $timeout, %other_options ); (class method) This method waits for the given aggregate to reach a certain relocation_status , while the aggregate relocation is in progress. =over =item Options =over =item B<< "method-timeout"=> $scalar >> (Optional) Timeout to be used per aggregate relocate . Default value is 60 seconds. If an aggregate takes more than 60 seconds a NACL::Exceptions::Timeout exception is thrown by the method. =item B<< "nacltask_poll_interval" => $scalar >> (Optional) Polling interval that needs to be used before the status of the relocation is polled again , after the previous poll did not find it in the expected status. It takes the value '10' by default. =item B<< node => $node >> (Required) The name of the node from which the aggregate(s) is relocated . =item B<< destination => $destination_node >> (Required) The name of the destination node to which the aggregate is relocated =item B<< 'aggregate' => $aggr_name >> (Required) An aggregate whose relocation_status would be verified using the given parameters =item B<< 'expected_relocation_status' => $expected_rel_status or ["state1","state2"] >> (Required) A relocation_status expected for the storage aggregate relocation operation initiated on the aggregate. Value can be Scalar or ArrayRef. The method returns successfully if any item of list matches the status. If the aggregate does not reach the given status in method-timeout time (in seconds), then a NACL::Exceptions::Timeout is thrown with the appropriate error message. If the aggregate reaches the relocation_status expected in the given timeout, then the method returns successfully. =back =back =over =item Exceptions =over =item C This type of exception is thrown when aggregate does not reaches expected relocation_status in the given timeout seconds. =back =back =cut sub wait_for_arl_status { $Log->enter() if $may_enter; my ( $pkg, @args ) = @_; # validate the parameters my %opts = $pkg->_common_validate_with( params => \@args, additional_spec => { aggregate => { type => SCALAR }, destination => { type => SCALAR }, expected_relocation_status => { type => SCALAR|ARRAYREF }, nacltask_poll_interval => { type => SCALAR, optional => 1 } }, ); my $poll_interval = delete $opts{nacltask_poll_interval} || POLL_STATUS; my $time_to_wait = delete $opts{'method-timeout'} || $pkg->_reloc_timeout_based_on_build_arch( command_interface => $opts{command_interface} ); my $exit_flag = 0; my $end_time = time() + $time_to_wait; my $actual_relocation_status; my $expected_relocation_status_str = ref $opts{expected_relocation_status} eq "ARRAY" ? "@{$opts{expected_relocation_status}}" : $opts{expected_relocation_status} ; $Log->comment( "Wait for relocation_status of the aggregate " . $opts{aggregate} . " to be " . $expected_relocation_status_str ); while ( time() < $end_time ) { try { $pkg->check_arl_status(%opts); $Log->debug( sub { "wait_for_arl_status - Aggregate " . $opts{aggregate} . " is in expected relocation_status"; } ); $exit_flag = 1; } ## end try catch NACL::Exceptions::NoElementsFound with { Tharn::snooze $poll_interval ; } catch NACL::Exceptions::UnexpectedState with { my $exception = shift; if ( $exception->relocation_status() !~ m[$expected_relocation_status_str]i && $exception->relocation_status() =~ m[Failed:] ) { $exception->throw(); } $actual_relocation_status = $exception->relocation_status(); Tharn::snooze $poll_interval ; }; last if $exit_flag; } if (!$exit_flag) { my $error_message = "After waiting for $time_to_wait seconds " . "aggregate $opts{aggregate} did not reach " . "the expected expected relocation status " . "$expected_relocation_status_str\nActual " . "relocation status : " . $actual_relocation_status; $Log->exit() if $may_exit; NACL::Exceptions::Timeout->throw($error_message); } } ## end sub wait_for_arl_status sub _check_moved_volume_state { $Log->enter() if $may_enter; my ( $pkg_or_obj, @args ) = @_; # validate the parameters my %opts = $pkg_or_obj->_common_validate_with( params => \@args, additional_spec => { aggregate => { type => SCALAR }, volume => { type => SCALAR }, vserver => { type => SCALAR }, state => { type => SCALAR, default => 'online' }, 'method-timeout' => { type => SCALAR }, polling_interval => { type => SCALAR }, }, ignore_primary_keys => 1 ); my $volume = delete $opts{volume}; my $vserver = delete $opts{vserver}; my $aggregate = delete $opts{aggregate}; my $state = delete $opts{state}; my $timeout = delete $opts{'method-timeout'}; my $polling_interval = delete $opts{polling_interval}; # query NACL::CS::Volume to see status. my $found = 1; my $end_time = time() + $timeout; my $vol_cs_obj; while ($found) { try { $vol_cs_obj = NACL::CS::Volume->fetch( %opts, requested_fields => ['state'], is_system_vol => 0, filter => { volume => $volume, vserver => $vserver, aggregate => $aggregate } ); if ( $vol_cs_obj->state ne $state ) { my $vol_obj = $vol_cs_obj->get_component_instance(); $vol_obj->wait_on_attribute( 'method-timeout' => $timeout, attribute_to_check => "state", till_value => [$state], polling_interval => $polling_interval ); } $found = 0; } ## end try catch NACL::Exceptions::NoElementsFound with { # When volume move operation is complete # then the volume entry is removed from # "volume move status" Tharn::snooze(POLL_DELTA); }; if ( time() > $end_time ) { $Log->exit() if $may_exit; NACL::Exceptions::Timeout->throw( "After waiting for $timeout seconds 'state' of volume $volume " . " in aggregate $aggregate is not expected $state " ); } } ## end while ($found) $Log->exit() if $may_exit; } ## end sub _check_moved_volume_state sub _reloc_timeout_based_on_build_arch { $Log->enter() if $may_enter; my ( $self, @args ) = @_; my %opts = validate_with( params => \@args, spec => { command_interface => { isa => 'NACL::C::CommandInterface::ONTAP' }, } ); if ( !$self->_aggr_migration_timeout() ) { my $vm = $opts{command_interface}->version_manager(); my $promoted = $vm->is_promoted(); my $timeout; if ( !$promoted ) { $timeout = $vm->is_debug() ? PER_AGGR_RELOCATE_DEBUG : PER_AGGR_RELOCATE_NON_DEBUG; } else { $timeout = PER_AGGR_RELOCATE_NON_DEBUG; } $self->_aggr_migration_timeout($timeout); } $Log->debug( 'ARL timeout : ' . $self->_aggr_migration_timeout ); $Log->exit() if $may_exit; return $self->_aggr_migration_timeout(); } ## end sub _reloc_timeout_based_on_build_arch 1;