# # Copyright (c) 2014 NetApp, Inc., All Rights Reserved # Any use, modification, or distribution is prohibited # without prior written consent from NetApp, Inc. # ## @summary VserverIscsi Task Module ## @author rahula@netapp.com, dl-nacl-dev@netapp.com ## @status public ## @pod here package NACL::STask::VserverIscsi; use strict; use warnings; use base qw(NACL::C::VserverIscsi 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 :types); use NACL::Exceptions::NoElementsFound qw(:try); use NATE::Exceptions::Argument (); use NACL::C::Exceptions::VserverIscsi::IscsiServiceExists (); use NACL::C::Exceptions::VserverIscsi::CannotRemoveServiceWhileEnabled (); use NACL::C::Exceptions::VserverIscsi::CannotFindService (); use NATE::BaseException qw(:try); =head1 NAME NACL::STask::VserverIscsi =head1 DESCRIPTION C provides a number of well-defined but potentially complex or multi-step methods related to VserverIscsi in 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 vserver-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 vserver (Required) The name of the Vserver to be created. =head2 job_component (Optional) A job component (NACL::C::Job) representing the last job that operated on this vserver. At the moment this will only get filled in for the job used to create this vserver iscsi (if this task object was used to create this vserver iscsi) =head1 METHODS =head2 create my $vserver_obj = NACL::STask::VserverIscsi->create( command_interface => $command_interface, vserver => $vserver_name, nacltask_if_exists => $action, # default 'die' nacltask_to_cleanup => 1, nacltask_cleanup_manager => $cleanupobj, %other_options ); (Class Method) Create a vserver iscsi. This method provides additional services beyond what's inherent to the product's vserver iscsi creation commands, as controlled and described by the "nacltask_if_exists" option. =over =item Options =over =item C<< nacltask_if_exists=>$action >> (Optional) What to do if the vserver to be created already exists. If $action is "die" (the default), then fail with an exception (in the same way that the vserver iscsi component would have: by trying the vserver iscsi create and letting the product complain about the vserver iscsi already existing). If action is "reuse", then do nothing (return a task object referring to the existing vserver iscsi). If action is "purge", then delete the vserver iscsi (see the C method, below) before creating a new one. =item C<< nacltask_verify => 1|0 >> (Optional) This option is used to verify whether the particular iscsi service is created for the vserver. The default value is 0. =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 vserver iscsi was found (value will be 0; this scenario is possible when nacltask_if_exists => "reuse") or whether the vserver iscsi was created (value will be 1). This is necessary to determine whether the vserver iscsi needs to be cleaned up later. my $was_created; my $vs_iscsi_obj = NACL::STask::VserverIscsi->create( nacltask_if_exists => 'reuse', _was_created => \$was_created, %other_opts ); # Operate on $vs_iscsi_obj here # ... # Now determine whether to clean up the vserver iscsi, since we're not sure # whether we reused an existing vserver iscsi or created a new one if ($was_created) { # New vserver was created. Clean it up. $vs_iscsi_obj->purge(); } =item C<< "method-timeout" => 600 >> (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 C<< nacltask_to_cleanup => 0|1 >> (Optional, defaults to 0(no to cleanup)) Flag indicating if this operation need to be registered for cleanup 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 other various options described in L<< NACL::C::VserverIscsi->create|lib-NACL-C-VserverIscsi-pm/create >> are supported by NACL::STask::VserverIscsi->create as well. =back =back =over =item Exceptions =over =item C This type of exception gets thrown if an attempt is made to create a iscsi service for a vserver that is already configured. =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_verify => {type => SCALAR, default => 0}, _was_created => {type => SCALARREF, 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_if_exists = delete $opts{nacltask_if_exists}; my $verify = delete $opts{nacltask_verify}; my $was_created = delete $opts{_was_created}; $$was_created = 0; my $self; CREATE: { use warnings qw(exiting); try { $self = $pkg->SUPER::create(%opts); $$was_created = 1; $pkg->taskverify_create(%opts) if $verify; } catch NACL::C::Exceptions::VserverIscsi::IscsiServiceExists with { my $exception = shift; $self = $pkg->_element_exists_handler( create_opts => \%opts, nacltask_if_exists => $nacltask_if_exists, exception => $exception ); if (!$self) { no warnings qw(exiting); redo CREATE; } }; } # 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 $VserverIscsi->purge(); (or) NACL::STask::VserverIscsi->purge( command_interface => $command_interface, vserver => $vserver_name, nacltask_if_purged => $if_purged, nacltask_verify => 1, # default 0 %other_options ); (Class or Instance method) Deletes the ISCSI for the particular vserver. =over =item Options =over =item C<< command_interface => $ci >> (Required for class method, Not Applicable for instance method) A component object that represents the host which to send commands. See NACL::C::Component::command_interface =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) If "die", exception is thrown when the ISCSI to be deleted does not exist If "pass", exits quietly when the ISCSI to be deleted does not exist =item command_interface, apiset_must, apiset_should, etc. All of the other options refer to L<< NACL::C::VserverIscsi->delete|lib-NACL-C-VserverIscsi-pm/delete >> =back =back =over =item Exceptions =over =item C This type of exception gets thrown if an attempt is made to delete a iscsi service for a vserver that is already in running state. =item C This type of exception gets thrown if an attempt is made to delete a iscsi service for a vserver that is already deleted. =back =back =cut sub purge { $Log->enter() if $may_enter; my ($pkg_or_obj, @args) = @_; my %orig_opts = $pkg_or_obj->_common_validate_with( params => \@args, additional_spec => { nacltask_verify => {type => BOOLEAN, default => 0}, nacltask_if_purged => {type => BOOLEAN, default => 0}, }, allow_extra => 1, ); my %nacltask_opts; $pkg_or_obj->_move_nacltask_options( source => \%orig_opts, target => \%nacltask_opts ); my $ci = $orig_opts{'command_interface'}; my $vserver = $orig_opts{'vserver'}; my $verify = $nacltask_opts{'nacltask_verify'}; my $if_purged = $nacltask_opts{nacltask_if_purged}; AGAIN: { use warnings; try { $pkg_or_obj->delete(%orig_opts); } catch NACL::C::Exceptions::VserverIscsi::CannotRemoveServiceWhileEnabled with { NACL::C::VserverIscsi->stop( command_interface => $ci, vserver => $vserver, ); no warnings; redo AGAIN; } catch NACL::C::Exceptions::VserverIscsi::CannotFindService with { my $exception_obj = shift; if ($if_purged !~ /pass/i) { $Log->exit() if $may_exit; $exception_obj->throw(); } }; } if ($verify) { $pkg_or_obj->_generic_purge_verify(%orig_opts); } $Log->exit() if $may_exit; } ## end sub purge =head2 start #method call description NACL::STask::VserverIscsi->start( 'command_interface' => $Node, vserver => $Vserver, nacltask_wait => $flag, nacltask_to_cleanup => 1, nacltask_cleanup_manager => $cleanupobj, ); (Class call) or $vserveriscsi->start(); (Instance call) (Class or Instance method) This method is used to start iscsi service for a particular vserver . =over =item Options =over =item C<< command_interface => $Node >> (Required) Specifies the interface of the host on which the TASK is performed . =item C<< "method-timeout" => $timeout >> (Optional) Specifies the time in seconds to wait for the iscsi to be in running state. Default :: 600secs . =item C<< nacltask_wait => $flag >> (Optional) This options is used as a flag . If set to 1 , the method will wait until the method-timeout for the start command to be completed , else (set to 0) it would skip the wait process . =item C<< polling_interval => $interval >> (Optional) If nacltask_wait is set to 1, this is the interval at which to poll the filer for the value of the "status-admin" field. Default :: 10secs =item C<< nacltask_to_cleanup => 0|1 >> (Optional, defaults to 0(no to cleanup)) Flag indicating if this operation need to be registered for cleanup or not. =item C<< nacltask_cleanup_manager >> Cleanup manager to be used for registering. Default : Will use the default cleanup manager. =item C<< nacltask_if_started=>die|pass >> (Optional) If "die", exception is thrown when the ISCSI service is already started If "pass", exits quietly when the ISCSI service is already started =item apiset_must, apiset_should, method-timeout, all the other options supported by, start method in VserverIscsi.pm See L<< NACL::C::VserverIscsi->start|lib-NACL-C-VserverIscsi-pm/start >> =back =back =cut sub start { $Log->enter() if $may_enter; my $pkg_or_obj = shift; my %opts = $pkg_or_obj->_common_validate_with( params => \@_, additional_spec => { "method-timeout" => {type => SCALAR, default => 600}, polling_interval => {type => SCALAR, default => 10}, nacltask_wait => {type => BOOLEAN, default => 1}, $pkg_or_obj->_cleanup_validate_spec(), nacltask_if_started => { type => SCALAR, optional => 1, callbacks => $pkg_or_obj->_if_action_completed_already_validate_callback() }, }, allow_extra => 1, ); #Extracting all the nacltask related options my $command_interface = $opts{command_interface}; my $nacltask_wait = delete $opts{nacltask_wait}; my (%opts_for_cleanup, %opts_for_register, $nacltask_to_cleanup); my $if_started = delete $opts{nacltask_if_started} || 'die'; my $already_started = 0; $pkg_or_obj->_move_common_cleanup_opts( source => \%opts, target => \%opts_for_cleanup, ); my (%wait_for_start_opts, %common_opts); $pkg_or_obj->_copy_common_component_params_with_ci( source => \%opts, target => \%common_opts ); %wait_for_start_opts = %common_opts; $pkg_or_obj->_hash_move( source => \%opts, target => \%wait_for_start_opts, move => [qw(polling_interval)] ); try { #Performing vserver iscsi start operation $pkg_or_obj->SUPER::start(%opts); } catch NACL::C::Exceptions::VserverIscsi::ServiceAlreadyStarted with { my $e = shift; $already_started = 1; if ($if_started !~ /pass/i) { $Log->exit() if $may_exit; $e->throw(); } }; if ($nacltask_wait and !$already_started) { $pkg_or_obj->wait_on_attribute( vserver => $opts{vserver}, attribute_to_check => 'status-admin', till_value => ['up'], %wait_for_start_opts, ); } ## end if ($nacltask_wait) # Register this resource with the Cleanup Manager for cleanup $pkg_or_obj->_copy_common_opts_for_cleanup( 'source' => {%opts, %opts_for_cleanup}, 'target' => \%opts_for_register, 'nacltask_to_cleanup' => \$nacltask_to_cleanup, 'to_cleanup' => 'stop' ); $pkg_or_obj->_register_for_cleanup(%opts_for_register) if ($nacltask_to_cleanup); $Log->exit() if $may_exit; } ## end sub start =head2 stop #method call description NACL::STask::VserverIscsi->stop( 'command_interface' => $Node, vserver => $Vserver, "method-timeout" => $timeout, nacltask_wait => $flag, ); (Class call) or $vserveriscsi->stop(); (Instance call) (Class or Instance method) This method is used to stop the iscsi service for a particular vserver. =over =item Options =over =item C<< command_interface => $Node >> (Required) Specifies the interface of the host on which the TASK is performed . =item C<< vserver => $vserver >> (Required) Specifies the vserver name on which the iscsi service should be stopped. =item C<< "method-timeout" => $timeout >> (Optional) Specifies the time in seconds to wait for iscsi service to stop . Default :: 600secs . =item C<< nacltask_wait => $flag >> (Optional) This options is used as a flag . If set to 1 , the method will wait until the method-timeout for the stop command to be completed , else (set to 0) it would skip the wait process . =item C<< nacltask_if_stopped=>die|pass >> (Optional) If "die", exception is thrown when the ISCSI service is already stopped If "pass", exits quietly when the ISCSI service is already stopped =item C<< polling_interval => $interval >> (Optional) If nacltask_wait is set to 1, this is the interval at which to poll the filer for the value of the "admin-state" field. Default :: 20secs =item apiset_must, apiset_should, method-timeout, all the other options supported by , stop method in VserverIscsi.pm See L<< NACL::C::VserverIscsi->stop|lib-NACL-C-VserverIscsi-pm/stop >> =back =back =cut sub stop { $Log->enter() if $may_enter; my $pkg_or_obj = shift; my %opts = $pkg_or_obj->_common_validate_with( params => \@_, additional_spec => { "method-timeout" => {type => SCALAR, default => 600}, polling_interval => {type => SCALAR, default => 20}, nacltask_wait => {type => BOOLEAN, default => 1}, nacltask_if_stopped => { type => SCALAR, optional => 1, callbacks => $pkg_or_obj->_if_action_completed_already_validate_callback() }, }, allow_extra => 1, ); #Extracting all the nacltask related options my $command_interface = $opts{command_interface}; my $nacltask_wait = delete $opts{nacltask_wait}; my $if_stopped = delete $opts{nacltask_if_stopped} || 'die'; my $already_stopped = 0; my (%wait_for_stop_opts, %common_opts); $pkg_or_obj->_copy_common_component_params_with_ci( source => \%opts, target => \%common_opts ); %wait_for_stop_opts = %common_opts; $pkg_or_obj->_hash_move( source => \%opts, target => \%wait_for_stop_opts, move => [qw(polling_interval)] ); try { #Performing vserver iscsi stop operation $pkg_or_obj->SUPER::stop(%opts); } catch NACL::C::Exceptions::VserverIscsi::ServiceAlreadyStopped with { my $e = shift; $already_stopped = 1; if ($if_stopped !~ /pass/i) { $Log->exit() if $may_exit; $e->throw(); } }; if ($nacltask_wait and !$already_stopped) { $pkg_or_obj->wait_on_attribute( vserver => $opts{vserver}, attribute_to_check => 'status-admin', till_value => ['down'], %wait_for_stop_opts, ); } ## end if ($nacltask_wait) $Log->exit() if $may_exit; } ## end sub stop 1;