# Copyright (c) 2012 NetApp, Inc., All Rights Reserved # Any use, modification, or distribution is prohibited # without prior written consent from NetApp, Inc. # # ## @summary Sanlun ComponentState Module ## @author gupendra@netapp.com, dl-nacl-dev@netapp.com ## @status shared ## @pod here ################################################################################ =head1 NAME NACL::CS::Client::Sanlun =head1 DESCRIPTION C is a derived class of L. It represents the state of Sanlun element. A related class is L, which represents access to a Sanlun element. =head1 ATTRIBUTES The individual pieces of data that are part of the state of the Sanlun element are the individual attributes of the Sanlun ComponentState =over =item C<< "lun_state" >> Filled in for Linux CLI. Maps to: Linux 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<< "host_path_state" >> Filled in for Linux CLI. Maps to: Linux 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<< "lun_pathname" >> Filled in for Linux CLI, Windows CLI. =item C<< "dev_node" >> Filled in for Linux CLI. Maps to: Linux 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<< "protocol" >> Filled in for Linux CLI, Windows CLI. =item C<< "primary_controller_port" >> Filled in for Linux CLI. Maps to: Linux 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<< "host_hba" >> Filled in for Linux CLI. Maps to: Linux 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<< "controller_target_port" >> Filled in for Linux CLI. Maps to: Linux 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<< "controller" >> Filled in for Linux CLI, Windows CLI. =item C<< "lun_size" >> Filled in for Linux CLI. Maps to: Linux 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<< "adapter" >> Filled in for Linux CLI. Maps to: Linux 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<< "sanlun_path_state" >> Filled in for Linux CLI. Maps to: Linux 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<<"controller_path_type" >> Filled in for Linux CLI. Maps to: Linux 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<< "partner_controller_port" >> Filled in for Linux CLI. Maps to: Linux 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<<"controller_partner" >> Filled in for Linux CLI. Maps to: Linux 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<< "lun" >> Filled in for Linux CLI. Maps to: Linux 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<< "controller_cf_state" >> Filled in for Linux CLI. Maps to: Linux 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<< "filer_cf_state" >> Filled in for Linux CLI. Maps to: Linux 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<< "multipath_provider" >> Filled in for Linux CLI. Maps to: Linux 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<< "volume_name" >> Filled in for Linux CLI. Maps to: Linux 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<< "controller_ip_address" >> Filled in for Linux CLI. Maps to: Linux 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<< "lun_serial_number" >> Filled in for Linux CLI, Solaris CLI. Maps to: Linux 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. Solaris 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<< "ontap_path" >> Filled in for Linux CLI. Maps to: Linux 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<< "mode" >> Filled in for Linux CLI. Maps to: Linux 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<< "controller_iscsi_ip_address" >> Filled in for Linux CLI. Maps to: Linux 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<< "snapshot_name" >> Filled in for Linux CLI. Maps to: Linux 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<< "controller_iscsi_port_number" >> Filled in for Linux CLI. Maps to: Linux 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<< "fsid" >> Filled in for Linux CLI. Maps to: Linux 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<< "qtree_name" >> Filled in for Linux CLI. Maps to: Linux 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<< "tpgs_flag" >> Filled in for Linux CLI, Solaris CLI. Maps to: Linux 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. Solaris 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<< "multipath_policy" >> Filled in for Linux CLI, Solaris CLI. Maps to: Linux 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. Solaris 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<< "host_device" >> Filled in for Linux CLI, Solaris CLI. Maps to: Linux 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. Solaris 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<< "serial_number" >> =item C<< "multiprotocol_access" >> Filled in for Linux CLI, Solaris CLI. Maps to: Linux 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. Solaris 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<< "valid_label" >> Filled in for Linux CLI, Solaris CLI. Maps to: Linux 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. Solaris 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<< "port_number" >> Filled in for Linux CLI, Solaris CLI. Maps to: Linux 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. Solaris 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<< "ip_address" >> Filled in for Linux CLI, Solaris CLI. Maps to: Linux 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. Solaris 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<< "qtree_id" >> Filled in for Linux CLI, Solaris CLI. Maps to: Linux 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. Solaris 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<< "iscsi_port_number" >> Filled in for Linux CLI, Solaris CLI. Maps to: Linux 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. Solaris 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<< "filer_ip_address" >> =item C<< "snapshot_id" >> Filled in for Linux CLI, Solaris CLI. Maps to: Linux 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. Solaris 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<< "multipath_info" >> Filled in for Linux CLI, Solaris CLI. Maps to: Linux 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. Solaris 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<< "filer_iscsi_ip_address" >> =item C<< "verbose" >> Filled in for Linux CLI, Solaris CLI. Maps to: Linux 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. Solaris 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<< "filer_iscsi_port_number" >> =item C<< "filer_partner" >> =item C<< "controller_ip_address" >> Filled in for Linux CLI, Solaris CLI. Maps to: Linux 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. Solaris 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" >> Filled in for Windows CLI. =item C<< "dsm" >> Filled in for Windows CLI. =item C<< "policy" >> Filled in for Windows CLI. =item C<< "paths" >> Filled in for Windows CLI. =item C<< "cfmode" >> Filled in for Windows CLI. =item C<< "luntype" >> Filled in for Windows CLI. =item C<< "serial" >> Filled in for Windows CLI. =item C<< "lun_id" >> Filled in for Windows CLI. =item C<< "msid" >> Filled in for Linux CLI. It is also filled when C-Mode luns are configured. =item C<< "vserver_iscsi_ip_address" >> Filled in for Linux CLI. It is also filled when C-Mode luns are configured. =item C<< "vserver_iscsi_port_number" >> Filled in for Linux CLI. It is also filled when C-Mode luns are configured. =item C<< "vserver_snapshot_name" >> Filled in for Linux CLI. It is also filled when C-Mode luns are configured. =item C<< "controller_snapshot_name" >> Filled in for Linux CLI. It is also filled when 7-Mode luns are configured. =item C<< "vserver_lif" >> Filled in for Linux CLI. It is also filled when C-Mode luns are configured. <<<< =back =cut ################### # Package package NACL::CS::Client::Sanlun; ################### # Everytime use strict; use warnings; ################### # Module includes use Params::Validate qw (validate validate_with HASHREF ARRAYREF OBJECT); use NACL::ComponentUtils qw (_optional_scalars Dumper); use NATE::Log qw(log_global); my $Log = log_global(); my $may_enter = $Log->may_enter(); my $may_exit = $Log->may_exit(); use base 'NACL::CS::ComponentState::Client'; use NACL::Exceptions::NoElementsFound qw(:try); use NACL::APISet::Exceptions::InvalidParamValueException qw(:try); use Class::MethodMaker [ scalar => "protocol", scalar => "dev_node", scalar => "device_filename", scalar => "lun_pathname", scalar => "lun_state", scalar => "host_path_state", scalar => "primary_controller_port", scalar => "controller_target_port", scalar => "host_hba", scalar => "controller", scalar => "lun_size", scalar => "adapter", scalar => "sanlun_path_state", scalar => "controller_path_type", scalar => "partner_controller_port", scalar => "controller_partner", scalar => "lun", scalar => "controller_cf_state", scalar => "filer_cf_state", scalar => "multipath_provider", scalar => "filer_partner", #new options scalar => "volume_name", scalar => "controller_ip_address", scalar => "filer_ip_address", scalar => "lun_serial_number", scalar => "ontap_path", scalar => "mode", scalar => "controller_iscsi_ip_address", scalar => "filer_iscsi_ip_address", scalar => "snapshot_name", scalar => "controller_iscsi_port_number", scalar => "filer_iscsi_port_number", scalar => "fsid", scalar => "qtree_name", scalar => "msid", scalar => "vserver_iscsi_ip_address", scalar => "vserver_iscsi_port_number", scalar => "vserver_snapshot_name", scalar => "controller_snapshot_name", scalar => "vserver_lif", scalar => "vserver_volume_name", scalar => "controller_model_name", array => "vserver_ip_address", #Filled in for solaris scalar => "tpgs_flag", scalar => "multipath_policy", scalar => "host_device", scalar => "serial_number", scalar => "multiprotocol_access", scalar => "valid_label", scalar => "port_number", scalar => "ip_address", scalar => "qtree_id", scalar => "iscsi_port_number", scalar => "snapshot_id", #windows specific options scalar => "disk", scalar => "dsm", scalar => "policy", scalar => "paths", scalar => "serial", scalar => "cfmode", scalar => "luntype", scalar => "lun_id", ]; =head1 METHODS =head2 fetch my $lun_state = NACL::CS::Client::Sanlun->fetch(command_interface=>$ci,...); my @lun_states = NACL::CS::Client::Sanlun->fetch(command_interface=>$ci,...); see L Supports Linux/Solaris CLI. Invokes "sanlun lun show" command for Linux/Solaris CLI. =cut sub fetch { my $pkg = shift; my @state_objs = $pkg->SUPER::fetch( @_, choices => [ { method => "_fetch_linux_cli", interface => "CLI", set => 'Linux' }, { method => "_fetch_solaris_cli", interface => "CLI", set => "Solaris" }, { method => "_fetch_windows_cli", interface => "CLI", set => "Windows" }, ], exception_text => 'No luns found' ); return wantarray ? @state_objs : $state_objs[0]; } sub _fetch_linux_cli { my $pkg = shift; my %opts = validate @_, $pkg->_fetch_backend_validate_spec(); my $apiset = $opts{apiset}; my $command_interface = delete $opts{command_interface}; 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; $req_field_filter->{'requested_fields'} = $requested_fields; $req_field_filter->{'filter'} = \%copy_filter; my ( @state_objs, @all_details, @luns ); my ( $response, $output, $outputv, $outputp ); my $fields_lun_show = [ qw( protocol controller adapter lun-size lun-state lun-pathname device-filename ) ]; my $fields_lun_show_p = [ qw( multipath-provider ontap-path dev-node mode host-hba controller-target-port lun controller-cf-state controller-path-type controller-partner host-path-state vserver-lif ) ]; my $fields_lun_show_v = [ qw( controller-iscsi-ip-address volume-name controller-ip-address snapshot-name controller-iscsi-port-number fsid lun-serial-number qtree-name primary-controller-port msid vserver-iscsi-ip-address vserver-iscsi-port-number vserver-snapshot-name controller-snapshot-name vserver-ip-address controller-model-name vserver-volume-name) ]; $pkg->_invoke_api_if_necessary( %$req_field_filter, fields_filled_by_api => $fields_lun_show, api_args => {}, all_details => \@all_details, apiset_obj => $apiset, ); foreach my $lun_details (@all_details) { my %all_det = %{$lun_details}; if (exists $all_det{lun_pathname} ) { push(@luns, "$all_det{controller}:$all_det{lun_pathname}"); } } foreach my $lun (@luns) { $pkg->_invoke_api_if_necessary( %$req_field_filter, fields_filled_by_api => $fields_lun_show_p, api_args => {'multipath-info' => "1", pathname => $lun}, all_details => \@all_details, apiset_obj => $apiset, ); $pkg->_invoke_api_if_necessary( %$req_field_filter, fields_filled_by_api => $fields_lun_show_v, api_args => {'verbose' => "1", pathname => $lun}, all_details => \@all_details, apiset_obj => $apiset, ); foreach my $row (@all_details) { my $obj = $pkg->new( command_interface => $command_interface ); $obj->_set_fields( row => \%$row ); push @state_objs, $obj; } @all_details = undef; } return @state_objs; } sub _fetch_solaris_cli { my $pkg = shift; my %opts = validate @_, $pkg->_fetch_backend_validate_spec(); my $apiset = $opts{apiset}; my $command_interface = delete $opts{command_interface}; 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; $req_field_filter->{'requested_fields'} = $requested_fields; $req_field_filter->{'filter'} = \%copy_filter; my ( @state_objs, @all_details ); my ( $response, $output, $outputv, $outputp ); my $fields_lun_show = [ qw(protocol controller adapter lun-size lun-state lun-pathname device-filename) ]; my $fields_lun_show_p = [ qw(multipath-provider lun tpgs-flag multipath-policy ontap-path host-device controller-cf-state controller-partner) ]; my $fields_lun_show_v = [ qw(volume-name serial-number multiprotocol-access valid-label port-number fsid qtree-name ip-address iscsi-ip-address snapshot-id qtree-id) ]; if ( $pkg->_want_any_field_of( %{$req_field_filter}, fields_filled_by_api => $fields_lun_show ) ) { $response = $apiset->sanlun_lun_show('privilege-level' => 'root',); $output = $response->get_parsed_output(); my $no_of_rows = scalar @{$output}; my @salun_arr = @{$output}; foreach my $i ( 0 .. $no_of_rows - 1 ) { if ( $all_details[$i] ) { $all_details[$i] = { %{ $all_details[$i] }, %{ $salun_arr[$i] } }; } else { $all_details[$i] = $salun_arr[$i]; } } } if ( $pkg->_want_any_field_of( %{$req_field_filter}, fields_filled_by_api => $fields_lun_show_p ) ) { $response = $response = $apiset->sanlun_lun_show( 'multipath-info' => "1", 'privilege-level' => 'root', ); $outputp = $response->get_parsed_output(); my $no_of_rows = scalar @{$outputp}; my @salun_arr = @{$outputp}; foreach my $i ( 0 .. $no_of_rows - 1 ) { if ( $all_details[$i] ) { $all_details[$i] = { %{ $all_details[$i] }, %{ $salun_arr[$i] } }; } else { $all_details[$i] = $salun_arr[$i]; } } } if ( $pkg->_want_any_field_of( %{$req_field_filter}, fields_filled_by_api => $fields_lun_show_v ) ) { $response = $apiset->sanlun_lun_show( 'verbose' => "1", 'privilege-level' => 'root', ); $outputv = $response->get_parsed_output(); my $no_of_rows = scalar @{$outputv}; my @salun_arr = @{$outputv}; foreach my $i ( 0 .. $no_of_rows - 1 ) { if ( $all_details[$i] ) { $all_details[$i] = { %{ $all_details[$i] }, %{ $salun_arr[$i] } }; } else { $all_details[$i] = $salun_arr[$i]; } } } foreach my $row (@all_details) { my $target = $pkg->_hash_copy( source => $row, copy => [ qw(protocol controller lun_size adapter device_filename lun_pathname lun_state ontap_path lun multipath_provider controller_cf_state controller_partner volume_name qtree_name fsid) ], map => { 'serial_number' => "lun_serial_number", 'port_number' => "controller_iscsi_port_number", 'ip_address' => "controller-ip-address", }, ); my $obj = $pkg->new( command_interface => $command_interface ); $obj->_set_fields( row => $target ); push @state_objs, $obj; } return @state_objs; } sub _fetch_windows_cli { $Log->enter() if $may_enter; my ($pkg, @args) = @_; my %opts = validate @args, $pkg->_fetch_backend_validate_spec(); my $apiset = $opts{apiset}; my $command_interface = delete $opts{command_interface}; my @state_objs; my $response = $apiset->mpc_show_luns(); my $output = $response->get_parsed_output(); foreach my $row (@$output) { my $obj = $pkg->new( command_interface => $command_interface ); $obj->_set_fields( row => $row ); push @state_objs, $obj; } $Log->exit() if $may_exit; return @state_objs; } sub _invoke_api_if_necessary { my ($pkg, @opts) = @_; $Log->enter() if $may_enter; my $spec = { api_args => {type => HASHREF}, all_details => {type => ARRAYREF}, apiset_obj => {type => OBJECT, isa => 'NACL::APISet'}, }; my %args = validate_with( params => \@opts, spec => $spec, # The other arguments are those accepted by # "_want_any_field_of". Invalid arguments will # cause that method to fail allow_extra => 1 ); my %other_args; $pkg->_hash_move( source => \%args, target => \%other_args, move => [keys %$spec] ); my $all_details = $other_args{all_details}; my $apiset = $other_args{apiset_obj}; if ($pkg->_want_any_field_of(%args)) { my $response = $apiset->sanlun_lun_show( 'privilege-level' => 'root', %{$other_args{api_args}} ); my $output = $response->get_parsed_output(); my $no_of_rows = scalar @{$output}; foreach my $i (0 .. $no_of_rows - 1) { if ($all_details->[$i]) { $all_details->[$i] = {%{$all_details->[$i]}, %{$output->[$i]}}; } else { $all_details->[$i] = $output->[$i]; } } } $Log->exit() if $may_exit; } 1;