# # # Copyright (c) 2009-2010 NetApp Inc. # All rights reserved. # ## @summary Provide an exception class that is a subclass of ## NATE::BaseException that will be thrown when a 'find' or 'fetch' ## returns no objects matching the query ## ## @author madhavs@netapp.com, dl-nacl-dev@netapp.com ## @status Shared ## @pod here =pod =head1 Package Name NATE::Exceptions::NoElementsFound =head1 Author/Maintainer Madhav Shekar, dl-nacl-dev =head1 Description An exception for when a 'find' or 'fetch' returns no objects matching the query Has gather_diagnostics() defined. If gather_diagnostics is called, then diagnostic commands will be executed to provide more info for triage =head1 EXAMPLE # Diagnostics for NACL::C::NoElementsFound try { # Some command } catch NACL::C::NoElementsFound with { # Get the NoElementsFound obj $exception_obj = shift; # If relevant, provide the arguments to fetch/find # The arguments are needed for gather_diagnostics to work. # # Note: the fetch_args needed are the fetch_args given to # NACL::CS::ComponentState::fetch() # # $exception_obj->pkg_name( ...e.g. 'NACL::CS::StorageAggregate'...); # #exception_obj->fetch_args( ...\%some_valid_fetch_args... ) # Rethrow the NoElementsFound exception $exception_obj->throw(); }; =head1 This implementation of gather_diagnostics() In this implementation of gather_diagnostics(), the diagnostics it gathers are: - reruns find/fetch without a filter =cut =head1 See Also Package inherits from the BaseException module in NATE. =head1 NACL::Exceptions::NoElementsFound =head2 Expected use Use when a 'find' or 'fetch' returns no objects matching the query. =head2 Base Class NATE::BaseException =cut package NACL::Exceptions::NoElementsFound; use base qw(NATE::BaseException); use NACL::CS::ComponentState; use Class::MethodMaker [ hash => 'fetch_args', scalar => 'pkg_name', ]; use NATE::Log qw(log_global); my $Log = log_global(); my $may_enter = $Log->may_enter(); my $may_exit = $Log->may_exit(); use NATE::BaseException qw(:try); use NACL::ComponentUtils qw(_dump_one); # Execute a diagnostic command. # For ANY exception, print out the info, but do NOT # let the exception propagate up the call stack. # We print and ignore the exception because the exception # was generated by diagnostics, NOT by the actual code # that is being tested. sub _exec_diagnostic_cmd { my ($self, %args) = @_; my $description = $args{description}; my $command = $args{command}; $Log->comment("=============================================="); $Log->comment("== $description"); $Log->comment("=============================================="); try { $command->(); } catch NATE::BaseException with { # Print out the exception, then don't do anything else my $exception_obj = shift; $Log->comment( $exception_obj->stringify() ); }; $Log->comment("=============================================="); $Log->comment("== End of diagnostic cmd"); $Log->comment("=============================================="); } # gather_diagnostics should print out commands that help # a developer triage the source of the mount failure # from the Client that attempted the Mount. # # Assumption(s): fetch_args and pkg_name are set. sub gather_diagnostics { my $self = shift; my %fetch_args = $self->fetch_args(); my $pkg_name = $self->pkg_name(); return if (!keys %fetch_args); $self->_exec_diagnostic_cmd( description => "Re-run NACL::C::*->find/fetch() without filter arg", command => sub { # Remove the filter my %filter = %{delete $fetch_args{filter}}; # Check for empty case if (!keys %filter) { $Log->comment("No filter was provided, so the command was not". " rerun without the filter"); return; } # Print the filter to the logs $Log->comment("== Printing the fields of the filter"); $Log->comment(_dump_one(\%filter)); # Re-run fetch, now that the filter is removed. my @cs = $pkg_name->fetch( %fetch_args ); $Log->comment('Details present in returned CS objects'); foreach my $obj (@cs) { my @values = map { "$_=" . $obj->$_() } (keys %filter); $Log->comment(join ('; ', @values)); } }, ); } 1;