# # Copyright (c) 2001-2017 NetApp, Inc., All Rights Reserved # Any use, modification, or distribution is prohibited # without prior written consent from NetApp, Inc. # ## @summary Lun ComponentState Module ## @author dl-nacl-dev@netapp.com ## @status shared ## @pod here =head1 NAME NACL::CS::Lun =head1 DESCRIPTION C is a derived class of L. It represents the state of an ONTAP Lun. A related class is L, which represents access to an ONTAP Lun. =head1 ATTRIBUTES The individual pieces of data that are part of the state of the Lun element are the attributes of the Lun ComponentState. =over =item C<< "device_text_id" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "isMapped" >> Is the LUN mapped to an initiator group? (As of UI change "vserver-lun-igroup-portset-rr-0" this got replaced by "is-mapped") Possible values: true; false =item C<< "clear_text_id" >> =item C<< "device_binary_id" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "uuid" >> Filled in for CMode CLI/ZAPI and 7Mode CLI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "are_vols_busy" >> =item C<< "device_id" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "staging" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "state" >> Filled in for CMode CLI/ZAPI. Maps to: CM ZAPI: 'state' $value =item C<< "space_resv_enabled" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "serial" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "igroup" >> Note that from RR onwards this field does not show up in the output of "lun show". For this reason, from RR onwards this field will not be populated in the state object. To get this value L<< NACL::CS::LunMapped->fetch|lib-NACL-CS-LunMapped-pm >> can be used. =item C<< "ostype" >> LUN OS Type Possible values: vmware | hyper_v | windows_2008 | windows_gpt | windows | linux | xen | solaris | solaris_efi | hpux | aix | netware | openvms Filled in for CMode CLI/ZAPI and 7Mode CLI Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "lun" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "tracks_per_cylinder" >> =item C<< "device_legacy_id" >> =item C<< "qtree" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "space_resv_honored" >> Builds which have the UI change "vserver-lun-igroup-portset-rr-0" will have both this field as well as "space_reserve_honored" filled into the CS object. Builds which do not contain that UI change will have only this field filled in (not "space_reserve_honored"). =item C<< "space_reserve_honored" >> Builds which have the UI change "vserver-lun-igroup-portset-rr-0" will have both this field as well as "space_reserve" filled into the CS object. Builds which do not contain that UI change will have only "space_resv_honored" filled into the CS object. =item C<< "write" >> =item C<< "file_path" >> =item C<< "clear_binary_id" >> =item C<< "suffix_size" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "share_state" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "previous_serial" >> =item C<< "sectors_per_cylinder" >> =item C<< "space_allocation" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value . =item C<< "max_resize_size" >> =item C<< "select_attribute" >> =item C<< "sectors_per_track" >> =item C<< "isOnline" >> =item C<< "sectors" >> =item C<< "block_size" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "cyl_size" >> =item C<< "creation_timestamp" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "size" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "vdiskId" >> =item C<< "offline" >> =item C<< "size_used" >> Filled in for CMode CLI/ZAPI and 7Mode CLI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "alignment" >> Filled in for CMode CLI/ZAPI and 7Mode CLI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value . =item C<< "option" >> =item C<< "extent_size" >> Filled in for CMode CLI and 7Mode CLI. =item C<< "volume" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value . =item C<< "cylinders" >> =item C<< "bytes_per_sector" >> =item C<< "vserver" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value . =item C<< "dev_size" >> =item C<< "space_alloc_enabled" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value . =item C<< "path" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value . =item C<< "space_resv" >> Space Reservation Builds which have the UI change "vserver-lun-igroup-portset-rr-0" will have both this field as well as "space_reserve" filled into the CS object. Builds which do not contain that UI change will have only this field filled in (not "space_reserve"). =item C<< "space_reserve" >> Space Reservation Builds which have the UI change "vserver-lun-igroup-portset-rr-0" will have both this field as well as "space_reserve" filled into the CS object. Builds which do not contain that UI change will have only "space_resv" filled into the CS object. =item C<< "online" >> Filled in for CMode ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< "prefix_size" >> Filled in for CMode CLI/ZAPI and 7Mode CLI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value . =item C<< "initiator" >> =item C<< "mapped" >> Filled in for CMode CLI/ZAPI and 7Mode CLI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value . This field describes whether the LUN is mapped to an initiator group. Possible values: true; false =item C<< "are_vols_onlining" >> =item C<< "comment" >> Filled in for CMode CLI/ZAPI and 7Mode CLI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value . =item C<< "read_only" >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< permission >> =item C<< inconsistent_blocks >> Filled in for CMode CLI. =item C<< read_histogram >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< write_partial >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< inconsistent_filesystem >> Filled in for CMode CLI. =item C<< is_mapped >> Filled in for CMode CLI/ZAPI. Maps to: CM ZAPI : 'mapped' $value =item C<< partition_type >> Filled in for CMode CLI/ZAPI. =item C<< write_histogram >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< nvfail >> Filled in for CMode CLI/ZAPI. =item C<< is_online >> Filled in for 7Mode. =item C<< node >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value . =item C<< bin_number >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< vserver_uuid >> Filled in for CMode CLI. =item C<< read_partial >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< partition_scheme >> Filled in for CMode CLI/ZAPI. =item C<< partition_count >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< partition_offset >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< volume_dsid >> Filled in for CMode CLI. =item C<< base_size >> Filled in for CMode CLI. =item C<< volume_msid >> Filled in for CMode CLI. =item C<< unmapped >> Filled in for CMode CLI. =item C<< is_clone >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value . =item C<< is_cad_enabled >> Filled in for CMode CLI. =item C<< qos_policy_group >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value . =item C<< restore_inaccessible >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value . =item C<< vserver_id >> Filled in for CMode CLI. =item C<< class >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< external_cache >> External Cache Policy Name Filled in for CMode CLI. =item C<< is_restore_inaccessible >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< is_clone_autodelete_enabled >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< has_metadata_provisioned >> *Has Metadata Provisioned, possible value(s) are true,false Filled in for CMode CLI. =item C<< inconsistent_import >> Inconsistent import possible value(s) are, true,false Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< caching_policy >> Filled in for CMode CLI. Caching Policy Name =item C<< qos_adaptive_policy_group >> Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value . =item C<< _7_mode_serial >> 7-mode Serial Number This is the accessor for the field '7-mode-serial'. Since it starts with a digit, we cannot have an accessor of the same name (perl doesn't allow subroutine whose names start with a digit). So the convention we follow is to have the accessor methods for such fields start with an underscore. Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: For "requested_fields", "filter" and Output mapping: $value =item C<< report_physical_size >> Filled in for 7Mode CLI. =item C<< maps >> Filled in for 7Mode CLI. =item C<< serial_7_mode >> 7-mode Serial Number Filled in for CMode CLI/ZAPI. Maps to: CMode ZAPI: =item C<< 'serial-hex' => $string >> Serial Number (Hex) Applicable for CMode CLI For "requested_fields", "filter" and Output mapping: $value =item C<< cluster_shared_volume_information >> =back =cut package NACL::CS::Lun; 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 NACL::APISet::Exceptions::InvalidParamValueException qw(:try); use NACL::APISet::Exceptions::ResponseException qw(:try); use NACL::C::_Mixins::Lun qw(:all); use base 'NACL::CS::ComponentState::ONTAP'; use Class::MethodMaker [ scalar => 'device_text_id', scalar => 'isMapped', scalar => 'clear_text_id', scalar => 'device_binary_id', scalar => 'uuid', scalar => 'are_vols_busy', scalar => 'device_id', scalar => 'staging', scalar => 'state', scalar => 'space_resv_enabled', scalar => 'igroup', scalar => 'ostype', scalar => 'lun', scalar => 'tracks_per_cylinder', scalar => 'device_legacy_id', scalar => 'qtree', scalar => 'space_resv_honored', scalar => 'space_reserve_honored', scalar => 'write', scalar => 'file_path', scalar => 'clear_binary_id', scalar => 'serial', scalar => 'suffix_size', scalar => 'share_state', scalar => 'previous_serial', scalar => 'sectors_per_cylinder', scalar => 'space_alloc', scalar => 'max_resize_size', scalar => 'select_attribute', scalar => 'sectors_per_track', scalar => 'isOnline', scalar => 'sectors', scalar => 'block_size', scalar => 'cyl_size', scalar => 'creation_timestamp', scalar => 'size', scalar => 'vdiskId', scalar => 'offline', scalar => 'size_used', scalar => 'alignment', scalar => 'option', scalar => 'extent_size', scalar => 'volume', scalar => 'cylinders', scalar => 'bytes_per_sector', scalar => 'vserver', scalar => 'dev_size', scalar => 'space_alloc_enabled', scalar => 'path', scalar => 'space_resv', scalar => 'space_reserve', scalar => 'online', scalar => 'prefix_size', scalar => 'initiator', scalar => 'mapped', scalar => 'are_vols_onlining', scalar => 'comment', scalar => 'read_only', scalar => 'permission', scalar => 'cluster_shared_volume_information', scalar => 'serial_hex', # 7Mode specific scalar => 'backed_by', scalar => 'is_staging', scalar => 'inconsistent_blocks', scalar => 'read_histogram', scalar => 'write_partial', scalar => 'inconsistent_filesystem', scalar => 'is_mapped', scalar => 'partition_type', scalar => 'write_histogram', scalar => 'nvfail', scalar => 'is_online', scalar => 'node', scalar => 'bin_number', scalar => 'space_allocation', scalar => 'vserver_uuid', scalar => 'read_partial', scalar => 'partition_scheme', scalar => 'partition_count', scalar => 'partition_offset', scalar => 'volume_dsid', scalar => 'base_size', scalar => 'volume_msid', scalar => 'unmapped', scalar => 'is_clone', scalar => 'is_cad_enabled', scalar => 'qos_policy_group', scalar => 'restore_inaccessible', scalar => 'vserver_id', scalar => 'class', scalar => 'external_cache', scalar => 'report_physical_size', scalar => 'maps', scalar => 'qos_adaptive_policy_group', #ZAPI Specific scalar => 'is_restore_inaccessible', scalar => 'multiprotocol_type', scalar => 'is_clone_autodelete_enabled', scalar => 'has_metadata_provisioned', scalar => 'inconsistent_import', scalar => 'caching_policy', scalar => '_7_mode_serial', scalar => 'serial_7_mode', ]; =head1 METHODS =head2 fetch my $Lun_state = NACL::CS::Lun->fetch(command_interface => $ci, ...); my @Lun_states = NACL::CS::Lun->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 CMode CLI or 7Mode CLI or CMode ZAPI APISet. The method invokes 'lun-get-iter' for CMode ZAPI =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_7mode_cli', interface => 'CLI', set => '7Mode', }, { method => '_fetch_cmode_zapi', interface => 'ZAPI', set => 'CMode', check => '_cmode_zapi_check', }, ], exception_text => 'No matching lun(s) found', show_cmd => 'lun show', ); $Log->exit() if $may_exit; return wantarray ? @state_objs : $state_objs[0]; } ## end sub fetch sub _fetch_cmode_cli { $Log->enter() if $may_enter; my ($pkg, %opts) = @_; my @state_objs; try { @state_objs = $pkg->SUPER::_fetch_cmode_cli(%opts, api => 'lun_show'); } catch NACL::APISet::Exceptions::ResponseException with { my $exception = shift; if ($exception->text() =~ /No such LUN exists/i) { $Log->debug("Silently Ignoring this error - product burt#537156. " . "The lun does not exist"); } else { $Log->exit() if $may_exit; $exception->throw(); } }; $Log->exit() if $may_exit; return @state_objs; } ## end sub _fetch_cmode_cli sub _fetch_7mode_cli { $Log->enter() if $may_enter; my $pkg = shift; my %opts = validate @_, $pkg->_fetch_backend_validate_spec(); my $apiset = $opts{apiset}; my $filter = $opts{filter}; my $requested_fields = $opts{requested_fields}; my %api_args; my @orig_requested_fields = @{$opts{requested_fields}}; my %orig_filter = %{$opts{filter}}; $pkg->_remove_relational_regex_filters( filter => \%orig_filter, requested_fields => \@orig_requested_fields ); $requested_fields = \@orig_requested_fields; $filter = \%orig_filter; # "lun show" allows us to filter by path or volume name # If both path and volume are provided in the filter we provide higher # priority to path, since that would refer to a specific LUN if (exists $filter->{path}) { $api_args{'lun-path'} = $filter->{path}; } elsif (exists $filter->{volume} && $filter->{qtree} && $filter->{lun} || exists $filter->{volume} && $filter->{lun}) { $pkg->_construct_path(params => $filter); $api_args{'lun-path'} = $filter->{path}; } elsif (exists $filter->{volume}) { $api_args{'vol-name'} = $filter->{volume}; } # Certain details are displayed only in verbose mode, conditionally # invoke "lun show" in verbose if any of these fields are required if ($pkg->_want_any_field_of( requested_fields => $requested_fields, filter => $filter, fields_filled_by_api => [ qw(serial backed-by share-state space-reserve space-resv protocol size-used creation-timestamp cluster-shared-volume-information comment maps prefix-size suffix-size extend-size alignment space_alloc space-allocation report-physical-size ostype) ] ) ) { $api_args{verbose} = 1; } ## end if ( $pkg->_want_any_field_of... my (%output_keyed_by_path, $need_to_return); try { my $response = $apiset->lun_show(%api_args); my $output = $response->get_parsed_output(); $need_to_return = 1 unless (@$output); foreach my $row (@{$output}) { # Construct a hash containing rows of parsed output, keyed by the # LUN path. This makes it easier to update with extra fields $output_keyed_by_path{$row->{'lun-path'}} = $row; if ($row->{state} eq "online") { # We need to map the 'state' field to both "isOnline" (older # field name) and "is-online" (newer field name) $row->{isOnline} = 'true'; $row->{'is-online'} = 'true'; } else { $row->{isOnline} = 'false'; $row->{'is-online'} = 'false'; } if ( $row->{mapped} && $row->{mapped} eq "mapped") { $row->{isMapped} = 'true'; $row->{'is-mapped'} = 'true'; $row->{mapped} = 'mapped'; } else { $row->{isMapped} = 'false'; $row->{'is-mapped'} = 'false'; $row->{mapped} = 'unmapped'; } } ## end foreach my $row ( @{$output... } ## end try catch NACL::APISet::Exceptions::InvalidParamValueException with { $need_to_return = 1; }; if ($need_to_return) { $Log->exit() if $may_exit; return; } # Check if "is-staging" is required and if so invoke "lun show staging" if ($pkg->_want_any_field_of( requested_fields => $requested_fields, filter => $filter, fields_filled_by_api => [qw(is-staging)] ) ) { while (my ($key, $value) = each %output_keyed_by_path) { $value->{'is-staging'} = 'false'; } my $mapped_response = $apiset->lun_show(staging => 1); my $mapped_parsed = $mapped_response->get_parsed_output(); foreach my $mapped_row (@{$mapped_parsed}) { $output_keyed_by_path{$mapped_row->{'lun-path'}}{'is-staging'} = 'true'; } } ## end if ( $pkg->_want_any_field_of... # list info -i would be invoked if the requested fields # like space-allocation, uuid, preifx-size, suffix-size # and extent-size are not returned from lun show -v # command. my %reqstd_fields = map { $_ => 1 } @{$requested_fields}; my @debug_list_info_fields = qw(uuid space-allocation suffix-size prefix-size extent-size); my @debug_list_info_reqstd = grep { $reqstd_fields{$_} } @debug_list_info_fields; my $need_debug_list; if ($pkg->_want_any_field_of( requested_fields => $requested_fields, filter => $filter, fields_filled_by_api => [qw(uuid)], ) ) { $need_debug_list = 1; } elsif ( $pkg->_want_any_field_of( requested_fields => $requested_fields, filter => $filter, fields_filled_by_api => [qw(space-allocation)], ) && ($opts{command_interface}->version_manager() ->is_version_lt(release => '8.1')) ) { $need_debug_list = 1; } elsif ( $pkg->_want_any_field_of( requested_fields => $requested_fields, filter => $filter, fields_filled_by_api => [qw(extent-size prefix-size suffix-size)], ) ) { LINE: while (my ($key, $value) = each %output_keyed_by_path) { foreach my $field (qw(extent-size prefix-size suffix-size)) { if ( !defined $value->{$field} && defined $reqstd_fields{$field}) { $need_debug_list = 1; last LINE; } } } } if ($need_debug_list) { while (my ($key, $value) = each %output_keyed_by_path) { my $response = $apiset->lun_show( 'debug-list-info' => 1, 'lun-path' => $key ); my $parsed = $response->get_parsed_output(); foreach my $field (@debug_list_info_reqstd) { if (!defined $value->{$field}) { if ($field eq 'space-allocation') { my $conversion_values = {'yes' => 'enabled', 'no' => 'disabled'}; my $space_alloc = @$parsed[0]->{'space_alloc'}; $value->{'space-allocation'} = $conversion_values->{$space_alloc}; } else { (my $new = $field) =~ s/-/_/g; $value->{$field} = @$parsed[0]->{$new}; } } } } } # Turn each of these hashes into a state object my @state_objs; while (my ($key, $value) = each %output_keyed_by_path) { $pkg->_hash_move( source => $value, target => $value, map => { 'share' => 'share-state', 'occupied-size' => 'size-used', 'extent-boundary' => 'extent-size', 'space_alloc' => 'space-allocation', 'protocol' => 'ostype' } ); my $path = delete $value->{'lun-path'}; ($value->{volume}, $value->{qtree}, $value->{lun}) = $pkg->_extract_volume_qtree_lun_from_path(path => $path); $value->{path} = $path; # If the creation time exists, convert it to the format it is in CMode # i.e "MM/DD/YYYY HH:MM:SS" if (exists $value->{'creation-timestamp'}) { my $timestamp = $value->{'creation-timestamp'}; my @values = split /\s+/, $timestamp; my $month_string = $values[1]; my $DD = $values[2]; my $HHMMSS = $values[3]; my $YYYY = $values[5]; # Turn the month string into the MM format my %mm_hash = ( 'Jan' => '01', 'Feb' => '02', 'Mar' => '03', 'Apr' => '04', 'May' => '05', 'Jun' => '06', 'Jul' => '07', 'Aug' => '08', 'Sep' => '09', 'Oct' => '10', 'Nov' => '11', 'Dec' => '12' ); my $MM = $mm_hash{$month_string}; $value->{'creation-timestamp'} = "$MM/$DD/$YYYY $HHMMSS"; } ## end if ( exists $value->{'creation-timestamp'... #The 7mode Cli returns size in the form 5m (5242880) #Cmode Cli returns it in bytes. Hence normalizing the output #to 5242880. foreach my $param ( qw( extent-size prefix-size suffix-size size-used ) ) { $value->{$param} =~ s/.*?\((\d+)\)/$1/g if (exists $value->{$param}); } my $obj = $pkg->new(command_interface => $opts{command_interface}); $obj->_set_fields(row => $value); push @state_objs, $obj; } ## end while ( my ( $key, $value... $Log->exit() if $may_exit; return @state_objs; } ## end sub _fetch_7mode_cli sub _fetch_cmode_zapi { $Log->enter() if $may_enter; my ($pkg, %opts) = @_; if (defined $opts{filter} && defined $opts{filter}->{mapped}) { if ($opts{filter}->{mapped} eq 'mapped') { $opts{filter}{mapped} = 'true'; } else { $opts{filter}{mapped} = 'false'; } } my @alignment_fields = qw(read-partial partition-offset partition-count read-histogram partition-type partition-scheme write-histogram bin-number write-partial ); my @state_objs = $pkg->SUPER::_fetch_cmode_zapi( %opts, api => 'lun_get_iter', copy => [ qw( alignment block-size creation-timestamp class is-clone prefix-size size-used path qtree read-only share-state size volume comment staging suffix-size uuid is-restore-inaccessible is-clone-autodelete-enabled vserver device-binary-id device-text-id node qos-policy-group device-id serial-7-mode mapped qos-adaptive-policy-group ) ], map => { 'serial' => 'serial-number', 'space-alloc-enabled' => 'is-space-alloc-enabled', 'space-resv-enabled' => 'is-space-reservation-enabled', 'space-resv' => 'is-space-reservation-enabled', 'space-reserve' => 'is-space-reservation-enabled', 'space-allocation' => 'is-space-alloc-enabled', 'restore-inaccessible' => 'is-restore-inaccessible', 'inconsistent-import' => 'is-inconsistent-import', '7-mode-serial' => 'serial-7-mode', 'ostype' => 'multiprotocol-type', 'is-mapped' => 'mapped', 'state' => 'state', }, # alignment_fields are obtained from NACL::CS::LunAlignment, # lun is not returned by the ZAPI, but is obtained from path inapplicable_for_help_xml => [@alignment_fields, 'lun'], ); foreach my $obj (@state_objs) { my $lun = $obj->_extract_lun_from_path(path => $obj->path()); $obj->lun($lun); } my $filter = $opts{filter}; if (!defined $filter->{path} && defined $filter->{lun}) { # ZAPI could not filter for us; do it here $pkg->_apply_filter( state_objs => \@state_objs, filter => {lun => $filter->{lun}}, ); } if (!@state_objs) { $Log->exit() if $may_exit; return @state_objs; } my %alignment_fields_req_field_hash; # Check if any of the alignment fields are present in requested_fields # or filter, and if so, set to 1. Also, keep the list of these options # required -- this will be the requested_fields value. my $want_alignment_fields; if ($filter) { foreach my $alignment_field (@alignment_fields) { if (exists $filter->{$alignment_field}) { $want_alignment_fields = 1; $alignment_fields_req_field_hash{$alignment_field} = 1; } } } if (!$want_alignment_fields && @{$opts{requested_fields}}) { my %req_field_hash = map { $_ => 1 } @{$opts{requested_fields}}; foreach my $alignment_field (@alignment_fields) { if (exists $req_field_hash{$alignment_field}) { $want_alignment_fields = 1; $alignment_fields_req_field_hash{$alignment_field} = 1; } } } if ($want_alignment_fields && @state_objs) { # Need the base class to filter. ${$opts{_apply_filter}} = 1; my @alignment_fields_req_field = keys %alignment_fields_req_field_hash; my %alignment_filter; if (defined $filter->{vserver}) { # Limit to this vserver only $alignment_filter{vserver} = $filter->{vserver}; } # Limit to showing the alignment values only for the luns returned by # SUPER::_fetch_cmode_zapi. my @paths = map { $_->path() } @state_objs; my $path_filter = join '|', @paths; $alignment_filter{path} = $path_filter; require NACL::CS::LunAlignment; my @align_objs = NACL::CS::LunAlignment->fetch( command_interface => $opts{command_interface}, apiset_should => {interface => 'ZAPI'}, requested_fields => \@alignment_fields_req_field, filter => \%alignment_filter, ); # Key by "vserver;path" my %orig_state_objs_hash; foreach my $state_obj (@state_objs) { $orig_state_objs_hash{$state_obj->vserver() . ';' . $state_obj->path()} = @state_objs; # Extract the lun name from the path and set it on the object my $lun = $state_obj->_extract_lun_from_path( path => $state_obj->path()); $state_obj->lun($lun); } foreach my $align_obj (@align_objs) { my $key = $align_obj->vserver() . ';' . $align_obj->path(); my $cs_to_update = $orig_state_objs_hash{$key}; if ($cs_to_update) { foreach my $align_field (@alignment_fields) { my $field = $align_field . "_isset"; if ($align_obj->$field()) { my $value = $align_obj->$align_field(); $align_obj->$align_field("$value"); } } } } } $Log->exit() if $may_exit; return @state_objs; } ## end sub _fetch_cmode_zapi sub _cmode_zapi_check { $Log->enter() if $may_enter; my ($pkg, %opts) = @_; my @requested = @{$opts{requested_fields}}; if (exists $opts{filter}->{'serial-hex'} || 'serial-hex' ~~ @requested ) { my $msg = "The field 'serial-hex' was provided in the filter or requested fields in the " . 'call to NACL::CS::Lun->fetch but ZAPI provides no ' . 'way to filter on the serial-hex, so the ZAPI implementation ' . 'cannot be used'; $Log->comment($msg); $Log->exit() if $may_exit; NACL::Exceptions::InvalidChoice->throw($msg); } $Log->exit() if $may_exit; } sub _update_state_objs_cmode_zapi { $Log->enter() if $may_enter; my ($pkg, @args) = @_; $pkg->SUPER::_update_state_objs_cmode_zapi( @args, zapi_field_translations => { enable_disable => [qw(space-resv space-reserve space-allocation)], hyphenate_value => [qw(state)], }, hash_map_translations => { mapped => { fields_to_translate => [qw(mapped)], hash_map => { true => 'mapped', false => 'unmapped', }, }, }, ); $Log->exit() if $may_exit; } 1;