# Copyright (c) 2001-2013 NetApp, Inc., All Rights Reserved # Any use, modification, or distribution is prohibited # without prior written consent from NetApp, Inc. # ## @summary Vfiler Task Module ## @author smittal@netapp.com,dl-nacl-dev@netapp.com ## @status shared ## @pod here package NACL::STask::Vfiler; use strict; use warnings; use NACL::ComponentUtils qw(Dumper _optional_scalars); use base qw(NACL::C::Vfiler 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 validate_with SCALAR OBJECT BOOLEAN ); use NATE::Exceptions::Argument qw(:try); use NACL::C::Exceptions::Vfiler::DoesNotExist qw(:try); use NACL::C::Exceptions::Vfiler::AlreadyExists qw(:try); use NACL::C::Exceptions::Vfiler::AlreadyStopped qw(:try); use Data::Random qw(rand_words); use constant VFILER_TIMEOUT => 600; =head1 NAME NACL::STask::Vfiler =head1 DESCRIPTION C provides a number of well-defined but potentially complex or multi-step methods related to Vfiler in ONTAP 7Mode. 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 vfilerr-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) A component object that represents the host to which to send commands. =head2 vfiler (Required) The name of the vfiler to be created. =head1 METHODS =head2 create my $vfiler_obj = NACL::STask::Vfiler->create( command_interface => $command_interface, vfiler => $vfiler_name, nacltask_if_exists => $action, # default 'die' nacltask_wait => $boolean, # default '1' %other_options ); (Class Method) Create a vfiler. This method provides additional services beyond what's inherent to the product's vfiler creation commands, as controlled and described by the "nacltask_if_exists" and "nacltask_wait" option. =over =item Options =over =item C<< nacltask_if_exists=>$action >> (Optional) What to do if the vfiler to be created already exists. If $action is "die" (the default), then fail with an exception (in the same way that the vfiler component would have: by trying the vfiler create and letting the product complain about the vfiler already existing). If action is "reuse", then do nothing (return a task object referring to the existing vfiler). If action is "purge", then delete the vfiler (see the C method, below) before creating a new one. =item C<< nacltask_wait => 0|1 >> (Optional) If 1 (the default), wait for this vfiler to be created (see "wait_for_creation" method, below). If 0, do not wait any longer than necessary (any longer than the vfiler creation command waits). =item C<< "method-timeout" => $timeout >> (Optional) As component method-timeout, controls how long the command will wait before completing. However, the default timeout has been raised to 600 seconds. =item Other options All of the other various options described in L<< NACL::C::Vfiler->create|lib-NACL-C-Vfiler-pm/create >> are supported by NACL::STask::Vfiler->create as well. See L for a description of the arguments it accepts. =back =back =over =item Exceptions =over =item C This type of exception gets thrown if an attempt is made to create a vfiler that already exists. =back =back =cut sub create { $Log->enter() if $may_enter; my ( $pkg, @args ) = @_; my %opts = $pkg->_common_validate_with( params => \@args, additional_spec => { nacltask_if_exists => $pkg->_if_exists_validate_spec(), nacltask_wait => { type => SCALAR, default => 1 }, # "vfiler" is auto-generated if not provided, so make it # optional here _optional_scalars(qw(vfiler)) }, allow_extra => 1, ); # Transform %opts from the options we received into the options to # pass to the base class method. my $command_interface = $opts{command_interface}; my $nacltask_wait = delete $opts{nacltask_wait}; my %task_opts; $pkg->_move_nacltask_options( source => \%opts, target => \%task_opts, ); my $nacltask_if_exists = delete $task_opts{nacltask_if_exists}; $opts{'method-timeout'} ||= VFILER_TIMEOUT; my %common_opts; $pkg->_copy_common_component_params( source => \%opts, target => \%common_opts ); my $random_vfiler_name_generated; if ( !defined $opts{vfiler} ) { $random_vfiler_name_generated = 1; $opts{vfiler} = _get_rand_name(); $Log->debug( "Random name is $opts{vfiler}"); } my $self; CREATE: { use warnings qw(exiting); try { $self = $pkg->SUPER::create(%opts); if ($nacltask_wait) { $self->wait_for_creation( %common_opts, attribute_to_check => 'status', till_not_value => qr/\created\b/ ); } ## end if ($nacltask_wait) } ## end try catch NACL::C::Exceptions::Vfiler::AlreadyExists with { my $exception = shift; my $text = $exception->text(); if ($random_vfiler_name_generated) { $Log->trace( 'Random name collision, regenerate a ' . 'new name and retry' ); $opts{vfiler} = _get_rand_name(); no warnings qw(exiting); redo CREATE; } else { $Log->trace('The vfiler already exists'); $self = $pkg->_element_exists_handler( create_opts => \%opts, nacltask_if_exists => $nacltask_if_exists, exception => $exception, ); if ( !$self ) { no warnings qw(exiting); redo CREATE; } } ## end else [ if ($random_vfiler_name_generated)] }; } ## end CREATE: $Log->exit() if $may_exit; return $self; } ## end sub create =head2 purge $vfiler->purge(%other_options); NACL::STask::Vfiler->purge( command_interface => $command_interface, vfiler => $vfiler, nacltask_if_purged => "pass", nacltask_verify => 1, %other_options ); (Class or instance method) This method deletes the vfiler, as well as detaching or deleting other features that may be preventing this vfiler from being deleted. i.e -the task will stop the vfiler before deleting it. =over =item Options =over =item C<< command_interface=>$command_interface >> (Required for class method, Not Applicable for instance method) See L =item C<< apiset_must=>$ruleset >> (Optional)See L =item C<< apiset_should=>$ruleset >> (Optional)See L =item C<< vfiler=>$vfiler >> (Required for class method, Not Applicable for instance method) Name of vfiler. =item C<< nacltask_verify => $nacltask_verify_boolean >> (Optional) If '0' (default), verification will not be performed. If '1', verification will be performed to ensure that the deletion did happen successfully. =item C<< nacltask_if_purged => die | pass >> (Optional, defaults to "die") Specifies what to do if the vfiler we're trying to purge no longer exists. A value of C (the default) will result in an exception being thrown. A value of C will mean that the exception that would normally occur when we're trying to delete a vfiler that does not exist is suppressed. =back =back =over =item Exceptions =over =item C This type of exception gets thrown if an attempt is stop a vfiler that already stopped. =item C This type of exception gets thrown if an attempt is made to delete a non-existing vfiler. =back =back =cut sub purge { $Log->enter() if $may_enter; my ( $pkg_or_obj, @args ) = @_; my %opts = $pkg_or_obj->_common_validate_with( params => \@args, additional_spec => { nacltask_if_purged => $pkg_or_obj->_if_action_completed_already_validate_spec(), nacltask_verify => { type => BOOLEAN, default => 0 }, }, ); my $nacltask_if_purged = delete $opts{nacltask_if_purged}; my $nacltask_verify = delete $opts{nacltask_verify}; my $need_to_return; try { try { $pkg_or_obj->stop(%opts); } catch NACL::C::Exceptions::Vfiler::AlreadyStopped with { $Log->trace("Vfiler has already stopped"); }; $pkg_or_obj->destroy( "method-timeout" => VFILER_TIMEOUT, %opts, ); } ## end try catch NACL::C::Exceptions::Vfiler::DoesNotExist with { my $exception = shift; if ( $nacltask_if_purged eq 'die' ) { $Log->trace( 'Check if the command failed because the vfiler does not exists' ); $Log->exit() if $may_exit; $exception->throw(); } else { $need_to_return = 1; } }; ## end if ( $nacltask_if_purged...) # Used for when nacltask_if_purged => 'pass' and the vfiler isn't found # In these cases we should return immediately, rather than try the # commands after it. if ($need_to_return) { $Log->exit() if $may_exit; return; } if ($nacltask_verify) { # Verify that the vfiler was purged. This is done by checking that the # vfiler does not exist $pkg_or_obj->_generic_purge_verify(%opts); } ## end if ($nacltask_verify) $Log->exit() if $may_exit; } ## end sub purge =head2 wait_for_creation $vfiler->wait_for_creation( "method-timeout" => $timeout, ); NACL::STask::Vfiler->wait_for_creation( "method-timeout" => $timeout, command_interface => $command_interface, vfiler => $vfiler_name, attribute_to_check => 'status', till_not_value => qr/\created\b/ ); =over =item C<< command_interface=>$command_interface >> (Required for class method, Not Applicable for instance method) See L =item C<< vfiler=>$vfiler >> (Required) The name of the vfiler to be created. =item C<< "method-timeout"=>$timeout >> (Optional) How long in seconds to wait for the attribute_to_check to become "till_not_value". Defaults to 600. =item C<< polling_interval => $interval >> (Optional) The interval, in seconds, at which to poll the value of the "attribute_to_check" field. This defaults to 10 seconds if not provided. =item C<< apiset_must=>$ruleset >> (Optional)See L =item C<< apiset_should=>$ruleset >> (Optional)See L =back =cut sub wait_for_creation { $Log->enter() if $may_enter; my ( $pkg_or_obj, @args ) = @_; my %opts = $pkg_or_obj->_common_validate_with( params => \@args, additional_spec => { polling_interval => { type => SCALAR, default => 10 }, attribute_to_check => { type => SCALAR, default => "status" }, till_not_value => { type => SCALAR, default => "created" }, }, ); $opts{'method-timeout'} ||= VFILER_TIMEOUT; my $attribute_to_check = delete $opts{attribute_to_check}; my $till_not_value = delete $opts{till_not_value}; $pkg_or_obj->wait_on_attribute( %opts, attribute_to_check => $attribute_to_check, till_not_value => $till_not_value ); $Log->exit() if $may_exit; } ## end sub wait_for_creation sub _get_rand_name { my @random_words = rand_words( size => 5 ); my $rand = $random_words[rand($#random_words)] . "$$" . "_vfiler" ; return $rand; } 1;