# # Copyright (c) 2012 NetApp, Inc., All Rights Reserved # Any use, modification, or distribution is prohibited # without prior written consent from NetApp, Inc. ## @summary Vserver Peer MTask Module ## @author anbumozh@netapp.com dl-nacl-dev@netapp.com ## @status shared ## @pod here package NACL::MTask::VserverPeer; use base qw(NACL::MTask::MTask); use strict; use warnings; use NACL::ComponentUtils qw(_hash_move); use NACL::MTask::ClusterPeer; use NACL::STask::VserverPeer; 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 HASHREF OBJECT ARRAYREF); use NATE::Exceptions::Argument qw(:try); use NACL::ComponentUtils qw(Dumper); use Class::MethodMaker [ new => [ '-hash', 'new' ], scalar => 'vserver', scalar => 'peer_vserver', scalar => [ { -type => 'NACL::C::CommandInterface::ONTAP' }, 'home_cluster_interface', ], scalar => [ { -type => 'NACL::C::CommandInterface::ONTAP' }, 'remote_cluster_interface', ], scalar => 'home_cluster_name', scalar => 'remote_cluster_name', scalar => '_was_cluster_peer_created' ]; =head1 NAME NACL::MTask::VserverPeer =head1 DESCRIPTION C provides a number of well-defined but potentially complex or multi-step methods related to Vserver Peer in ONTAP. This task is built on top of L and L =head1 ATTRIBUTES =head2 home_cluster_interface A component object of C that represents a node in home cluster. =head2 remote_cluster_interface A component object of C that represents a node in remote cluster. =head2 vserver vserver name =head2 peer_vserver Peer vserver name =head2 home_cluster_name Home cluster name =head2 remote_cluster_name Remote cluster name =cut =head1 METHODS =head2 create create (Class or Instance Method) $vserverpeer = NACL::MTask::VserverPeer->create( home_cluster_interface => $home_cluster_interface, # required remote_cluster_interface => $remote_cluster_interface, # optional nacltask_lif_details => \%nacltask_lif_details, # optional home_cluster_name => $home_cluster_name # required remote_cluster_name => $remote_cluster_name # optional vserver => $vserver_name # required peer-vserver => $peer_vserver # required nacltask_if_exists_lifs => $action_lif, # default 'reuse' nacltask_if_exists_cluster_peer => $action, # default 'reuse' nacltask_if_exists_vserver_peer => $action, # default 'die' nacltask_verify => 1, # default 0 _was_created => \$was_created # optional ); Creates vserver-peer relationship on nodes specified by home_cluster_interface and remote_cluster_interface attribute. This method provides additional services beyond what's inherent to the product's vserver peer create command, as controlled and described by the "nacltask_if_exists_vserver_peer" option. It also takes care of vserver-peer related dependencies such as creating cluster peer relationship. Perform the following step to create vserver-peer: 1) If remote_cluster_name is not specified it just creates the intra cluster vserver peer relationship alone else it creates cluster peer relationship and then create the inter cluster vserver peer relationship. 2) Executes "vserver peer create" on $home_cluster_interface 3) Incase of intercluster vserver peering ,it executes "vserver peer accept" on $remote_cluster_interface 4) verifies vserver peer relationship This method returns an object of type NACL::MTask::VserverPeer =over =item Options =over =item home_cluster_interface, remote_cluster_interface, nacltask_lif_details, nacltask_if_exists_lifs , nacltask_if_exists_cluster_peer and other options are described in L =item vserver, peer-vserver, peer-type, peer-cluster and all other options are described in L =item C<< home_cluster_name >> (Required) Name of the home cluster =item C<< remote_cluster_name >> (Optional) Name of the remote cluster =item C<< nacltask_if_exists_vserver_peer => $action >> (Optional) What to do if the vserver-peer is setup already. If $action is "die" the default), then fail with an exception (in the same way that the vserver-peer component would have: by trying the vserver-peer create and letting the product complain about the existence of vserver-peer setup). If action is "reuse", then do nothing (return a task object referring to the existing vserver-peer). If action is "purge", then destroy the vserver-peer (see the C method, below) before creating a new one. =item C<< _was_created => \$scalar >> (Optional) When this option is provided with a reference to a scalar variable, the variable gets filled in with a boolean value describing whether the vserver peer relation was found (value will be 0; this scenario is possible when nacltask_if_exists_peer => "reuse") or whether the vserver peer relation was created (value will be 1). This is necessary to determine whether the vserver peer relation needs to be cleaned up later. my $was_created; my $vserver_peer_obj = NACL::MTask::VserverPeer->create( nacltask_if_exists => 'reuse', _was_created => \$was_created, %other_opts ); # Operate on $vserver_peer_obj here # ... # Now determine whether to clean up the vserver peer, since we're not sure # whether we reused an existing vserver peer relation or created a new one if ($was_created) { # New vserver peer was created. Clean it up. $vserver_obj->purge(); } =item C<< nacltask_verify => 0|1 >> (Optional) when set to 1, vserver-peer creation will be verified. - when set to 0, the verification step is skipped. - by default its set to 0. =item C<< "method-timeout" => $scalar >> (Optional) As component method-timeout, controls how long the command will wait before completing. However, the default timeout has been raised to 60 seconds. =item apiset_must, apiset_should, all the other options supported by , stop method in Vserver.pm See L<< NACL::STask::VserverPeer->create|lib-NACL-STask-VserverPeer-pm/create >> =back =back =cut sub create { $Log->enter() if $may_enter; my ( $pkg_or_obj, @args ) = ( @_ ); my %cluster_peer_opts; my %opts = $pkg_or_obj->_common_validate_with( params => \@args, additional_spec => { nacltask_if_exists_vserver_peer => { type => SCALAR, default => "die" }, nacltask_if_exists_cluster_peer => { type => SCALAR, default => "reuse" }, _was_created => { type => SCALARREF, optional => 1 }, home_cluster_name => { type => SCALAR }, remote_cluster_name => { type => SCALAR, optional => 1 }, home_cluster_interface => { type => OBJECT, isa => 'NACL::C::CommandInterface::ONTAP' }, remote_cluster_interface => { type => OBJECT, isa => 'NACL::C::CommandInterface::ONTAP', optional => 1 }, 'method-timeout' => { type => SCALAR, default => 60 }, nacltask_verify => { type => SCALAR, default => 0 } }, ); my $home_cluster_name = delete $opts{home_cluster_name}; my $remote_cluster_name = delete $opts{remote_cluster_name}; my $home_cluster_interface = delete $opts{home_cluster_interface}; my $remote_cluster_interface = delete $opts{remote_cluster_interface}; my $was_created = delete $opts{_was_created}; my $verify = $opts{nacltask_verify}; $opts{nacltask_if_exists} = delete $opts{nacltask_if_exists_vserver_peer}; my $was_cluster_peer_created = delete $opts{_was_cluster_peer_created}; $$was_created = 0; $pkg_or_obj->_hash_move( source => \%opts, target => \%cluster_peer_opts, map => { 'nacltask_if_exists_cluster_peer' => 'nacltask_if_exists_peer' }, move => [qw(nacltask_lif_details nacltask_if_exists_lifs)] ); my $obj = $pkg_or_obj->new( home_cluster_interface => $home_cluster_interface, home_cluster_name => $home_cluster_name, vserver => $opts{vserver}, peer_vserver => $opts{'peer-vserver'}, ); if ( defined $remote_cluster_name && ( $home_cluster_name ne $remote_cluster_name ) ) { $cluster_peer_opts{'home_cluster_interface'} = $home_cluster_interface; $cluster_peer_opts{'remote_cluster_interface'} = $remote_cluster_interface; $Log->debug( "Opts to ClusterPeer create call: " . Dumper( \%cluster_peer_opts ) ); NACL::MTask::ClusterPeer->create(%cluster_peer_opts); $obj->remote_cluster_name($remote_cluster_name); $obj->remote_cluster_interface($remote_cluster_interface); $obj->_was_cluster_peer_created(1); $opts{'peer-cluster'} = $remote_cluster_name || $opts{'peer-cluster'} ; } my %additional_opts; if ($remote_cluster_interface) { $additional_opts{remote_interface} = $remote_cluster_interface; } NACL::STask::VserverPeer->create( %opts, %additional_opts, command_interface => $home_cluster_interface, ); $$was_created = 1; $Log->exit() if $may_exit; return $obj; } ## end sub create =head2 purge NACL::MTask::VserverPeer->purge( home_cluster_interface => $home_cluster_interface, #Required remote_cluster_interface => $remote_cluster_interface, #Optional vserver => $vserver, #Required 'peer-vserver' => $peer_vserver ); or $VserverPeer->purge(nacltask_delete_cluster_peer => 1); #default 0 (Class or instance method) This method deletes a vserver-peer on the nodes. When called as an instance method ,if cluster peer was created by the object reference, it deletes cluster peer also =over =item Options =over =item home_cluster_interface (Required for Class Method) As C. A component object that represents a node to which commands to be sent on home cluster. =item remote_cluster_interface (Required for Class Method) As C. A component object that represents a node to which commands to be sent on home cluster. =item vserver (Required for Class Method) Name of vserver =item peer-vserver (Required for Class Method) Name of peer vserver =item nacltask_delete_cluster_peer (Optional) Only applicable for instance method. If 0(default), don't delete the cluster peer. If 1 deletes cluster peer also =item C<< home_cluster_name >> (Optional) Name of the home cluster. This is required if cluster peer needs to be purged =item C<< remote_cluster_name >> (Optional) Name of the remote cluster. =item C<< "method-timeout" => $scalar >> (Optional) As component method-timeout, controls how long the command will wait before completing. However, the default timeout has been raised to 60 seconds. =item apiset_must, apiset_should, all the other options supported by , stop method in Vserver.pm See L<< NACL::STask::VserverPeer->purge|lib-NACL-STask-VserverPeer-pm/purge >> =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 => { home_cluster_interface => { type => OBJECT, isa => 'NACL::C::CommandInterface::ONTAP' }, remote_cluster_interface => { type => OBJECT, isa => 'NACL::C::CommandInterface::ONTAP', optional => 1 }, home_cluster_name => { type => SCALAR, optional => 1 }, remote_cluster_name => { type => SCALAR, optional => 1 }, vserver => { type => SCALAR }, 'peer-vserver' => { type => SCALAR }, nacltask_delete_cluster_peer => { type => SCALAR, default => 0 }, 'method-timeout' => { type => SCALAR, default => 60 } }, ); my $vserver = delete $opts{vserver}; my $home_cluster_name = $opts{home_cluster_name}; my $remote_cluster_name = $opts{remote_cluster_name}; my $remote_cluster_interface = $opts{remote_cluster_interface}; my $peer_vserver = delete $opts{'peer-vserver'}; my $home_cluster_interface = $opts{home_cluster_interface}; my $delete_cluster_peer = delete $opts{'nacltask_delete_cluster_peer'}; my $was_cluster_peer_created = delete $opts{_was_cluster_peer_created}; my %common_opts; $pkg_or_obj->_copy_common_component_params( source => \%opts, target => \%common_opts, ); my %opts_for_vs_purge = ( command_interface => $home_cluster_interface, vserver => $vserver, 'peer-vserver' => $peer_vserver, %common_opts ); if ( defined $remote_cluster_name && $home_cluster_name ne $remote_cluster_name ) { $opts_for_vs_purge{remote_interface} = $remote_cluster_interface; } NACL::STask::VserverPeer->purge(%opts_for_vs_purge); if ( $was_cluster_peer_created || $delete_cluster_peer ) { #Check and see if there are any vserver peer relationship exists,if not #then purge the cluster peer relation try{ NACL::STask::VserverPeer->find( %common_opts, command_interface => $home_cluster_interface, filter => { vserver => $vserver, 'peer-vserver' => $peer_vserver }, ); } catch NACL::Exceptions::NoElementsFound with { my $hcluster = delete $opts{home_cluster_name}; my $rcluster = delete $opts{remote_cluster_name}; NACL::MTask::ClusterPeer->purge( %opts,%common_opts, unique_key_for_home_cluster => { 'cluster' => $home_cluster_name }, unique_key_for_remote_cluster => { 'cluster' => $remote_cluster_name } ); }; } $Log->exit() if $may_exit; } sub _common_validate_with { $Log->enter() if $may_enter; my $pkg_or_obj = shift; my %opts = validate_with( params => \@_, spec => { params => { type => ARRAYREF }, additional_spec => { type => HASHREF, default => {} }, allow_extra => { optional => 1 }, }, ); my %params = @{ $opts{params} }; my %spec = %{ $opts{additional_spec} }; my @keys = qw (home_cluster_interface remote_cluster_interface vserver peer_vserver home_cluster_name remote_cluster_name _was_cluster_peer_created); if ( ref $pkg_or_obj ) { foreach my $key (@keys) { my $key_isset = "${key}_isset"; if ( $params{$key} && $pkg_or_obj->$key_isset() ) { NATE::Exceptions::Argument->throw( "Option '$key' not allowed (it is already an " . 'attribute of this object' ); } ## end if ( $params{$key} ) if ( $pkg_or_obj->$key_isset() ) { my $value = $pkg_or_obj->$key(); $key =~ s/_/-/g if ( $key eq "peer_vserver" ); $params{$key} = $value; } } ## end foreach my $key (@keys) } ## end if ( ref $pkg_or_obj ) # Any argument to a method call can either be of the type specified in # the call to _common_validate_with (i.e. scalar or arrayref) or can be # an object. This makes OBJECT be a valid type for all arguments while ( my ( $key, $value ) = each %spec ) { $value->{type} = $value->{type} | OBJECT if ( defined $value->{type} ); } $Log->exit() if $may_exit; return validate_with( params => \%params, spec => \%spec, allow_extra => 1, ); } ## end sub _common_validate_with 1;