# This is a prototype and serves as an example. It still needs # documentation. # # Copyright (c) 2001-2016 NetApp, Inc., All Rights Reserved # Any use, modification, or distribution is prohibited # without prior written consent from NetApp, Inc. # ## @summary VolumeQuotaReport ComponentState Module ## @author dl-nacl-dev@netapp.com ## @status shared ## @pod here =head1 NAME NACL::CS::VolumeQuotaReport =head1 DESCRIPTION C is a derived class of L. Object(s) of this type are returned when NACL::C::VolumeQuota->report() is invoked. (This module does not represent the state of any element, but is an object repesentation of the output obtained when quota reports are queried) =head1 ATTRIBUTES The individual pieces of data that are part of the state of the VolumeQuotaReport element are the attributes of the VolumeQuotaReport ComponentState. =over =item C<< tree >> Filled in for CMode CLI/ZAPI/SNMP, 7Mode CLI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value 7Mode CLI: For "filter": Applicable, Filtering will be done by Components. For "requested_fields", Not applicable, but the field will be populated in the CS object. =item C<< index >> Filled in for CMode CLI. =item C<< vserver >> Filled in for CMode CLI/ZAPI/SNMP. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< volume >> Filled in for CMode CLI/ZAPI/SNMP, 7Mode CLI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value 7Mode CLI: For "filter": Applicable, Filtering will be done by Components. For "requested_fields", Not applicable, but the field will be populated in the CS object. =item C<< quota_type >> Filled in for CMode CLI/ZAPI/SNMP, 7Mode CLI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value 7Mode CLI: For "filter": Applicable, Filtering will be done by Components. For "requested_fields", Not applicable, but the field will be populated in the CS object. =item C<< quota_target >> Filled in for CMode CLI/ZAPI, 7Mode CLI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value 7Mode CLI: For "filter": Applicable, Filtering will be done by Components. For "requested_fields", Not applicable, but the field will be populated in the CS object. =item C<< quota_target_id >> Filled in for CMode CLI/SNMP. =item C<< disk_used >> Filled in for CMode CLI/ZAPI/SNMP, 7Mode CLI. Maps to: 7Mode CLI: For "filter": Applicable, Filtering will be done by Components. For "requested_fields", Not applicable, but the field will be populated in the CS object. =item C<< disk_limit >> Filled in for CMode CLI/ZAPI/SNMP, 7Mode CLI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value 7Mode CLI: For "filter": Applicable, Filtering will be done by Components. For "requested_fields", Not applicable, but the field will be populated in the CS object. =item C<< files_used >> Filled in for CMode CLI/ZAPI/SNMP, 7Mode CLI. Maps to: 7Mode CLI: For "filter": Applicable, Filtering will be done by Components. For "requested_fields", Not applicable, but the field will be populated in the CS object. =item C<< file_limit >> Filled in for CMode CLI/ZAPI/SNMP, 7Mode CLI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value 7Mode CLI: For "filter": Applicable, Filtering will be done by Components. For "requested_fields", Not applicable, but the field will be populated in the CS object. =item C<< threshold >> Filled in for CMode CLI/ZAPI/SNMP, 7Mode CLI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value 7Mode CLI: For "filter": Applicable, Filtering will be done by Components. For "requested_fields": -s (programmatic name: soft-limit) =item C<< soft_disk_limit >> Filled in for CMode CLI/ZAPI/SNMP, 7Mode CLI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value 7Mode CLI: For "filter": Applicable, Filtering will be done by Components. For "requested_fields": -s (programmatic name: soft-limit) =item C<< soft_file_limit >> Filled in for CMode CLI/ZAPI/SNMP, 7Mode CLI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value 7Mode CLI: For "filter": Applicable, Filtering will be done by Components. For "requested_fields: -s (programmatic name: soft-limit) =item C<< quota_specifier >> Filled in for CMode CLI/SNMP, 7Mode CLI. Maps to: 7Mode CLI: For "filter": Applicable, Filtering will be done by Components. For "requested_fields", Not applicable, but the field will be populated in the CS object. =item C<< vfiler >> Filled in for 7Mode CLI. Maps to: 7Mode CLI: For "filter": Applicable, Filtering will be done by Components. For "requested_fields": -s (programmatic name: soft-limit) =item C<< path >> Path Filled in for 7Mode/CMode CLI. Maps to: 7Mode CLI: For "filter": path name (Programmatic name: path) For "requested_fields", Not applicable, but the field will be populated in the CS object. =item C<< snmp_id_type >> Filled in for CMode SNMP. Value of qrV2IdType/qrV3IdType. Indicates which one of C or C is valid. =item C<< snmp_id >> Filled in for CMode SNMP. Value of qrV2Id/qrV3Id. Only valid when snmp_id_type is qrV2IdValid/qrV3IdValid. =item C<< snmp_sid >> Filled in for CMode SNMP. Value of qrV2Sid/qrV3Sid. Only valid when snmp_id_type is qrV2SidValid/qrV3SidValid. =item C<< snmp_quota_unlimited >> Filled in for CMode SNMP. Value of qrV2QuotaUnlimited/qrV3QuotaUnlimited. =item C<< snmp_file_quota_unlimited >> Filled in for CMode SNMP. Value of qrV2FileQuotaUnlimited/qrV3FileQuotaUnlimited. =item C<< snmp_soft_quota_unlimited >> Filled in for CMode SNMP. Value of qrV2SoftQuotaUnlimited/qrV3SoftQuotaUnlimited. =item C<< snmp_soft_file_quota_unlimited >> Filled in for CMode SNMP. Value of qrV2SoftFileQuotaUnlimited/qrV3SoftFileQuotaUnlimited. =item C<< snmp_threshold_unlimited >> Filled in for CMode SNMP. Value of qrV2ThresholdUnlimited/qrV3ThresholdUnlimited. =back =head2 ADDITIONAL FILTER FIELDS The fetch method also allows the following options to be passed in the filter even though they are not MethodMaker fields. =over =item C<< path >> =back =cut package NACL::CS::VolumeQuotaReport; use feature 'state'; use strict; use warnings; use Data::Dumper; use List::MoreUtils qw(each_arrayref); use Params::Validate qw(validate validate_pos); 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::Util::QuotaLibSingleton; use NACL::Exceptions::NoElementsFound qw(:try); use base 'NACL::CS::ComponentState::ONTAP'; use NACL::CS::ComponentState::ZapiSkip qw(make_zapi_skip); use NACL::CS::ComponentState::ZapiArray qw(make_zapi_array); use Class::MethodMaker [ scalar => 'tree', scalar => 'index', scalar => 'vserver', scalar => 'volume', scalar => 'quota_type', scalar => 'quota_target', array => 'quota_target_id', scalar => 'disk_used', scalar => 'disk_limit', scalar => 'files_used', scalar => 'file_limit', scalar => 'threshold', scalar => 'soft_disk_limit', scalar => 'soft_file_limit', scalar => 'disk_used_pct_soft_disk_limit', scalar => 'disk_used_pct_threshold', scalar => 'disk_used_pct_disk_limit', scalar => 'files_used_pct_soft_file_limit', scalar => 'files_used_pct_file_limit', scalar => 'quota_specifier', array => 'quota_user_name', #Internal temporary attribute array => 'quota_users', #A valid ZAPI-only attribute scalar => 'quota_target_str', #New Internal attribute to normalize quota_target for both CLI and ZAPI # specific to 7Mode scalar => 'vfiler', scalar => 'path', # specific to SNMP scalar => 'snmp_id_type', scalar => 'snmp_id', scalar => 'snmp_sid', scalar => 'snmp_quota_unlimited', scalar => 'snmp_file_quota_unlimited', scalar => 'snmp_soft_quota_unlimited', scalar => 'snmp_soft_file_quota_unlimited', scalar => 'snmp_threshold_unlimited', ]; =head1 METHODS =head2 fetch my $VolumeQuotaReport_state = NACL::CS::VolumeQuotaReport->fetch(command_interface => $ci, ...); my @VolumeQuotaReport_states = NACL::CS::VolumeQuotaReport->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. Supports CMode CLI/ZAPI/SNMP, 7Mode CLI. Invokes "quota-report-iter" API for CMode ZAPI. Walks C or C for CMode SNMP. Invokes "quota report" command for 7Mode CLI. =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, %opts) = @_; my $quota_singleton = NACL::Util::QuotaLibSingleton->get(); $opts{apiset_must} = $quota_singleton->apiset_must(%opts); $opts{apiset_should} = $quota_singleton->apiset_should(%opts); my @state_objs = $pkg->SUPER::fetch( %opts, choices => [ { method => '_fetch_cmode_cli', interface => 'CLI', set => 'CMode', }, { method => '_fetch_7mode_cli', interface => 'CLI', set => '7Mode', }, { method => '_fetch_cmode_zapi', interface => 'ZAPI', set => 'CMode', }, { method => '_fetch_cmode_snmp', check => '_fetch_cmode_snmp_check', interface => 'SNMP', set => 'CMode', }, ], show_cmd => 'volume quota report', exception_text => 'No matching volume quota report(s) found' ); $Log->exit() if $may_exit; return wantarray ? @state_objs : $state_objs[0]; } ## end sub fetch sub _fetch_cmode_cli { my $pkg = shift; my @state_objs = $pkg->SUPER::_fetch_cmode_cli(@_, api => 'volume_quota_report'); #quota_target_str is to normalize the quota_target field in the quota report for both CLI and ZAPI. #In CLI, quota_target may be a string of user names separated by ','. But, in ZAPI, quota_target #may be a reference to an array of User Names. See burt999809 for more info. foreach my $state_obj (@state_objs) { my $quota_type = $state_obj->{'quota_type'}; if( $quota_type ) { if(($quota_type eq 'user') || ($quota_type eq 'group')) { if( $state_obj->{'quota_target'} ) { $state_obj->{'quota_target_str'} = $state_obj->{'quota_target'}; } } elsif( $quota_type eq 'tree' ) { #quota_target is actually the tree ID in CLI and we do not want to use the ID as #the string of quota_target. #So, use the tree name for quota_target_str in CLI, instead. if( $state_obj->{'tree'} ) { $state_obj->{'quota_target_str'} = $state_obj->{'tree'}; } } } } return @state_objs; } sub _fetch_7mode_cli { my $pkg = shift; my %opts = validate @_, $pkg->_fetch_backend_validate_spec(); my $apiset = $opts{apiset}; my $filter = $opts{filter}; my ($response, $caught_exception, %api_args); $api_args{'connectrec-timeout'} = $opts{'method-timeout'} || 1200; my %req_field_and_filter = ( requested_fields => $opts{requested_fields}, filter => $filter ); # By default invoke with -x option $api_args{'all-id-single-line'} = 1; # Invoke with "-t" if the threshold field is required if ($pkg->_want_any_field_of( %req_field_and_filter, fields_filled_by_api => [qw(threshold)] ) ) { $api_args{'warning-threshold'} = 1; } ## end if ( $pkg->_want_any_field_of...) # Invoke with "-s" if any of the soft limit values are required if ($pkg->_want_any_field_of( %req_field_and_filter, fields_filled_by_api => [qw(soft-file-limit soft-disk-limit)] ) ) { $api_args{'soft-limit'} = 1; } ## end if ( $pkg->_want_any_field_of...) # Invoke with "-v" if the vfiler value is required if ($pkg->_want_any_field_of( %req_field_and_filter, fields_filled_by_api => [qw(vfiler)] ) ) { $api_args{vfiler} = 1; } ## end if ( $pkg->_want_any_field_of...) # "quota report" allows us to filter by path if (exists $filter->{path}) { $api_args{path} = $filter->{path}; } try { $response = $apiset->quota_report(%api_args); } catch NACL::APISet::Exceptions::InvalidParamValueException with { # A caught exception indicates that the quota being looked for # does not exist. We catch the exception and return immediately. The # 'fetch' frontend decides whether to throw a NoElementsFound # exception based on the value of 'allow_empty' $caught_exception = 1; }; return if ($caught_exception); my $output = $response->get_parsed_output(); my @state_objs; foreach my $row (@$output) { my $final_attributes = $pkg->_hash_copy( source => $row, copy => [qw( tree volume vfiler )], map => { 's_file_limit' => 'soft-file-limit', 'files_used' => 'files-used', 'file_limit' => 'file-limit', 'quota_specifier' => 'quota-specifier', 'disk_limit' => 'disk-limit', 'type' => 'quota-type', 'id' => 'quota-target', 's_disk_limit' => 'soft-disk-limit', 'k_bytes_used' => 'disk-used', 't_hold' => 'threshold', }, ); # "quota report" displays the values of the space consumption and disk # limit fields in multiples of 4KB. Convert to bytes here. # Thus the numbers are reported in multiples of 4KB, not in units # of 4KB. The units are KB, and should always be divisible by 4 foreach my $size_field ( qw(disk-used disk-limit threshold soft-disk-limit)) { if (Scalar::Util::looks_like_number( $final_attributes->{$size_field} ) ) { $final_attributes->{$size_field} *= 1024; } ## end if ( Scalar::Util::looks_like_number...) } ## end foreach my $size_field (...) $final_attributes->{'quota-target-id'} = $row->{id}; my $obj = $pkg->new(); $obj->_set_fields(row => $final_attributes); push @state_objs, $obj; } ## end foreach my $row (@$output) return @state_objs; } ## end sub _fetch_7mode_cli sub _fetch_cmode_zapi { $Log->enter() if $may_enter; my $pkg = shift; my %opts = validate @_, $pkg->_fetch_backend_validate_spec(); my %pass_through_opts = (); my $filter = $opts{'filter'}; if (defined($filter) && defined($filter->{path})) { # "quota report" allows us to filter by path $pass_through_opts{path} = $filter->{path}; } my @state_objs = $pkg->SUPER::_fetch_cmode_zapi( @_, api => 'quota-report-iter', copy => [ qw(file-limit volume threshold vserver soft-file-limit quota-target disk-limit quota-type soft-disk-limit tree disk-used files-used quota-users disk-used-pct-soft-disk-limit disk-used-pct-threshold disk-used-pct-disk-limit files-used-pct-soft-file-limit files-used-pct-file-limit ) ], map => { #quota-user-id would be used as target id during primary key #generation in NACL/UnitTest/C/Quota.thpl 'quota_target_id' => [ make_zapi_array('quota-users'), make_zapi_skip('quota-user'), make_zapi_skip('quota-user-id') ], #Capture quota_user_name in the state_obj 'quota_user_name' => [ make_zapi_array('quota-users'), make_zapi_skip('quota-user'), make_zapi_skip('quota-user-name') ], }, pass_through_opts => \%pass_through_opts, ); #Assign quota_user_name to quota_target in case of user and group quotas foreach my $state_obj (@state_objs) { my $quota_type = $state_obj->{"quota_type"}; if( !($state_obj->{"quota_specifier"}) ) { #There is no quota_specifier field in the quota report of ZAPI. #But, quota_target is actually quota_specifier for ZAPI. if( $state_obj->{"quota_target"} ) { $state_obj->{"quota_specifier"} = $state_obj->{"quota_target"}; } } #quota_target_str is to normalize the quota_target field in the quota report for both CLI and ZAPI. #In CLI, quota_target may be a string of user names separated by ','. But, in ZAPI, quota_target #may be a reference to an array of User Names. See burt999809 for more info. if( $quota_type ) { if ($quota_type eq "user" || $quota_type eq "group" ) { if( $state_obj->{"quota_user_name"} ) { $state_obj->{"quota_target"} = $state_obj->{"quota_user_name"}; } if( $state_obj->{"quota_target"} ) { if( ref($state_obj->{"quota_target"}) && (ref($state_obj->{"quota_target"}) eq 'ARRAY') ) { #Must be a ref to an array of User Names. #Convert the array to a string of user names separated by ',' like the CLI format. $state_obj->{"quota_target_str"} = join ',', @{$state_obj->{"quota_target"}}; } else { $state_obj->{"quota_target_str"} = $state_obj->{"quota_target"}; } } } elsif( $quota_type eq 'tree' ) { if( $state_obj->{"quota_target"} ) { $state_obj->{"quota_target_str"} = $state_obj->{"quota_target"}; } } } # Delete the quota_user_name field in the object, since we don't have # this key in CLI Quota Report. if( $state_obj->{"quota_user_name"} ) { delete $state_obj->{"quota_user_name"}; } } $Log->exit() if $may_exit; return @state_objs; } ## end sub _fetch_cmode_zapi use constant SNMP_ID_FIELDS => qw(snmp_id_type snmp_id snmp_sid); use constant LIMIT_FIELDS => qw(disk-limit file-limit soft-disk-limit soft-file-limit threshold); use constant SNMP_UNLIMITED_FIELDS => qw(snmp_quota_unlimited snmp_file_quota_unlimited snmp_soft_quota_unlimited snmp_soft_file_quota_unlimited snmp_threshold_unlimited); sub _fetch_cmode_snmp_map { $Log->enter() if $may_enter; my $self = shift; validate_pos(@_); my $quota_singleton = NACL::Util::QuotaLibSingleton->get(); my ($prefix,) = $quota_singleton->snmp_report_table() =~ /^(qrV[23])/; state $base_map = [ [vserver => 'Vserver' ], [volume => 'VolumeName' ], ['quota-type' => 'Type' ], ['quota-specifier' => 'PathName' ], [tree => 'Tree' ], ['disk-used' => 'KBytesUsed' ], ['files-used' => 'FilesUsed' ], ['disk-limit' => 'KBytesLimit' ], ['file-limit' => 'FileLimit' ], ['soft-disk-limit' => 'KBytesSoftLimit' ], ['soft-file-limit' => 'SoftFileLimit' ], [threshold => 'KBytesThreshold' ], [snmp_id_type => 'IdType' ], [snmp_id => 'Id' ], [snmp_sid => 'Sid' ], [snmp_quota_unlimited => 'QuotaUnlimited' ], [snmp_file_quota_unlimited => 'FileQuotaUnlimited' ], [snmp_soft_quota_unlimited => 'SoftQuotaUnlimited' ], [snmp_soft_file_quota_unlimited => 'SoftFileQuotaUnlimited' ], [snmp_threshold_unlimited => 'ThresholdUnlimited' ], ]; my @prefix_map = map { my ($field, $snmp_name) = @$_; my $bits = (($prefix eq 'qrV2') && ($snmp_name =~ /^KB/)) ? 64 : ''; $field => "${prefix}${bits}${snmp_name}"; } @$base_map; $Log->exit() if $may_exit; return @prefix_map; } ## end sub _fetch_cmode_snmp_map sub _fetch_cmode_snmp { $Log->enter() if $may_enter; my $pkg = shift; my %opts = validate @_, $pkg->_fetch_backend_validate_spec(); my $requested_fields; my ($field, $snmp_unlimited_field, $itr); if (defined($opts{requested_fields})) { my %requested_fields_hash = map { $_ => 1 } @{$opts{requested_fields}}; $itr = each_arrayref([LIMIT_FIELDS], [SNMP_UNLIMITED_FIELDS]); while ((($field, $snmp_unlimited_field) = $itr->())) { if (exists($requested_fields_hash{$field})) { $requested_fields_hash{$snmp_unlimited_field} = 1; } } if (exists($requested_fields_hash{'quota-target-id'})) { map { $requested_fields_hash{$_} = 1; } SNMP_ID_FIELDS; } if (exists($requested_fields_hash{'quota-specifier'})) { $requested_fields_hash{volume} = 1; $requested_fields_hash{tree} = 1; $requested_fields_hash{'quota-type'} = 1; } $requested_fields = [keys(%requested_fields_hash)]; } delete $opts{requested_fields}; # Complexity of translating the filter to work with SNMP isn't worth # it. Delete the troublesome fields here. But to keep things behaving # as expected, we'll save the original filter and apply after we translate # the fetched state objects. my $orig_filter = delete $opts{filter}; my $filter = defined($orig_filter) ? {%$orig_filter} : {}; foreach my $field (qw(quota-type quota-target-id disk-used quota-specifier), LIMIT_FIELDS) { delete $filter->{$field}; } my $quota_singleton = NACL::Util::QuotaLibSingleton->get(); my $table = $quota_singleton->snmp_report_table(); my $apiset = $opts{apiset}; my %orig_session_attributes = %{$apiset->get_session_attributes()}; $apiset->set_session_attributes(retries => 3, timeout => 10); my @state_objs; try { @state_objs = $pkg->SUPER::_fetch_snmp( %opts, baseoid => "netapp1_quota_$table", requested_fields => $requested_fields, filter => $filter, map => { $pkg->_fetch_cmode_snmp_map() }, ); } catch NACL::APISet::Exceptions::NoMatchingEntriesException with { $Log->debug("Caught NoMatchingEntriesException, returning empty " . "state object list to the frontend"); } finally { $apiset->set_session_attributes(%orig_session_attributes); }; my $row = 0; foreach my $state_obj (@state_objs) { $Log->debug(' - $state_objs[' . $row++ . ']:'); # If fetched, remap the snmp type value to a CLI-compatible value my $snmp_type; if ($state_obj->quota_type_isset()) { state $snmp_type_mapping = { qrV2TypeUser => 'user', qrV2TypeGroup => 'group', qrV2TypeTree => 'tree', qrV2TypeUserDefault => 'user', qrV2TypeGroupDefault => 'group', qrV2TypeTreeDefault => 'tree', qrV3TypeUser => 'user', qrV3TypeGroup => 'group', qrV3TypeTree => 'tree', qrV3TypeUserDefault => 'user', qrV3TypeGroupDefault => 'group', qrV3TypeTreeDefault => 'tree', }; $snmp_type = $state_obj->quota_type(); my $mapped_type = $snmp_type_mapping->{$snmp_type}; if (!defined($mapped_type)) { NACL::Exceptions::UnexpectedOutputException->throw('The ' . 'SNMP walk for NACL::CS::VolumeQuotaReport::fetch' . "returned an unexpected qrV3Type value ($snmp_type)" ); } $Log->debug("Mapped SNMP type => '$snmp_type' " . "to CLI quota-type => '$mapped_type'"); $state_obj->quota_type($mapped_type); } # Populate quota-target-id from snmp_id or snmp_sid, whichever is # appropriate given snmp_id_type if ($state_obj->snmp_id_type_isset()) { if (($state_obj->snmp_id_type() =~ /qrV[23]IdValid/) && $state_obj->snmp_id_isset()) { $Log->debug("SNMP id type indicates the id field is " . "valid, using it to populate quota-target-id"); $state_obj->quota_target_id([$state_obj->snmp_id()]); } elsif (($state_obj->snmp_id_type() =~ /qrV[23]SidValid/) && $state_obj->snmp_sid_isset()) { $Log->debug("SNMP id type indicates the sid field is " . "valid, using it to populate quota-target-id"); $state_obj->quota_target_id([$state_obj->snmp_sid()]); } } # Due to a bug, qrV2Table presented sizes as bytes, even though # the field names indicate they are in kilobytes; so multiply # qrV3Table values by 1024 for compatability with the CLI if ($state_obj->disk_used_isset() && ($table eq 'qrV3Table')) { $state_obj->disk_used($state_obj->disk_used() * 1024); } # Build CLI-compatible limit fields out of the separate limit and # unlimited fields that SNMP uses $itr = each_arrayref([LIMIT_FIELDS], [SNMP_UNLIMITED_FIELDS]); while ((($field, $snmp_unlimited_field) = $itr->())) { my $field_isset = "${field}_isset"; if ($state_obj->$field_isset()) { my $mapped_limit = $state_obj->$field(); if (($field !~ /file-limit/) && ($table eq 'qrV3Table')) { $mapped_limit *= 1024; } if ($state_obj->$snmp_unlimited_field() eq 'true') { $Log->debug("Mapped $snmp_unlimited_field => 'true' " . "to CLI $field => '-'"); $mapped_limit = '-'; } $state_obj->$field($mapped_limit); } } # Convert a qtree quota specifier from /vol// to if ($state_obj->quota_specifier_isset() && ($snmp_type =~ /qrV[23]TypeTree/)) { my $quota_specifier = $state_obj->quota_specifier(); my $qtree_path = "/vol/" . $state_obj->volume() . "/" . $state_obj->tree(); if ($quota_specifier eq $qtree_path) { $Log->debug("SNMP path name for a tree record is in " . "the form '/vol//', populating " . "CLI quota-specifier with ''"); $state_obj->quota_specifier($state_obj->tree()); } } } local $Data::Dumper::Maxdepth = 2; $Log->debug("Before _apply_filter: " . Dumper(\@state_objs)); $pkg->SUPER::_apply_filter( state_objs => \@state_objs, filter => $orig_filter, return_on_mismatch => 1, ); $Log->exit() if $may_exit; return @state_objs; } ## end sub _fetch_cmode_snmp sub _fetch_cmode_snmp_check { $Log->enter() if $may_enter; my ($pkg, @opts) = @_; state $unsupported = [qw(index quota-target path quota_target_str)]; my @fields = $pkg->_invalid_fields_check(@opts, _fields => $unsupported); if (@fields) { $Log->exit() if $may_exit; NACL::Exceptions::InvalidChoice->throw('Could not use SNMP ' . 'since required_fields or filter specifies the following ' . 'unsupported attributes: ' . join(', ', @fields) . "\n"); } $Log->exit() if $may_exit; } ## end sub _fetch_cmode_snmp_check # Overriding because "path" is not an attribute of the # object but this field will be present in the filter when state() is # invoked on a component object sub _extra_filter_fields { $Log->enter() if $may_enter; $Log->exit() if $may_exit; return ['path']; } sub _update_state_objs_cmode_zapi { my ($pkg, %opts) = @_; $pkg->SUPER::_update_state_objs_cmode_zapi( %opts, additional_translations => { size_to_bytes => { method => '_zapi_output_translate_size', fields_to_translate => [ 'disk-used', 'disk-limit', 'soft-disk-limit', 'threshold' ] }, }, ); # rewrite quota_target (with dependency on quota_type, volume) foreach my $state_obj (@{$opts{state_objs}}) { $state_obj->quota_target( $pkg->_zapi_output_translate_target( $state_obj->quota_type(), $state_obj->volume(), $state_obj->quota_target(), ) ); } } # ZAPI returns field in terms of KBytes. Normalize to Bytes. sub _zapi_output_translate_size { my ($pkg, $val) = @_; $val *= 1024; return $val; } sub _zapi_output_translate_target { my ($pkg, $type, $volume, $target) = @_; if ($type eq 'tree') { if ($target =~ qr/^\/vol\/($volume)\/(.+)$/) { # $2 is the qtree name return $2; } elsif ($target =~ qr/^\"\/vol\/($volume)\/(.+)\"$/) { # "$2" is the qtree name return '"'.$2.'"'; # with quoting } } return $target; } 1;