# $Id$ # This is a prototype. It needs documentation. # The field representation is incomplete: # # Copyright (c) 2001-2010 NetApp, Inc., All Rights Reserved # Any use, modification, or distribution is prohibited # without prior written consent from NetApp, Inc. # ## @summary VolumeClone ComponentState Module ## @author Dheeraj.K@netapp.com, dl-nacl-dev@netapp.com ## @status shared ## @pod here =head1 NAME NACL::CS::VolumeClone =head1 DESCRIPTION C is a derived class of L. It represents the state of an ONTAP Volume Clone. A related class is L, which represents access to an ONTAP Volume, it has two different component states depending on which methods you call (NACL::CS::Volume and NACL::CS::VolumeClone). =head1 ATTRIBUTES The individual pieces of data that are part of the state of the element are the attributes of the ComponentState. =over =item C<< vserver >> =item C<< flexclone >> =item C<< parent_volume >> =item C<< parent_snapshot >> =item C<< junction_path >> =item C<< space_guarantee >> =item C<< space_guarantee_enabled >> =item C<< aggregate >> =item C<< dsid >> =item C<< msid >> =item C<< size >> =item C<< used >> =item C<< split_estimate >> =item C<< state >> =item C<< inodes_processed >> =item C<< inodes_total >> =item C<< inode_percentage_complete >> =item C<< blocks_scanned >> =item C<< blocks_updated >> =item C<< comment >> =item C<< use_snaprestore_license >> Filled in for CMode CLI. =item C<< foreground >> Filled in for CMode CLI. =item C<< type >> Filled in for CMode CLI. =item C<< qos_policy_group >> Filled in for CMode CLI. =item C<< external_cache >> External Cache Policy Name Filled in for CMode CLI. =item C<< caching_policy >> Caching Policy Name Filled in for CMode CLI. =item C<< junctionFileHandle >> Junction File Handle Filled in for CMode CLI. =item C<< parent_msid >> FlexClone Master Data Set ID Filled in for CMode CLI. =item C<< parent_vol_type >> Parent volume volAccess type Filled in for CMode CLI. =item C<< parent_snapshot_uuid >> UUID of parent snapshot Filled in for CMode CLI. =back =cut package NACL::CS::VolumeClone; use strict; use warnings; use Params::Validate qw(:all); use NACL::ComponentUtils qw(_dump_one); use NATE::Log qw(log_global); my $Log = log_global(); my $may_enter = $Log->may_enter(); my $may_exit = $Log->may_exit(); use NACL::Exceptions::NoElementsFound qw(:try); use Data::Dumper; use base 'NACL::CS::ComponentState::ONTAP'; use Class::MethodMaker [ scalar => "vserver", scalar => "flexclone", scalar => "parent_volume", scalar => "parent_snapshot", scalar => "junction_path", scalar => "junction_active", scalar => "space_guarantee", scalar => "space_guarantee_enabled", scalar => "aggregate", scalar => "dsid", scalar => "msid", scalar => "size", scalar => "used", scalar => "split_estimate", scalar => "state", scalar => "inodes_processed", scalar => "inodes_total", scalar => "inode_percentage_complete", scalar => "blocks_scanned", scalar => "blocks_updated", scalar => "comment", scalar => 'use_snaprestore_license', scalar => 'foreground', scalar => 'type', scalar => 'qos_policy_group', scalar => 'external_cache', scalar => 'caching_policy', scalar => 'junctionFileHandle', scalar => 'parent_msid', scalar => 'parent_vol_type', scalar => 'parent_snapshot_uuid', ]; =head1 METHODS =head2 fetch my $vol_clone_state = NACL::CS::VolumeClone->fetch(command_interface=>$ci,...); my @vol_clone_states = NACL::CS::VolumeClone->fetch(command_interface=>$ci,...); see L =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 = shift; my @state_objs = $pkg->SUPER::fetch( @_, choices => [ { method => "_fetch_cmode_cli", interface => "CLI", set => "CMode", }, { method => "_fetch_cmode_zapi", interface => "ZAPI", set => "CMode", }, { method => '_fetch_7mode_cli', interface => 'CLI', set => '7Mode' }, { method => '_fetch_7mode_zapi', interface => 'ZAPI', set => '7Mode' } ], show_cmd => 'volume clone show', exception_text => 'No matching volume clone(s) found' ); $Log->exit() if $may_exit; return wantarray ? @state_objs : $state_objs[0]; } ## end sub fetch sub _fetch_cmode_cli { my $pkg = shift; return $pkg->SUPER::_fetch_cmode_cli(@_, api => "volume_clone_show"); } sub _fetch_cmode_zapi { $Log->enter() if $may_enter; my ($pkg, @args) = @_; my $map = { 'flexclone' => ['volume'], 'space-guarantee' => ['space-reserve'] }; my $copy = [ qw(vserver aggregate dsid junction-active junction-path msid parent-snapshot parent-volume size space-guarantee-enabled split-estimate used state inodes-processed inodes-total inode-percentage-complete blocks-scanned blocks-updated) ]; my @state_objs; try { @state_objs = $pkg->SUPER::_fetch_cmode_zapi( @args, api => 'volume-clone-get-iter', copy => $copy, map => $map, ); } catch NACL::APISet::Exceptions::ResponseException with { my $exception = $_[0]; # See burt 656827 if ($exception->text() !~ /Volume.*not found/i) { $Log->exit() if $may_exit; $exception->throw(); } }; $Log->exit() if $may_exit; return @state_objs; } ## end sub _fetch_cmode_zapi sub _fetch_7mode_cli { $Log->enter() if $may_enter; my ($pkg, @args) = @_; my @state_objs = $pkg->_fetch_7mode(@args, _interface => 'CLI'); $Log->exit() if $may_exit; return @state_objs; } ## end sub _fetch_7mode_cli sub _fetch_7mode_zapi { $Log->enter() if $may_enter; my ($pkg, @args) = @_; my @state_objs = $pkg->_fetch_7mode(@args, _interface => 'ZAPI'); $Log->exit() if $may_exit; return @state_objs; } ## end sub _fetch_7mode_zapi # For both CLI and ZAPI, the implementation is virtually identical (we use # NACL::CS::Volume). This is a common implementation with the # interface-specific portions handled. sub _fetch_7mode { $Log->enter() if $may_enter; my ($pkg, @args) = @_; my %opts = validate_with( params => \@args, spec => { %{$pkg->_fetch_backend_validate_spec()}, _interface => {type => SCALAR} } ); my $interface = $opts{_interface}; my $apiset = $opts{apiset}; my $requested_fields = $opts{requested_fields}; my $filter = $opts{filter}; # There's no separate "vol clone status" in 7Mode. A lot of the fields # can be obtained through commands that are run for NACL::CS::Volume # For those fields we simply reuse that implementation. require NACL::CS::Volume; my $vol_filter = {}; if (defined $filter->{flexclone}) { $vol_filter->{volume} = $filter->{flexclone}; } my $timeout = $opts{'method-timeout'} || 1200; my $all_fields = [ qw(space-guarantee space-guarantee-enabled aggregate dsid msid size used state) ]; my $vol_req_fields = $pkg->_requested_fields_intersection( all_fields => $all_fields, requested_fields => $requested_fields ); my @vol_cs = NACL::CS::Volume->fetch( command_interface => $opts{command_interface}, requested_fields => $vol_req_fields, filter => $vol_filter, 'method-timeout' => $timeout, apiset_must => {interface => $interface}, allow_empty => 1, ); my @state_objs; foreach my $each_vol (@vol_cs) { if ($each_vol->clone_volume() eq 'true') { my $obj = $pkg->new(command_interface => $opts{command_interface}); my $row = {}; $pkg->_hash_copy( source => $each_vol, target => $row, copy => [ qw(space_guarantee space_guarantee_enabled aggregate dsid msid size used state junction_path) ], map => { volume => 'flexclone', clone_parent_name => 'parent-volume', clone_parent_bsnap_name => 'parent-snapshot' } ); $obj->_set_fields(row => $row); # ZAPI also has a "volume-clone-split-estimate" but it does not # return the split estimate, so we don't invoke it (instead it # returns an "estimate-blocks", which doesn't map to anything # in any of the other modes/interfaces) if ($interface eq 'CLI') { if ($pkg->_want_any_field_of( requested_fields => $requested_fields, filter => $filter, fields_filled_by_api => [qw(split-estimate)] ) ) { my $response = $apiset->vol_clone_split_estimate( volume => $row->{flexclone}); my $output = $response->get_parsed_output(); $obj->split_estimate($output->[0]{split_estimate}); } ## end if ( $pkg->_want_any_field_of... } ## end if ( $interface eq 'CLI') push @state_objs, $obj; } ## end if ( $each_vol->clone_volume... } ## end foreach my $each_vol (@vol_cs) $Log->exit() if $may_exit; return @state_objs; } ## end sub _fetch_7mode # Determine the intersection between the requested fields passed in # by the user and the fields that can be filled in by NACL::CS::Volume # This method returns the intersection as an array-reference # all_fields - All fields which NACL::CS::Volume fills in # requested_fields - The value that the user passes sub _requested_fields_intersection { $Log->enter() if $may_enter; my $pkg = shift; my %opts = validate( @_, { all_fields => {type => ARRAYREF}, requested_fields => {type => ARRAYREF} } ); my $all_fields = $opts{all_fields}; my $requested_fields = $opts{requested_fields}; # Name of the volume is a must. Also, knowing whether it's a clone-volume # or not is also a must. my @fields_always_needed = (qw(volume clone-volume)); if (@$requested_fields) { my %all_fields_hash; foreach my $field (@$all_fields) { $all_fields_hash{$field} = 1; } my @intersection_fields; foreach my $req_field (@$requested_fields) { if (exists $all_fields_hash{$req_field}) { push @intersection_fields, $req_field; } } push @intersection_fields, @fields_always_needed; $Log->exit() if $may_exit; return \@intersection_fields; } else { $Log->exit() if $may_exit; my @fields = (@$all_fields, @fields_always_needed); return \@fields; } } ## end sub _requested_fields_intersection 1;