# $Id: //depot/prod/test/main/lib/NACL/CS/Snapvault.pm#1 $ # # Copyright (c) 2001-2012 NetApp, Inc., All Rights Reserved # Any use, modification, or distribution is prohibited # without prior written consent from NetApp, Inc. # ## @summary Snapvault ComponentState Module ## @author dl-dpg-nb-automation; dl-nacl-dev@netapp.com ## @status shared ## @pod here =head1 NAME NACL::CS::Snapvault =head1 DESCRIPTION C is a derived class of L. It represents the state of ONTAP Snapvault. A related class is L, which represents access to ONTAP snapvault. =head1 ATTRIBUTES The individual pieces of data that are part of the state of the Snapvault element are the attributes of the Snapvault ComponentState. Note that if any of the following fields are provided in requested_fields or in filter then they'd need to be provided in their hyphenated format. =over =item C<< primary_path >> =item C<< secondary_path >> =item C<< status >> =item C<< lag >> =item C<< last_transfer_type >> =item C<< current_transfer_error >> =item C<< current_transfer_type >> =item C<< progress >> =item C<< contents >> =item C<< last_transfer_from >> =item C<< last_transfer_duration >> =item C<< state >> =item C<< mirror_timestamp >> =item C<< last_transfer_size >> =item C<< base_snapshot >> =item C<< consecutive_successes >> =item C<< total_successes >> =item C<< current_failure >> =item C<< current_defer_count >> =item C<< total_failure >> =item C<< total_defer_count >> =back =cut package NACL::CS::Snapvault; use strict; use warnings; use Params::Validate qw(validate); use NATE::Log qw(log_global); my $Log = log_global(); my $may_enter = $Log->may_enter(); my $may_exit = $Log->may_exit(); use Data::Dumper; use base 'NACL::CS::ComponentState::ONTAP'; use Class::MethodMaker [ #snapvault status -l (except the common ones) scalar => 'primary_path', scalar => 'secondary_path', scalar => 'status', scalar => 'lag', scalar => 'last_transfer_type', scalar => 'current_transfer_error', scalar => 'current_transfer_type', scalar => 'progress', scalar => 'contents', scalar => 'last_transfer_from', scalar => 'last_transfer_duration', scalar => 'state', scalar => 'mirror_timestamp', scalar => 'last_transfer_size', scalar => 'base_snapshot', #snapvault status -m (except the common ones) scalar => 'consecutive_successes', scalar => 'total_successes', scalar => 'current_failure', scalar => 'current_defer_count', scalar => 'total_failure', scalar => 'total_defer_count', ]; =head1 METHODS =head2 fetch my $Snapvault_state = NACL::CS::Snapvault->fetch(command_interface => $ci, ...); my @Snapvault_states = NACL::CS::Snapvault->fetch(command_interface => $ci, ...); (Class method) Discovers which elements are present and returns their state in ComponentState objects. Called in scalar context it returns only one state object, in list context it returns all state objects. See L for a more detailed description along with a complete explanation of the options it accepts. Uses a 7Mode-CLI or Nodescope-CLI APISet. =over =item Exceptions =over =item C When there are no elements matching the query specified or elements of that type doesn't exist, then this exception will be thrown. =back =back =cut sub fetch { $Log->enter() if $may_enter; my ($pkg, @args) = @_; my @state_objs = $pkg->SUPER::fetch( @args, choices => [ { method => '_fetch_7mode_cli', interface => 'CLI', set => '7Mode|Nodescope', }, ], exception_text => 'No matching snapvault(s) found' ); $Log->exit() if $may_exit; return wantarray ? @state_objs : $state_objs[0]; } sub _fetch_7mode_cli { $Log->enter() if $may_enter; my ($pkg, @args) = @_; my %opts = validate @args, $pkg->_fetch_backend_validate_spec(); my $apiset = $opts{apiset}; my %copy_filter = %{$opts{filter}}; my @copy_requested_fields = @{$opts{requested_fields}}; my $deleted_filter = $pkg->_remove_relational_regex_filters( filter => \%copy_filter, requested_fields => \@copy_requested_fields ); my $filter = \%copy_filter; my $requested_fields = \@copy_requested_fields; my %req_field_filter = ( requested_fields => $requested_fields, filter => $filter ); # The "system-path" is a space-separated list of paths. These could # be for source/destination or both. my %cmd_opts; foreach my $arg (qw(primary-path secondary-path)) { if (defined $filter->{$arg}) { if (defined $cmd_opts{'system-path'}) { # If it already has a value, then append to it $cmd_opts{'system-path'} .= " $filter->{$arg}"; } else { # No value yet, assign this value $cmd_opts{'system-path'} = $filter->{$arg}; } } } # In all of the calls below, fields_filled_by_api will be fields # that are exclusive to that option. # Here's what's being done below: # Check if "-l" is needed, if not then check if any of the fields # of snapvault status without any options have been requested. # Then check if "-m" is needed. # If none of these return true, then only the fields common to all # 3 (i.e. "source-path" and "destination-path") are required, so # invoke snapvault status without any options. my @needed_options; if ($pkg->_want_any_field_of(%req_field_filter, fields_filled_by_api => [ qw(base-snapshot contents current-transfer-error current-transfer-type last-transfer-duration last-transfer-from last-transfer-size last-transfer-type mirror-timestamp progress) ] ) ) { push @needed_options, { long => 1 }; } elsif ($pkg->_want_any_field_of(%req_field_filter, fields_filled_by_api => [ qw(state lag status) ] ) ) { push @needed_options, {}; } if ($pkg->_want_any_field_of(%req_field_filter, fields_filled_by_api => [ qw(consecutive-successes current-defer-count current-failure total-defer-count total-failure total-successes) ] ) ) { push @needed_options, { 'success-status' => 1 }; } unless (@needed_options) { # If neither -l or -m are required, then just invoke status # without any options push @needed_options, {}; } my %objs_keyed_by_destination; my @state_objs; foreach my $option (@needed_options) { my $response = $apiset->snapvault_status(%$option, %cmd_opts); my $output = $response->get_parsed_output()->[0]{snapvault_entries}; # No matching entries unless (@$output) { $Log->exit() if $may_exit; return; } foreach my $row (@$output) { $pkg->_hash_move( source => $row, target => $row, map => { source => 'primary-path', destination => 'secondary-path' } ); if (exists $objs_keyed_by_destination{$row->{'secondary-path'}}) { my $obj = $objs_keyed_by_destination{$row->{'secondary-path'}}; $obj->_set_fields(row => $row); } else { my $obj = $pkg->new(command_interface => $opts{command_interface}); $obj->_set_fields(row => $row); push @state_objs, $obj; $objs_keyed_by_destination{$row->{'secondary-path'}} = $obj; } } } $Log->exit() if $may_exit; return @state_objs; } ## end sub _fetch_7mode_cli 1;