# # Copyright (c) 2001-2013 NetApp, Inc., All Rights Reserved # Any use, modification, or distribution is prohibited # without prior written consent from NetApp, Inc. # ## @summary VserverCifsShare task module ## @author anerudh@netapp.com, dl-nacl-dev@netapp.com ## @status shared ## @pod here =head1 NAME NACL::STask::VserverCifsShare =head1 DESCRIPTION C provides a number of methods related to CIFS Shares. It builds on top of and is a derived class of C. This means that any functionality present in L will also be present in this STask object. (functionality which is multi-step will have overridden implementations defined here, single step functionality will be directly re-used from the component) =head1 ATTRIBUTES =head2 command_interface (Required) A component object that represents the host to which to send commands. =head2 share-name (Required) The name of the share that this object represents =head2 vserver (Optional) The name of the vserver on which this share exists (applicable for CMode only) =cut package NACL::STask::VserverCifsShare; use strict; use warnings; use NACL::C::Volume; use NATE::Exceptions::Argument qw(:try); 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 SCALARREF OBJECT); use base qw/NACL::C::VserverCifsShare NACL::STask::STask/; use NACL::C::Exceptions::VserverCifsShare::AlreadyExists (); use NACL::C::Exceptions::VserverCifsShare::DoesNotExist (); use NACL::STask::_Mixins::CifsConfigReplayUtils qw(wait_for_cifs_share_replay); # define task specific attributes use Class::MethodMaker [ scalar => 'nacltask_replay_timeout' ]; =head1 METHODS =head2 new my $share_obj = NACL::STask::VserverCifsShare->create( command_interface => $ci ); This returns a new CIFS Share object. Note that this does not actually create a share, it merely returns a Perl object. =head2 find my @share_objs = NACL::STask::VserverCifsShare->find(command_interface => $ci, %other_opts); or my $share_obj = NACL::STask::VserverCifsShare->find(command_interface => $ci, %other_opts); (Class method) A constructor of sorts, which discovers which shares are present on the host. In an array context it creates an STask object for each share that is present and returns them. In a scalar context it creates an STask object for the first share that is found and returns the object. See for a more detailed description along with explanation of all the options accepted. =head2 state my $share_state_obj = $share_obj->state(); (Instance method) Fetch the current state of the share associated with this task object, and return a Component State object corresponding to this task (the returned CS object is of type L. See for a more detailed description along with explanation of all the options accepted. =head2 create my $share_obj = NACL::STask::VserverCifsShare->create( command_interface => $ci, nacltask_to_cleanup => 1, %other_options ); (Class method) Creates a share using volume / qtree / path provided, and returns an STask object representing it. Either of path or volume / qtree / additional_path should be provided so as to obtain information about the path that should be used for the cifs share creation =over =item C<< volume => $volume_name >> (Optional) This parameter is a volume name or object of type NACL::C::Volume for which the share has to be created and if an object is passed then the "command_interface" and "vserver" arguments are optional since they would be extracted from the object. (part of what is required to uniquely identify the volume). =item C<< qtree => $qtree_name >> (Optional) A qtree name. If the intention is to create a share for a qtree (part of what is required to uniquely identify the qtree). =item C<< command_interface => $cmd_interface >> (Required when Volume is not provided as an object) This is the component object that represents the host to which the commands are sent. =item C<< vserver => $vserver_name >> (Required for CMode and when Volume is not provided as an object, ignored for 7Mode) Vserver name for the share's creation =item nacltask_additional_path C<< additional_path => $additional_path_string >> (Optional) A string that indicates the path to a directory inside the volume / qtree (relative to the path of the volume/qtree itself) =item C<< 'share-name' => $share_name >> (Required) A string indicating the name of the share to be created. =item C<< _was_created => \$scalar >> (Optional) When this option is provided a reference to a scalar variable, the variable gets filled in with a boolean value describing whether the cifs share was found (value will be 0; this scenario is possible when nacltask_if_exists => "reuse") or whether the cifs share was created (value will be 1). This is necessary to determine whether the cifs share needs to be cleaned up later. my $was_created; my $share_obj = NACL::STask::VserverCifsShare->create( nacltask_if_exists => 'reuse', _was_created => \$was_created, nacltask_to_cleanup => 1, %other_opts ); # Operate on $share_obj here # ... # Now determine whether to clean up the share, since we're not sure # whether we reused an existing cifs share or created a new one if ($was_created) { # New cifs share was created. Clean it up. $share_obj->purge(); } =item C<< nacltask_replay_timeout => $val >> (Optional, SCALAR) The total timeout before complaining that the replay didn't succeed. In order for this wait not to happen, timeout can be specified as 0. The default value is 30 seconds. This is for waiting for the config change to be replayed to the nblade. This can be skipped by sending in the value as 0. =item C<< nacltask_replay_interval => $val2 >> (Optional, SCALAR) The interval between two invocations of diag nblade replay show. The default value is 5 seconds. Applicable only if the nacltask_replay_timeout value is greater than 0. =item C<< nacltask_verify => 0|1 >> (Optional, defaults to 0) Verifies whether the CIFS share created had all of the attributes as specified in the method call. Note that it is also possible to perform the verification later by calling L. This can be used for cases where ONTAP chooses to not set all attributes to the exact values specified. In the call we can specify those attributes we want verified. =item C<< nacltask_if_exists => $action >> (Optional, defaults to "die") Specifies an action to be taken if the share already exists. =over =item C An exception is thrown if a matching CIFS share already exists. =item C If a matching CIFS share is found, reuse it. =item C If a matching CIFS share is found, purge it and then create a new one. =item C<< nacltask_to_cleanup => 0|1 >> (Optional, defaults to 0(no to cleanup)) Flag indicating if this operation is to be cleaned up or not. =item C<< nacltask_cleanup_manager >> Cleanup manager to be used for registering. Default : Will use the default cleanup manager. =item Other options All of the options accpted by L are accepted by this method. =back =back =over =item Exceptions =over =item C This type of exception is thrown when an attempt is made to create a CIFS share that already exists. =item C This type of exception is thrown when verification fails for the created CIFS share. =item C This type of exception is thrown when neither of the parameters volume and path or command_interface were provided. =back =back =cut sub create { $Log->enter() if $may_enter; my $pkg = shift; my %opts = $pkg->_common_validate_with( params => \@_, additional_spec => { nacltask_additional_path => { type => SCALAR, default => "" }, nacltask_if_exists => $pkg->_if_exists_validate_spec, _was_created => { type => SCALARREF, optional => 1 }, nacltask_verify => { type => SCALAR, default => 0 }, volume => { type => SCALAR | OBJECT, optional => 1 }, 'command_interface' => { isa => 'NACL::C::CommandInterface::ONTAP', type => OBJECT, optional => 1, }, $pkg->_cleanup_validate_spec(), }, allow_extra => 1 ); my ( %opts_for_cleanup, %opts_for_register, $nacltask_to_cleanup ); $pkg->_move_common_cleanup_opts( source => \%opts, target => \%opts_for_cleanup, ); my $nacltask_options = {}; $pkg->_move_nacltask_options( source => \%opts, target => $nacltask_options ); my $was_created = delete $opts{_was_created}; $$was_created = 0; my $volume = $opts{volume}; my $path = delete $opts{path} || ""; my $qtree = delete $opts{qtree} || ""; # if both volume and path are not provided, then error out if ( !$volume && !$path ) { $Log->exit() if $may_exit; NATE::Exceptions::Argument->throw( 'Either of Volume or path are ' . 'required but neither were provided' ); } if ( !defined( $opts{'command_interface'} ) && defined( $opts{'volume'} ) && !( ref $opts{'volume'} ) ) { NATE::Exceptions::Argument->throw( 'Either of command_interface or ' . 'volume should be passed as an object to get the ' . 'command_interface but neither were provided' ); } # if path is not provided, only then construct one from volume, qtree etc. if ( !$path ) { if ( ref($volume) ) { $path = $volume->get_one_state_attribute('junction-path'); $opts{command_interface} ||= $volume->command_interface(); $opts{vserver} ||= $volume->vserver(); delete $opts{volume}; } elsif ($volume) { $path = NACL::CS::Volume->fetch( command_interface => $opts{command_interface}, requested_fields => ['junction-path'], filter => NACL::C::Volume->get_primary_keys_options(%opts), %{ $pkg->_copy_common_component_params( source => \%opts ) } )->junction_path(); delete $opts{volume}; } # if its a qtree, then append the qtree name to the path $path .= '/' . $qtree if ($qtree); $path .= '/' . $nacltask_options->{nacltask_additional_path} if($nacltask_options->{nacltask_additional_path}); $path =~ s/\/\/+/\//; } if ( ref($opts{vserver}) ) { $opts{vserver} = $opts{vserver}->vserver(); } # add path to %opts $opts{path} = $path; my $self; # now %opts has only those params required for creation CREATE: { use warnings; try { $self = $pkg->SUPER::create(%opts); $self->wait_for_cifs_share_replay(%opts, %{$nacltask_options}, method_action => 'create'); $$was_created = 1; $pkg->taskverify_create(%opts) if $nacltask_options->{nacltask_verify}; } catch NACL::C::Exceptions::VserverCifsShare::AlreadyExists with { my $exception = shift; $Log->debug("Cifs Share already Exists!"); $self = $pkg->_element_exists_handler( create_opts => \%opts, nacltask_if_exists => $nacltask_options->{nacltask_if_exists}, exception => $exception ); if ( !$self ) { no warnings qw(exiting); redo CREATE; } }; } $self->nacltask_replay_timeout($nacltask_options->{nacltask_replay_timeout}) if ($nacltask_options->{nacltask_replay_timeout}); # Register this resource with the Cleanup Manager for cleanup $pkg->_copy_common_opts_for_cleanup( 'source' => {%opts, %opts_for_cleanup}, 'target' => \%opts_for_register, 'nacltask_to_cleanup' => \$nacltask_to_cleanup, 'to_cleanup' => 'purge' ); $pkg->_register_for_cleanup(%opts_for_register) if ($nacltask_to_cleanup && $$was_created); $Log->exit() if $may_exit; return $self; } ## end sub create =head2 purge NACL::STask::VserverCifsShare->delete( command_interface => $ci, %other_options ); (Class method) Deletes a share using share-name, vserver name provided. =over =item C<< command_interface => $cmd_interface >> (Required) This is the component object that represents the host to which the commands are sent. =item C<< vserver => $vserver_name >> (Required for CMode, ignored for 7Mode) Vserver name of the share. =item C<< 'share-name' => $share_name >> (Required) A string indicating the name of the share to be deleted. =item C<< nacltask_replay_timeout => $val >> (Optional, SCALAR) The total timeout before complaining that the replay didn't succeed. In order for this wait not to happen, timeout can be specified as 0. The default value is 30 seconds. This is for waiting for the config change to be replayed to the nblade. This can be skipped by sending in the value as 0. =item C<< nacltask_replay_interval => $val2 >> (Optional, SCALAR) The interval between two invocations of diag nblade replay show. The default value is 5 seconds. Applicable only if the nacltask_replay_timeout value is greater than 0. =item C<< _was_deleted => \$scalar >> (Optional) When this option is provided a reference to a scalar variable, the variable gets filled in with a boolean value describing whether the cifs share did not exist (value will be 0; this scenario is possible when nacltask_if_purged => "pass") or whether the cifs share was deleted (value will be 1). =item C<< nacltask_verify >> (Optional) - when set to 1, share deletion will be verified. - when set to 0, the verification step is skipped. - by default its set to 0. All of the other parameters accepted by L are accepted by this method. =back =over =item Exceptions =over =item C This type of exception is thrown when an attempt is made to delete a CIFS share that does not exist. =item C This type of exception is thrown when verification fails for the deleted CIFS share. =back =back =cut sub purge { $Log->enter() if $may_enter; my $pkg_or_obj = shift; my %opts = $pkg_or_obj->_common_validate_with( params => \@_, additional_spec => { nacltask_if_purged => $pkg_or_obj->_if_action_completed_already_validate_spec(), nacltask_verify => { type => SCALAR, default => 0 }, nacltask_replay_timeout => { type => SCALAR, optional => 1} }, allow_extra => 1 ); if(!exists($opts{nacltask_replay_timeout}) && ref($pkg_or_obj)) { $opts{nacltask_replay_timeout} = $pkg_or_obj->nacltask_replay_timeout() if($pkg_or_obj->nacltask_replay_timeout_isset()); } my $nacltask_options = {}; $pkg_or_obj->_move_nacltask_options( source => \%opts, target => $nacltask_options ); # Nowm $pkg_or_obj will become the package name $pkg_or_obj = ref $pkg_or_obj if ref $pkg_or_obj; my $if_purged = $nacltask_options->{'nacltask_if_purged'}; my $was_deleted = delete $opts{_was_deleted}; $$was_deleted = 0; try { $pkg_or_obj->delete(%opts); $pkg_or_obj->wait_for_cifs_share_replay(%opts, %{$nacltask_options}, method_action => 'purge'); $$was_deleted = 1; } catch NACL::C::Exceptions::VserverCifsShare::DoesNotExist with { my $exception = shift; $Log->debug("Entry Does Not Exists!"); if ( $if_purged !~ /pass/i ) { $Log->exit() if $may_exit; $exception->throw(); } }; if ( $nacltask_options->{nacltask_verify} ) { $pkg_or_obj->_generic_purge_verify(%opts); } $Log->exit() if $may_exit; } ## end sub purge =head2 modify NACL::STask::VserverCifsShare->modify( command_interface => $command_interface, vserver => $vserver, nacltask_to_cleanup => 1, %other_options ); or $cifs_share_obj->modify(%opts); (Class or Instance method) Modify CIFS share options. This method will modify the options present for the specified CIFS share. =over =item =item C<< nacltask_verify => 0|1 >> (Optional, defaults to 0) Verifies whether all of the attributes got set to the specified value. Note that it is also possible to perform the verification later by calling L. This can be used for cases where ONTAP chooses to not set all attributes to the exact values specified. In the call we can specify those attributes we want verified. =item C<< nacltask_to_cleanup => 0|1 >> (Optional, defaults to 0(no to cleanup)) Flag indicating if this operation is to be cleaned up or not. =item C<< nacltask_cleanup_manager >> Cleanup manager to be used for registering. Default : Will use the default cleanup manager. =item other options See Lmodify|lib-NACL-C-VserverCifsShare-pm/modify> for all the other options accepted by this method. =back =cut sub modify { $Log->enter() if $may_enter; my ($pkg_or_obj, @args) = @_; my %opts = $pkg_or_obj->_common_validate_with( params => \@args, additional_spec => {$pkg_or_obj->_cleanup_validate_spec(),}, allow_extra => 1, ); my ($opts_for_register, $register_for_cleanup, %opts_for_cleanup); $pkg_or_obj->_move_common_cleanup_opts( source => \%opts, target => \%opts_for_cleanup, nacltask_to_cleanup => \$register_for_cleanup ); if ($register_for_cleanup) { $opts_for_register = $pkg_or_obj->_common_modify_for_cleanup(%opts_for_cleanup, %opts); } $pkg_or_obj->_call_method_then_verify(%opts); # Register for cleanup if $nacltask_to_cleanup is set $pkg_or_obj->_register_for_cleanup(%{$opts_for_register}) if ($register_for_cleanup); $Log->exit() if $may_exit; } ## end sub modify 1;