$Parse::NetApp::ASUP::VERSION='1.07';
=head1 NAME:
Parse::NetApp::ASUP - Parse NetApp Weekly Auto Support Files
=head1 SYNOPSIS:
Parse NetApp Weekly Auto Support Files
=head1 USAGE:
use Parse::NetApp::ASUP;
my $pna = Parse::NetApp::ASUP->new();
$pna->load($raw_asup_data_as_scalar);
=cut
use Carp;
use strict;
use warnings;
package Parse::NetApp::ASUP;
=head3 new()
Instance a new parser.
=cut
sub new {
my $self = {};
bless $self;
return $self;
}
=head3 load($raw_asup_data)
Load a raw asup data file for parsing.
=cut
sub load {
my $self = shift @_;
my $asup = shift @_;
if ( not defined $asup or not length $asup ) {
warn "load() called without input data.";
return undef;
}
$self->{asup} = $asup;
return 1;
}
sub version {
return $Parse::NetApp::ASUP::VERSION;
}
### Utilties
sub _agnostic_line_split { # Now dealing with CRLF and the occasional standalone LF
my $all = $_[0];
my @lines = split /\r?\n/, $all;
return @lines;
}
sub _regex_lun_name {
return qr/[\d\w\/\{\}\.-]+/;
}
sub _regex_qtree_name {
return qr/[\w\-\? ]+/;
}
sub _regex_vol_name {
return qr/[\w\-\?]+/;
}
sub _regex_path {
return qr/[\w\-\?\$\\]+/;
}
### Sectional extract methods
=head1 EXTRACT METHODS:
=head3 extract_acp_list_all()
=cut
sub extract_acp_list_all {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ACP LIST ALL =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_aggr_status()
=cut
sub extract_aggr_status {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== AGGR-STATUS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_cf_monitor()
=cut
sub extract_cf_monitor {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== CF MONITOR =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_cifs_domaininfo()
=cut
sub extract_cifs_domaininfo {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== CIFS DOMAININFO =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_cifs_sessions()
=cut
sub extract_cifs_sessions {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== CIFS SESSIONS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_cifs_shares()
=cut
sub extract_cifs_shares {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== CIFS SHARES =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_cifs_stat()
=cut
sub extract_cifs_stat {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== CIFS STAT =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_cluster_monitor()
=cut
sub extract_cluster_monitor {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== CLUSTER MONITOR =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_df()
=cut
sub extract_df {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== DF =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_df_a()
=cut
sub extract_df_a {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== DF-A =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_df_i()
=cut
sub extract_df_i {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== DF-I =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_df_r()
=cut
sub extract_df_r {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== DF-R =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_df_s()
=cut
sub extract_df_s {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== DF-S =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_dns_info()
=cut
sub extract_dns_info {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== DNS info =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_ecc_memory_scrubber_stats()
=cut
sub extract_ecc_memory_scrubber_stats {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ECC MEMORY SCRUBBER STATS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_environment()
=cut
sub extract_environment {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ENVIRONMENT =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_exports()
=cut
sub extract_exports {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
# v7
if ( $raw =~ /(===== EXPORTS =====.*?)=====/s ) {
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
# v8
my @lines = Parse::NetApp::ASUP::_agnostic_line_split($raw);
my @trim;
while ( @lines ) {
my $line = shift @lines;
if ( $line =~ /^\/vol\/\S+\s+-sec=/ ) {
@trim = ( $line );
while ( $lines[0] =~ /^\/vol\/\S+\s+-sec=/ ) {
push @trim, shift @lines;
}
}
}
return join("\n",@trim) . "\n" if scalar(@trim);
# give up
return undef;
}
=head3 extract_failed_disk_registry()
=cut
sub extract_failed_disk_registry {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== FAILED_DISK_REGISTRY =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_fc_device_map()
=cut
sub extract_fc_device_map {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== FC DEVICE MAP =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_fc_link_stats()
=cut
sub extract_fc_link_stats {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== FC LINK STATS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_fc_stats()
=cut
sub extract_fc_stats {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== FC STATS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_fcp_cfmode()
=cut
sub extract_fcp_cfmode {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== FCP CFMODE =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_fcp_initiator_status()
=cut
sub extract_fcp_initiator_status {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== FCP INITIATOR STATUS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_fcp_status()
=cut
sub extract_fcp_status {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== FCP STATUS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_fcp_target_adapters()
=cut
sub extract_fcp_target_adapters {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== FCP TARGET ADAPTERS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_fcp_target_configuration()
=cut
sub extract_fcp_target_configuration {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== FCP TARGET CONFIGURATION =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_fcp_target_stats()
=cut
sub extract_fcp_target_stats {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== FCP TARGET STATS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_flash_card_info()
=cut
sub extract_flash_card_info {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== FLASH CARD INFO =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_fmm_data()
=cut
sub extract_fmm_data {
# Space at end to handle lots of equal signs in the content.
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== FMM-DATA =====.*?)===== /s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_fpolicy()
=cut
sub extract_fpolicy {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== FPOLICY =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_headers()
=cut
sub extract_headers {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(GENERATED_ON=.*?\n)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_hosts()
=cut
sub extract_hosts {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== HOSTS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_httpstat()
=cut
sub extract_httpstat {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== HTTPSTAT =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_hwassist_stats()
=cut
sub extract_hwassist_stats {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== HWASSIST_STATS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_ifconfig_a()
=cut
sub extract_ifconfig_a {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== IFCONFIG-A =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_ifgrp_status()
=cut
sub extract_ifgrp_status {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== IFGRP-STATUS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_ifstat_a()
=cut
sub extract_ifstat_a {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== IFSTAT-A =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_initiator_groups()
=cut
sub extract_initiator_groups {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== INITIATOR GROUPS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_interconnect_config()
=cut
sub extract_interconnect_config {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== INTERCONNECT CONFIG =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_interconnect_stats()
=cut
sub extract_interconnect_stats {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== INTERCONNECT STATS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_iscsi_alias()
=cut
sub extract_iscsi_alias {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ISCSI ALIAS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_iscsi_connections()
=cut
sub extract_iscsi_connections {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ISCSI CONNECTIONS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_iscsi_initiator_status()
=cut
sub extract_iscsi_initiator_status {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ISCSI INITIATOR STATUS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_iscsi_interface()
=cut
sub extract_iscsi_interface {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ISCSI INTERFACE =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_iscsi_interface_accesslist()
=cut
sub extract_iscsi_interface_accesslist {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ISCSI INTERFACE ACCESSLIST =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_iscsi_isns()
=cut
sub extract_iscsi_isns {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ISCSI ISNS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_iscsi_nodename()
=cut
sub extract_iscsi_nodename {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ISCSI NODENAME =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_iscsi_portals()
=cut
sub extract_iscsi_portals {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ISCSI PORTALS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_iscsi_security()
=cut
sub extract_iscsi_security {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ISCSI SECURITY =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_iscsi_sessions()
=cut
sub extract_iscsi_sessions {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ISCSI SESSIONS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_iscsi_statistics()
=cut
sub extract_iscsi_statistics {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ISCSI STATISTICS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_iscsi_status()
=cut
sub extract_iscsi_status {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ISCSI STATUS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_iscsi_target_portal_groups()
=cut
sub extract_iscsi_target_portal_groups {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ISCSI TARGET PORTAL GROUPS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_lun_config_check()
=cut
sub extract_lun_config_check {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== LUN CONFIG CHECK =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_lun_configuration()
=cut
sub extract_lun_configuration {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
# v7
if ( $raw =~ /(===== LUN CONFIGURATION =====.*?)=====/s ) {
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
#v8
my @lines = Parse::NetApp::ASUP::_agnostic_line_split($raw);
my @trim;
my $regex_lun_name = Parse::NetApp::ASUP::_regex_lun_name();
while ( @lines ) {
while ( $lines[0] =~ /^(\s{7,8}|\t)($regex_lun_name) +(.*?) +\((\d+)\).*\((.+)\)$/ ) {
push @trim, shift @lines;
push @trim, shift @lines if $lines[0] =~ /^\w/; # handle word-wrap on summary line
while ( $lines[0] =~ /^(\s{7,8}|\t)\s+.+: .+$/ ) {
push @trim, shift @lines;
}
}
shift @lines;
}
return join("\n",@trim) . "\n" if scalar(@trim);
# give up
return undef;
}
=head3 extract_lun_hist()
=cut
sub extract_lun_hist {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== LUN HIST =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_lun_statistics()
=cut
sub extract_lun_statistics {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== LUN STATISTICS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_messages()
=cut
sub extract_messages {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
my $trim;
if ( $raw =~ /(===== MESSAGES =====.*?)(=====|\n\n)/s ) { # Often the last item
$trim = $1;
}
if ( not $trim and $raw =~ /((^[MTWFS][ouehra][neduit] [JFMASOND]\w\w \d\d? \d\d:\d\d:\d\d [A-Z]{1,4}([\+\-]\d+)? (\[[^\]]+]: .+?|last message repeated \d+ times.+?)\n\n?)+)/ms ) { # v8 is unlabelled
$trim = "===== MESSAGES =====\n" . $1;
}
return undef unless $trim;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_nbtstat_c()
=cut
sub extract_nbtstat_c {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== NBTSTAT-C =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_netstat_s()
=cut
sub extract_netstat_s {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== NETSTAT-S =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_nfsstat_cc()
=cut
sub extract_nfsstat_cc {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== NFSSTAT-CC =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_nfsstat_d()
=cut
sub extract_nfsstat_d {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== NFSSTAT-D =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_nis_info()
=cut
sub extract_nis_info {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== NIS info =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_nsswitch_conf()
=cut
sub extract_nsswitch_conf {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== NSSWITCH-CONF =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_options()
=cut
sub extract_options {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== OPTIONS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_portsets()
=cut
sub extract_portsets {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== PORTSETS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_priority_show()
=cut
sub extract_priority_show {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== PRIORITY_SHOW =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_qtree_status()
=cut
sub extract_qtree_status {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
# v7
if ( $raw =~ /(===== QTREE-STATUS =====.*?)=====/s ) {
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
# v8
my @lines = Parse::NetApp::ASUP::_agnostic_line_split($raw);
my @trim;
my $word = Parse::NetApp::ASUP::_regex_path();
while ( @lines ) {
my $line = shift @lines;
if ( $line =~ /^Volume\s+Tree\s+Style\s+Oplocks\s+Status\s+ID/ ) {
@trim = ( $line, shift @lines ); # grab the "---" line too
while ( $lines[0] =~ /^(${word}\s+){4,6}\d/ ) {
push @trim, shift @lines;
}
}
}
return join("\n",@trim) . "\n" if scalar(@trim);
# give up
return undef;
}
=head3 extract_quotas()
=cut
sub extract_quotas {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== QUOTAS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_rc()
=cut
sub extract_rc {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== RC =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_resolv_conf()
=cut
sub extract_resolv_conf {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== RESOLV-CONF =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_route_gsn()
=cut
sub extract_route_gsn {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== ROUTE-GSN=====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sas_adapter_state()
=cut
sub extract_sas_adapter_state {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SAS ADAPTER STATE =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sas_dev_stats()
=cut
sub extract_sas_dev_stats {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SAS DEV STATS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sas_expander_map()
=cut
sub extract_sas_expander_map {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SAS EXPANDER MAP =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sas_expander_phy_state()
=cut
sub extract_sas_expander_phy_state {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SAS EXPANDER PHY STATE =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sas_shelf()
=cut
sub extract_sas_shelf {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SAS SHELF =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_service_usage()
=cut
sub extract_service_usage {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SERVICE USAGE =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_shelf_log_esh()
=cut
sub extract_shelf_log_esh {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SHELF-LOG-ESH =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_shelf_log_iom()
=cut
sub extract_shelf_log_iom {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SHELF-LOG-IOM =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sis_stat()
=cut
sub extract_sis_stat {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SIS STAT =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sis_stat_l()
=cut
sub extract_sis_stat_l {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SIS STAT L =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sis_status()
=cut
sub extract_sis_status {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SIS STATUS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sis_status_l()
=cut
sub extract_sis_status_l {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SIS STATUS L =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sm_allow()
=cut
sub extract_sm_allow {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SM-ALLOW =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sm_conf()
=cut
sub extract_sm_conf {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SM-CONF =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_snap_list_n()
=cut
sub extract_snap_list_n {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SNAP-LIST-N =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_snap_list_n_a()
=cut
sub extract_snap_list_n_a {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SNAP-LIST-N-A =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_snap_reserve()
=cut
sub extract_snap_reserve {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SNAP-RESERVE =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_snap_reserve_a()
=cut
sub extract_snap_reserve_a {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SNAP-RESERVE-A =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_snap_sched()
=cut
sub extract_snap_sched {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SNAP-SCHED =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_snap_sched_a()
=cut
sub extract_snap_sched_a {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SNAP-SCHED-A =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_snap_status()
=cut
sub extract_snap_status {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SNAP-STATUS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_snap_status_a()
=cut
sub extract_snap_status_a {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SNAP-STATUS-A =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_snapmirror_destinations()
=cut
sub extract_snapmirror_destinations {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SNAPMIRROR DESTINATIONS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_snapmirror_status()
=cut
sub extract_snapmirror_status {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SNAPMIRROR STATUS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_snapvault_destinations()
=cut
sub extract_snapvault_destinations {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SNAPVAULT DESTINATIONS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_snapvault_snap_sched()
=cut
sub extract_snapvault_snap_sched {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SNAPVAULT SNAP SCHED =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_snapvault_status_l()
=cut
sub extract_snapvault_status_l {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SNAPVAULT STATUS L =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_snaplock()
=cut
sub extract_snaplock {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SNAPLOCK =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_snaplock_clock()
=cut
sub extract_snaplock_clock {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SNAPLOCK-CLOCK =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_software_licenses()
=cut
sub extract_software_licenses {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SOFTWARE LICENSES =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_ssh()
=cut
sub extract_ssh {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SSH =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_storage()
=cut
sub extract_storage {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== STORAGE =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sysconfig_a()
=cut
sub extract_sysconfig_a {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SYSCONFIG-A =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sysconfig_ac()
=cut
sub extract_sysconfig_ac {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SYSCONFIG-AC =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sysconfig_c()
=cut
sub extract_sysconfig_c {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SYSCONFIG-C =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sysconfig_d()
=cut
sub extract_sysconfig_d {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SYSCONFIG-D =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sysconfig_hardware_ids()
=cut
sub extract_sysconfig_hardware_ids {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SYSCONFIG HARDWARE IDS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sysconfig_m()
=cut
sub extract_sysconfig_m {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SYSCONFIG-M =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_sysconfig_r()
=cut
sub extract_sysconfig_r {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SYSCONFIG-R =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_system_serial_number()
=cut
sub extract_system_serial_number {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== SYSTEM SERIAL NUMBER =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_unowned_disks()
=cut
sub extract_unowned_disks {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== UNOWNED-DISKS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_usage()
=cut
sub extract_usage {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== USAGE =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_usermap_cfg()
=cut
sub extract_usermap_cfg {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== USERMAP-CFG =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_vfiler_startup_times()
=cut
sub extract_vfiler_startup_times {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== VFILER STARTUP TIMES =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_vfilers()
=cut
sub extract_vfilers {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== VFILERS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_vif_status()
=cut
sub extract_vif_status {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== VIF-STATUS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_vlan_stat()
=cut
sub extract_vlan_stat {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== VLAN STAT =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_vol_language()
=cut
sub extract_vol_language {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== VOL-LANGUAGE =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_vol_status()
=cut
sub extract_vol_status {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== VOL-STATUS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_vscan()
=cut
sub extract_vscan {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== VSCAN =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_vscan_options()
=cut
sub extract_vscan_options {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== VSCAN OPTIONS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_vscan_scanners()
=cut
sub extract_vscan_scanners {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return '' unless $raw =~ /(===== VSCAN SCANNERS =====.*?)=====/s;
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
=head3 extract_xheader()
=cut
sub extract_xheader {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
# v7
if ( $raw =~ /(===== X-HEADER DATA =====.*?)(=====|\n\n)/s ) {
my $trim = $1;
while ( $trim !~ /\n\n$/s ) { $trim .= "\n"; }
return $trim;
}
# v8
my @lines = Parse::NetApp::ASUP::_agnostic_line_split($raw);
my @trim;
while ( @lines and $lines[0] !~ /^GENERATED_ON/ ) {
shift @lines; # Skip the mail header, to avoid confusion
}
while ( @lines ) {
my $line = shift @lines;
push @trim, $line if $line =~ /^X-Netapp-asup-/;
}
return join("\n",@trim) . "\n" if scalar(@trim);
# give up
return undef;
}
### Version 8 and higher extract has to be iterative
sub iterative_extract {
my $raw = shift @_;
my %ex = ( xml => [] );
($ex{mailheader},$ex{header},$raw) = split /\n\n+/, $raw, 3;
# Now dealing with CRLF and the occasional standalone LF
my @lines = Parse::NetApp::ASUP::_agnostic_line_split($raw);
# sysconfig -a
while ( $lines[0] =~ /^(\t|\s{5})/ ) {
$ex{sysconfig_a} .= (shift @lines) . "\n";
}
# sysconfig -d
$ex{sysconfig_d} .= (shift @lines) . "\n" if ( $lines[0] =~ /^Device/ );
$ex{sysconfig_d} .= (shift @lines) . "\n" if ( $lines[0] =~ /^------/ );
while ( $lines[0] =~ /^[0-9a-f]{2}\.[0-9a-f]{2}/ ) {
$ex{sysconfig_d} .= (shift @lines) . "\n";
}
# sn
$ex{serialnum} = (shift @lines) . "\n" if $lines[0] =~ /^system serial number/;
# options
while ( $lines[0] =~ /^[a-z_\-0-9]+(\.[a-z_\-0-9]+)+\s+/i ) {
$ex{options} .= (shift @lines) . "\n";
}
# service usage
while ( $lines[0] =~ /^Service statistics as of/ ) {
$ex{service_usage} .= (shift @lines)."\n";
while ( $lines[0] =~ /^ \S+\s+\(\S+\).+recorded/ ) {
$ex{service_usage} .= (shift @lines)."\n";
while ( $lines[0] =~ /^\s+[A-Z](\s+\d+,){3}/ ) {
$ex{service_usage} .= (shift @lines)."\n";
}
}
}
# ifconfig -a
while ( $lines[0] =~ /^[a-zA-Z0-9\-]+: flags/ ) {
$ex{ifconfig_a} .= (shift @lines) . "\n";
while ( $lines[0] =~ /^(\t|\s{3})/ ) {
$ex{ifconfig_a} .= (shift @lines) . "\n";
}
}
# ifstat -a
shift @lines if $lines[0] =~ /^$/; # Remove a blank line
while ( $lines[0] =~ /^-- interface/ ) {
$ex{ifstat_a} .= (shift @lines)."\n";
$ex{ifstat_a} .= (shift @lines)."\n" if $lines[0] =~ /^$/;
while ( $lines[0] =~ /^[A-Z_]+\w/ ) {
$ex{ifstat_a} .= (shift @lines)."\n";
while ( $lines[0] =~ /^ [A-Z]/i ) {
$ex{ifstat_a} .= (shift @lines)."\n";
}
}
while ( $lines[0] =~ /^$/ ) { $ex{ifstat_a} .= (shift @lines)."\n"; }
}
# cifs_stat
while ( $lines[0] =~ /^\s+(\S+\s+)+\d+(\s+\d+\%)?$/ ) {
$ex{cifs_stat} .= (shift @lines)."\n";
}
while ( $lines[0] =~ /^(Max|Local|RPC)/ ) {
$ex{cifs_stat} .= (shift @lines)."\n";
}
# Volume-language
while ( $lines[0] =~ /^\s+Volume Language$/ ) {
$ex{volume_language} .= (shift @lines)."\n";
while ( $lines[0] =~ /^(\s+)?\S+( \S+){1,2} \(.+\)$/ ) {
$ex{volume_language} .= (shift @lines)."\n";
}
}
# httpstat
while ( $lines[0] =~ /^ Requests$/ ) {
$ex{httpstat} .= (shift @lines)."\n";
$ex{httpstat} .= (shift @lines) . "\n" if ( $lines[0] =~ /^\s+Accept\s+Reuse\s+Response\s+InBytes\s+OutBytes$/ );
$ex{httpstat} .= (shift @lines)."\n" if $lines[0] =~ /^$/;
while ( $lines[0] =~ /^\S+ Stats:$/ ) {
$ex{httpstat} .= (shift @lines)."\n";
while ( $lines[0] =~ /^(\s+\d+)+$/ ) {
$ex{httpstat} .= (shift @lines)."\n";
$ex{httpstat} .= (shift @lines)."\n" if $lines[0] =~ /^$/;
}
}
}
# df
while ( $lines[0] =~ /^Filesystem\s+kbytes/ ) {
$ex{df} .= (shift @lines)."\n";
while ( $lines[0] =~ /^(\/vol|snap reserve)/ ) {
$ex{df} .= (shift @lines)."\n";
}
}
# df_i
while ( $lines[0] =~ /^Filesystem\s+iused/ ) {
$ex{df_i} .= (shift @lines)."\n";
while ( $lines[0] =~ /^\/vol/ ) {
$ex{df_i} .= (shift @lines)."\n";
}
}
# snap-sched
while ( $lines[0] =~ /^Volume \S+: \d+/ ) {
$ex{snapsched} .= (shift @lines)."\n";
}
# vol-status
while ( $lines[0] =~ /^\s+Volume\s+State\s+Status\s+Options/ ) {
$ex{vol_status} .= (shift @lines)."\n";
while ( $lines[0] =~ /^(\s+)?\S+\s+(online|offline|restricted)\s+\S+/ ) {
$ex{vol_status} .= (shift @lines)."\n";
while ( $lines[0] =~ /^\s{14}\s+\S+/ ) {
$ex{vol_status} .= (shift @lines)."\n";
}
}
}
# sysconfig_r
while ( $lines[0] =~ /^(Volume|Aggregate) \S+ \(.+?\) \(.+?\)$/ ) {
$ex{sysconfig_r} .= (shift @lines)."\n";
while ( $lines[0] =~ /^ Plex \S+ \(.+?\)$/ ) {
$ex{sysconfig_r} .= (shift @lines)."\n";
while ( $lines[0] =~ /^ RAID group \S+ \(.+?\)$/ ) {
$ex{sysconfig_r} .= (shift @lines)."\n";
$ex{sysconfig_r} .= (shift @lines)."\n" if $lines[0] =~ /^$/;
$ex{sysconfig_r} .= (shift @lines)."\n" if $lines[0] =~ /^ RAID Disk/;
$ex{sysconfig_r} .= (shift @lines)."\n" if $lines[0] =~ /^ ---------/;
while ( $lines[0] =~ /^(\s+\S+){3}(\s+\d+){2}(\s+\S+\s+(\d+|\-)){2}(\s+\d+\/\d+){2}(\s+)?$/ ) {
$ex{sysconfig_r} .= (shift @lines)."\n";
}
while ( $lines[0] =~ /^$/ ) {
$ex{sysconfig_r} .= (shift @lines)."\n";
}
while ( $lines[0] =~ /(spare|broken|partner) disks/i ) {
$ex{sysconfig_r} .= (shift @lines)."\n";
$ex{sysconfig_r} .= (shift @lines)."\n" if $lines[0] =~ /^$/;
$ex{sysconfig_r} .= (shift @lines)."\n" if $lines[0] =~ /^RAID Disk/;
$ex{sysconfig_r} .= (shift @lines)."\n" if $lines[0] =~ /^---------/;
while ( $lines[0] =~ /^(spare|failed|partner)/i ) {
$ex{sysconfig_r} .= (shift @lines)."\n";
}
$ex{sysconfig_r} .= (shift @lines)."\n" if $lines[0] =~ /^$/;
}
}
}
}
# fc stats
while ( $lines[0] =~ /^\S+ driver statistics for slot/ ) {
$ex{fc_stats} .= (shift @lines)."\n";
while ( $lines[0] =~ /^ \S+\s+\d+$/ ) {
$ex{fc_stats} .= (shift @lines)."\n";
}
$ex{fc_stats} .= (shift @lines)."\n" if $lines[0] =~ /^ device status:\s+/;
while ( $lines[0] =~ /^ \S+\s+.*total:\s+\d+$/ ) {
$ex{fc_stats} .= (shift @lines)."\n";
}
}
while ( $lines[0] =~ /^Cannot complete operation on channel \S+; link is DOWN/ ) {
$ex{fc_stats} .= (shift @lines)."\n";
while ( $lines[0] =~ /^$/ ) { $ex{fc_stats} .= (shift @lines)."\n" }
}
# FC device map
while ( $lines[0] =~ /^Loop Map for channel/ ) {
$ex{fc_dev_map} .= (shift @lines)."\n";
while ( $lines[0] =~ /^(Translated Map|Shelf mapping|(Target SES devices|Initiators) on this loop):/ ) {
$ex{fc_dev_map} .= (shift @lines)."\n";
while ( $lines[0] =~ /^$/ ) { $ex{fc_dev_map} .= (shift @lines)."\n" }
while ( $lines[0] =~ /^\s+(Shelf (\d+|Unknown):\s+)?((\d+|XXX)\s+)+/ ) {
$ex{fc_dev_map} .= (shift @lines)."\n";
}
while ( $lines[0] =~ /^$/ ) { $ex{fc_dev_map} .= (shift @lines)."\n" }
}
while ( $lines[0] =~ /^$/ ) { $ex{fc_dev_map} .= (shift @lines)."\n" }
while ( $lines[0] =~ /^Cannot complete operation on channel \S+; link is DOWN/ ) {
$ex{fc_dev_map} .= (shift @lines)."\n";
while ( $lines[0] =~ /^$/ ) { $ex{fc_dev_map} .= (shift @lines)."\n" }
}
}
# FC link stats
while ( $lines[0] =~ /Loop\s+Link\s+Transport\s+Loss of\s+Invalid\s+Frame In\s+Frame Out/ ) {
$ex{fc_link_stats} .= (shift @lines)."\n".(shift @lines)."\n".(shift @lines)."\n";
while ( $lines[0] =~ /^\w+\.\w+(\s+\d+){6}$/ ) {
$ex{fc_link_stats} .= (shift @lines)."\n";
}
while ( $lines[0] =~ /^$/ ) { $ex{fc_link_stats} .= (shift @lines)."\n" }
while ( $lines[0] =~ /^Cannot complete operation on channel \S+; link is DOWN/ ) {
$ex{fc_link_stats} .= (shift @lines)."\n";
while ( $lines[0] =~ /^$/ ) { $ex{fc_link_stats} .= (shift @lines)."\n" }
}
}
# Registry
while ( $lines[0] =~ /^Loaded=/ ) {
for ( 1 .. 15 ) { $ex{registry} .= (shift @lines)."\n"; }
}
# Usage
while ( $lines[0] =~ /^[\w\-]+(\.[\w\-]+)+=\d+$/ ) {
$ex{usage} .= (shift @lines)."\n";
}
# ACP list all
$ex{acp_list_all} .= (shift @lines)."\n" if $lines[0] =~ /^\[acpadmin list.all\]/;
$ex{acp_list_all} .= (shift @lines)."\n" if length($ex{acp_list_all}) and $lines[0] =~ /^$/;
# DNS info? - should be IP?
$ex{dns_info} .= (shift @lines)."\n" if $lines[0] =~ /^IP\s+MAC/;
$ex{dns_info} .= (shift @lines)."\n" if $lines[0] =~ /^Address\s+Address/;
$ex{dns_info} .= (shift @lines)."\n" if $lines[0] =~ /^\-+$/;
while ( $lines[0] =~ /^\d{1,3}(\.\d{1,3}){3}/ ) {
$ex{dns_info} .= (shift @lines)."\n";
}
# media_scrub
while ( $lines[0] =~ /^\S+ media_scrub: status/ ) {
$ex{media_scrub} .= (shift @lines)."\n";
while ( $lines[0] =~ /^\t\S/ ) {
$ex{media_scrub} .= (shift @lines)."\n";
}
$ex{media_scrub} .= (shift @lines)."\n" if $lines[0] =~ /^$/;
}
# scrub
while ( $lines[0] =~ /^\S+ scrub/ ) {
$ex{scrub} .= (shift @lines)."\n";
}
# UNKNOWN
while ( $lines[0] =~ /^(Aggregate|Volume) \S+ \(.+?\) \(.+?\)$/ ) {
$ex{UNKNOWN} .= (shift @lines)."\n";
while ( $lines[0] =~ /^ Plex \S+ \(.+?\)$/ ) {
$ex{UNKNOWN} .= (shift @lines)."\n";
while ( $lines[0] =~ /^ RAID group \S+ \(.+?\)$/ ) {
$ex{UNKNOWN} .= (shift @lines)."\n";
$ex{UNKNOWN} .= (shift @lines)."\n" if $lines[0] =~ /^$/;
$ex{UNKNOWN} .= (shift @lines)."\n" if $lines[0] =~ /^ RAID Disk/;
$ex{UNKNOWN} .= (shift @lines)."\n" if $lines[0] =~ /^ ---------/;
while ( $lines[0] =~ /^ (dparity|data|parity)/ ) {
$ex{UNKNOWN} .= (shift @lines)."\n";
}
while ( $lines[0] =~ /^$/ ) {
$ex{UNKNOWN} .= (shift @lines)."\n";
}
}
}
}
# aggr_status
while ( $lines[0] =~ /^\s+Aggr\s+State\s+Status\s+Options/ ) {
$ex{aggr_status} .= (shift @lines)."\n";
while ( $lines[0] =~ /^(\s+)?\S+\s+(online|offline|restricted)\s+\S+/ ) {
$ex{aggr_status} .= (shift @lines)."\n";
while ( $lines[0] =~ /^\s{14}\s+\S+/ ) {
$ex{aggr_status} .= (shift @lines)."\n";
}
}
$ex{aggr_status} .= (shift @lines)."\n" if $lines[0] =~ /^$/;
while ( $lines[0] =~ /^\s+Volumes: \S/ ) {
$ex{aggr_status} .= (shift @lines)."\n";
while ( $lines[0] =~ /^\s{8}\s+\S/ ) {
$ex{aggr_status} .= (shift @lines)."\n";
}
$ex{aggr_status} .= (shift @lines)."\n" if $lines[0] =~ /^$/;
while ( $lines[0] =~ /^\s+Plex \S+: \S/ ) {
$ex{aggr_status} .= (shift @lines)."\n";
while ( $lines[0] =~ /^\s+RAID group \S+: \S/ ) {
$ex{aggr_status} .= (shift @lines)."\n";
}
}
$ex{aggr_status} .= (shift @lines)."\n" if $lines[0] =~ /^$/;
while ( $lines[0] =~ /^\s*\S+\s+(online|offline|restricted)(\s+\S+){2}/ ) {
$ex{aggr_status} .= (shift @lines)."\n";
while ( $lines[0] =~ /^\s{19}\s+\S+/ ) {
$ex{aggr_status} .= (shift @lines)."\n";
}
}
$ex{aggr_status} .= (shift @lines)."\n" if $lines[0] =~ /^$/;
}
}
# xml
while ( scalar(@lines) and $lines[0] =~ /<\?xml version="1.0"\?>/ ) {
my $xml = (shift @lines)."\n";
while ( scalar(@lines) and $lines[0] !~ /<\?xml version="1.0"\?>/ ) {
$xml .= (shift @lines)."\n";
}
push @{$ex{xml}}, $xml;
}
$ex{_REMAINDER} = \@lines;
return \%ex;
}
### Parse methods
sub parse_df {
my %vols = ();
return ( wantarray ? %vols : \%vols ) unless defined $_[0];
my @df = split "\n", $_[0];
shift @df if $df[0] =~ /^===== DF =====$/;
shift @df if $df[0] =~ /^Filesystem.*kbytes.*used.*avail.*capacity.*Mounted on/; # Drop the header row
while ( scalar(@df) ) {
my $line = shift @df;
$line .= shift @df if defined $df[0] and $df[0] =~ /^[\w\d\/\.]+$/; # Wraparound on mount point
Carp::croak "BAD DF LINE: '$line'\n"
unless $line =~ /^([\w\d\/\.]+).+?(\d+).+?(\d+).+?(\d+).+?([-\d]+\%).+?([\w\d\/\.]+)$/;
my ( $volume, $kbytes, $used, $avail, $capacity, $mounted_on ) = ( $1, $2, $3, $4, $5, $6 );
next if $volume =~ /.snapshot$/;
my $volname_clean = $volume;
$volname_clean =~ s/^\/vol\///i;
$volname_clean =~ s/\/$//;
next if $volume =~ /^snap$/;
$vols{$volname_clean}{kbytes} = $kbytes;
$vols{$volname_clean}{used} = $used;
$vols{$volname_clean}{avail} = $avail;
$vols{$volname_clean}{capacity} = $capacity;
$vols{$volname_clean}{mounted_on} = $mounted_on;
}
return wantarray ? %vols : \%vols;
}
sub parse_export {
my %export = ();
return ( wantarray ? %export : \%export ) unless defined $_[0];
my @lines = split "\n", $_[0];
for my $line (@lines) {
next if $line =~ /^#/;
next if $line =~ /^\s*$/;
if ( $line =~ /^(\S+)\s+(\S+)$/ ) {
$export{$1} = $2;
}
}
return wantarray ? %export : \%export;
}
sub parse_header {
my %header = ();
return ( wantarray ? %header : \%header ) unless defined $_[0];
my @lines = split "\n", $_[0];
for my $line (@lines) {
next if $line =~ /^\s*$/;
if ( $line =~ /Console is using (.+)$/ ) {
$header{'console_charset'} = $1;
} elsif ( $line =~ /^(\w+)=(.*)$/ ) {
$header{$1} = $2;
} elsif ( $line =~ /Console encoding is nfs but/ ) {
chomp $line;
$header{warnings} = $line;
} else {
Carp::croak "Bad header line: [$line]";
}
}
$header{short_version} = $1 if $header{VERSION} =~ /NetApp Release ([\w\.\d]+)/;
$header{short_version} = $header{VERSION} unless defined $header{short_version};
return wantarray ? %header : \%header;
}
sub parse_lun {
my %luns = ();
return ( wantarray ? %luns : \%luns ) unless length $_[0]; # Return empty if no data given
my @lun_conf = split "\n", $_[0];
shift @lun_conf while $lun_conf[0] =~ /^\s*$/;
shift @lun_conf if defined $lun_conf[0] and $lun_conf[0] eq '===== LUN CONFIGURATION ====='; # remove the first line
my $regex_lun_name = Parse::NetApp::ASUP::_regex_lun_name();
while ( scalar(@lun_conf) ) {
my $line = shift @lun_conf;
next if $line =~ /^\s*$/;
Carp::croak "Bad LUN Conf Line: [$line]" unless $line =~ /^(\s{7,8}|\t)(\/.+)$/;
my $rawluninfo = $2;
$rawluninfo .= ' ' . shift @lun_conf if $lun_conf[0] =~ /^\w/; # handle possible line wrap
$rawluninfo =~ /^($regex_lun_name) +(.*?) +\((\d+)\).*\((.+)\)$/
or Carp::croak "CAN'T PARSE LUN SUMMARY LINE: [$rawluninfo]";
my $lun = $1;
$luns{$lun}{_size} = $2;
$luns{$lun}{_raw_size} = $3;
$luns{$lun}{_status} = $4;
$luns{$lun}{_size} =~ s/g$//;
$luns{$lun}{_size} = ( $1 * 1024 ) if $luns{$lun}{_size} =~ /(.*)t$/;
while ( defined $lun_conf[0] and $lun_conf[0] =~ /^(\s{15,16}|\t{2})(\w.+): (.+)$/ ) {
my $name = $2; my $data = $3;
shift @lun_conf;
$data .= ' ' . shift @lun_conf
if defined $lun_conf[0] and $lun_conf[0] =~ /^\w/; # handle possible line wrap
$luns{$lun}{$name} = $data;
}
}
return wantarray ? %luns : \%luns;
}
sub parse_qtree {
my %qtree = ();
return ( wantarray ? %qtree : \%qtree ) unless defined $_[0];
my @lines = split "\n", $_[0];
shift @lines if $lines[0] eq '===== QTREE-STATUS =====';
my $reg_path = Parse::NetApp::ASUP::_regex_path();
my $reg_qtree_name = Parse::NetApp::ASUP::_regex_qtree_name();
my $reg_vol_name = Parse::NetApp::ASUP::_regex_vol_name();
for my $line (@lines) {
next if $line =~ /^[\s-]*$/; # Blank and line rows.
next if $line =~ /Volume.*Tree.*Style.*Oplocks.*Status.*ID/; # header row
my ( $vol, $tree, $style, $oplocks, $status, $id, $vfiler );
if ( $line =~ /^($reg_vol_name)\s+($reg_qtree_name)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\d+)\s+(\w+)$/ ) { # v8 with vfiler
( $vol, $tree, $style, $oplocks, $status, $id, $vfiler ) = ( $1, $2, $3, $4, $5, $6, $7 );
} elsif ( $line =~ /^($reg_vol_name)\s+($reg_qtree_name)\s+(\w+)\s+(\w+)\s+(\d+)\s+(\w+)$/ ) { # v8
( $vol, $style, $oplocks, $status, $id, $vfiler ) = ( $1, $2, $3, $4, $5, $6 );
} elsif ( $line =~ /^($reg_vol_name)\s+($reg_qtree_name)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\d+)\s*$/ ) { # v7 and earlier
( $vol, $tree, $style, $oplocks, $status, $id ) = ( $1, $2, $3, $4, $5, $6 );
} elsif ( $line =~ /^($reg_path)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\d+)\s*$/ ) { # v7 and earlier
( $vol, $style, $oplocks, $status, $id ) = ( $1, $2, $3, $4, $5 );
} else {
Carp::croak "Bad Qtree Status Line: [$line]\n";
}
my $key = $vol . $id;
$qtree{$key}{volume} = $vol;
$qtree{$key}{tree} = $tree;
$qtree{$key}{style} = $style;
$qtree{$key}{oplocks} = $oplocks;
$qtree{$key}{status} = $status;
$qtree{$key}{id} = $id;
}
return wantarray ? %qtree : \%qtree;
}
sub parse_sysconfig {
my %sysconfig = ();
return ( wantarray ? %sysconfig : \%sysconfig ) unless defined $_[0];
my @lines = split "\n", $_[0];
for my $line (@lines) {
$sysconfig{SERIAL_NUM} = $1 if $line =~ /System Serial Number: (\d+) \(/;
}
return wantarray ? %sysconfig : \%sysconfig;
}
sub parse_volstatus {
my %vols = ();
return ( wantarray ? %vols : \%vols ) unless defined $_[0];
my @lines = split "\n", $_[0];
shift @lines if $lines[0] eq '===== VOL-STATUS =====';
my @chunk; my @next_chunk; my $header_count;
for my $line (@lines) {
next if $line =~ /^[\s-]*$/; # Blank and line rows.
if ( $line =~ /Volume.*State.*Status.*Options/ ) { # header row
$header_count++;
next;
}
last if $header_count > 1;
if ( scalar(@chunk) > 0 and $line =~ /^\s*([\w\-]+)\s+(online|offline)\s+(.+?)\s\s\s+(.+)$/ ) {
push @next_chunk, $line;
my ( $volname, $volopts ) = &_parse_volstatus_block(@chunk);
$vols{$volname} = $volopts;
@chunk = @next_chunk;
@next_chunk = ();
} else {
push @chunk, $line;
}
}
if (@chunk) {
my ( $volname, $volinfo ) = &_parse_volstatus_block(@chunk);
$vols{$volname} = $volinfo;
}
return wantarray ? %vols : \%vols;
}
sub _parse_volstatus_block {
my @lines = @_;
my %volinfo;
my ( $volname, $volstate, $voloptions, $volstatus, $volaggr ) = ('','','','','');
for my $line (@lines) {
# v7 unused
next if $line =~ /Plex \//;
next if $line =~ /RAID group/;
next if $line =~ /Snapshot autodelete settings/;
next if $line =~ /Volume autosize settings/;
# v8
next if $line =~ /Volume UUID: /;
next if $line =~ /Volinfo mode: /;
next if $line =~ /Volume has clones: /;
next if $line =~ /Clone, backed by volume '/;
if ( $line =~ /^\s*([\w\-]+)\s+(online|offline|restricted)\s+(.+?)\s\s\s+(.+)$/ ) {
$volname = $1;
$volstate = $2;
$volstatus = $3;
$voloptions = $4;
} elsif ( $line =~ /^(\s{27,30}\s*|\t{5})(\S+)\s\s\s+(\S.+)$/ ) { # v7 and earlier
$volstatus .= ', ' . $2;
$voloptions .= $3;
} elsif ( $line =~ /^(\s{27,30}\s*|\t{5})(.*)$/ ) { # v7 and earlier
$voloptions .= $2;
} elsif ( $line =~ /^\s*(\w+=[\w\(\)]+,?)$/ ) { # v8
$voloptions .= $1;
} elsif ( $line =~ /^vol status: Volume '(.*?)' is temporarily busy \(snapmirror destination\)/ ) {
$volname = $1;
$volstate = 'busy';
} elsif ( $line =~ /Containing aggregate: ('[\w\-]+'|<N\/A>)/ ) {
$volaggr = $1;
$volaggr = $1 if $volaggr =~ /^'(.+)'$/;
} else {
Carp::croak "Bad Vol Status Line: [$line]\n";
}
}
$volinfo{state} = $volstate;
$volinfo{status} = $volstatus;
$volinfo{options} = $voloptions;
$volinfo{aggregate} = $volaggr;
$volinfo{notes} = '';
$volinfo{notes} = 'Volume is offline' if $volstate eq 'offline';
$volinfo{notes} = 'Volume is busy' if $volstate eq 'busy';
push(@Parse::NetApp::ASUP::concerns, "$volname is marked as $volstate") if $volstate eq 'offline' or $volstate eq 'busy';
return ( $volname, \%volinfo );
}
sub parse_xheader {
my %xheader = ();
return ( wantarray ? %xheader : \%xheader ) unless defined $_[0];
my @lines = split "\n", $_[0];
shift @lines if $lines[0] eq '===== X-HEADER DATA =====';
for my $line (@lines) {
next if $line =~ /^\s*$/;
if ( $line =~ /^([\w\-]+): (.*)$/ ) {
$xheader{$1} = $2;
} else {
Carp::croak "Bad x-header line: [$line]";
}
}
return wantarray ? %xheader : \%xheader;
}
### Overall methods
=head3 Parse::NetApp::ASUP::asup_version($raw)
Given the entire text of an ASUP, it returns the version of the file.
=cut
sub asup_version {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
my $version;
for my $line ( split '\n', $raw ) {
next unless $line =~ /^VERSION=NetApp Release ([\w\.\d]+)/;
$version = $1;
last;
}
return $version if defined $version;
for my $line ( split '\n', $raw ) {
next unless $line =~ /^X-Netapp-asup-os-version: NetApp Release ([\w\.\d]+)/;
$version = $1;
last;
}
return $version ? $version : 'unknown';
}
=head3 Parse::NetApp::ASUP::dave($raw)
Given the entire text of an ASUP, it returns a "dave" version of the file.
=cut
sub dave {
my $raw = defined $_[0]->{asup} ? $_[0]->{asup} : $_[0];
return undef unless length $raw;
my $dave;
$dave .= Parse::NetApp::ASUP::extract_headers($raw);
$dave .= Parse::NetApp::ASUP::extract_xheader($raw);
$dave .= Parse::NetApp::ASUP::extract_sysconfig_a($raw);
$dave .= Parse::NetApp::ASUP::extract_sysconfig_c($raw);
$dave .= Parse::NetApp::ASUP::extract_sysconfig_d($raw);
$dave .= Parse::NetApp::ASUP::extract_system_serial_number($raw);
$dave .= Parse::NetApp::ASUP::extract_software_licenses($raw);
$dave .= Parse::NetApp::ASUP::extract_options($raw);
$dave .= Parse::NetApp::ASUP::extract_service_usage($raw);
$dave .= Parse::NetApp::ASUP::extract_cluster_monitor($raw);
$dave .= Parse::NetApp::ASUP::extract_cf_monitor($raw);
$dave .= Parse::NetApp::ASUP::extract_interconnect_config($raw);
$dave .= Parse::NetApp::ASUP::extract_interconnect_stats($raw);
$dave .= Parse::NetApp::ASUP::extract_ifconfig_a($raw);
$dave .= Parse::NetApp::ASUP::extract_ifstat_a($raw);
$dave .= Parse::NetApp::ASUP::extract_vif_status($raw);
$dave .= Parse::NetApp::ASUP::extract_vlan_stat($raw);
$dave .= Parse::NetApp::ASUP::extract_nis_info($raw);
$dave .= Parse::NetApp::ASUP::extract_cifs_stat($raw);
$dave .= Parse::NetApp::ASUP::extract_cifs_sessions($raw);
$dave .= Parse::NetApp::ASUP::extract_cifs_shares($raw);
$dave .= Parse::NetApp::ASUP::extract_cifs_domaininfo($raw);
$dave .= Parse::NetApp::ASUP::extract_vol_language($raw);
$dave .= Parse::NetApp::ASUP::extract_httpstat($raw);
$dave .= Parse::NetApp::ASUP::extract_df($raw);
$dave .= Parse::NetApp::ASUP::extract_df_i($raw);
$dave .= Parse::NetApp::ASUP::extract_aggr_status($raw);
$dave .= Parse::NetApp::ASUP::extract_df_a($raw);
$dave .= Parse::NetApp::ASUP::extract_df_r($raw);
$dave .= Parse::NetApp::ASUP::extract_df_s($raw);
$dave .= Parse::NetApp::ASUP::extract_snap_sched($raw);
$dave .= Parse::NetApp::ASUP::extract_vol_status($raw);
$dave .= Parse::NetApp::ASUP::extract_sysconfig_r($raw);
$dave .= Parse::NetApp::ASUP::extract_unowned_disks($raw);
$dave .= Parse::NetApp::ASUP::extract_failed_disk_registry($raw);
$dave .= Parse::NetApp::ASUP::extract_fc_stats($raw);
$dave .= Parse::NetApp::ASUP::extract_fc_device_map($raw);
$dave .= Parse::NetApp::ASUP::extract_fc_link_stats($raw);
$dave .= Parse::NetApp::ASUP::extract_ecc_memory_scrubber_stats($raw);
$dave .= Parse::NetApp::ASUP::extract_usage($raw);
$dave .= Parse::NetApp::ASUP::extract_acp_list_all($raw);
$dave .= Parse::NetApp::ASUP::extract_rc($raw);
$dave .= Parse::NetApp::ASUP::extract_hosts($raw);
$dave .= Parse::NetApp::ASUP::extract_dns_info($raw);
$dave .= Parse::NetApp::ASUP::extract_resolv_conf($raw);
$dave .= Parse::NetApp::ASUP::extract_exports($raw);
$dave .= Parse::NetApp::ASUP::extract_environment($raw);
$dave .= Parse::NetApp::ASUP::extract_fcp_cfmode($raw);
$dave .= Parse::NetApp::ASUP::extract_fcp_initiator_status($raw);
$dave .= Parse::NetApp::ASUP::extract_fcp_status($raw);
$dave .= Parse::NetApp::ASUP::extract_fcp_target_adapters($raw);
$dave .= Parse::NetApp::ASUP::extract_fcp_target_configuration($raw);
$dave .= Parse::NetApp::ASUP::extract_fcp_target_stats($raw);
$dave .= Parse::NetApp::ASUP::extract_flash_card_info($raw);
$dave .= Parse::NetApp::ASUP::extract_fmm_data($raw);
$dave .= Parse::NetApp::ASUP::extract_fpolicy($raw);
$dave .= Parse::NetApp::ASUP::extract_hwassist_stats($raw);
$dave .= Parse::NetApp::ASUP::extract_ifgrp_status($raw);
$dave .= Parse::NetApp::ASUP::extract_initiator_groups($raw);
$dave .= Parse::NetApp::ASUP::extract_iscsi_alias($raw);
$dave .= Parse::NetApp::ASUP::extract_iscsi_connections($raw);
$dave .= Parse::NetApp::ASUP::extract_iscsi_initiator_status($raw);
$dave .= Parse::NetApp::ASUP::extract_iscsi_interface($raw);
$dave .= Parse::NetApp::ASUP::extract_iscsi_interface_accesslist($raw);
$dave .= Parse::NetApp::ASUP::extract_iscsi_isns($raw);
$dave .= Parse::NetApp::ASUP::extract_iscsi_nodename($raw);
$dave .= Parse::NetApp::ASUP::extract_iscsi_portals($raw);
$dave .= Parse::NetApp::ASUP::extract_iscsi_security($raw);
$dave .= Parse::NetApp::ASUP::extract_iscsi_sessions($raw);
$dave .= Parse::NetApp::ASUP::extract_iscsi_statistics($raw);
$dave .= Parse::NetApp::ASUP::extract_iscsi_status($raw);
$dave .= Parse::NetApp::ASUP::extract_iscsi_target_portal_groups($raw);
$dave .= Parse::NetApp::ASUP::extract_portsets($raw);
$dave .= Parse::NetApp::ASUP::extract_lun_config_check($raw);
$dave .= Parse::NetApp::ASUP::extract_lun_configuration($raw);
$dave .= Parse::NetApp::ASUP::extract_lun_hist($raw);
$dave .= Parse::NetApp::ASUP::extract_lun_statistics($raw);
$dave .= Parse::NetApp::ASUP::extract_nbtstat_c($raw);
$dave .= Parse::NetApp::ASUP::extract_netstat_s($raw);
$dave .= Parse::NetApp::ASUP::extract_route_gsn($raw);
$dave .= Parse::NetApp::ASUP::extract_nfsstat_cc($raw);
$dave .= Parse::NetApp::ASUP::extract_nfsstat_d($raw);
$dave .= Parse::NetApp::ASUP::extract_nsswitch_conf($raw);
$dave .= Parse::NetApp::ASUP::extract_priority_show($raw);
$dave .= Parse::NetApp::ASUP::extract_qtree_status($raw);
$dave .= Parse::NetApp::ASUP::extract_quotas($raw);
$dave .= Parse::NetApp::ASUP::extract_sas_adapter_state($raw);
$dave .= Parse::NetApp::ASUP::extract_sas_dev_stats($raw);
$dave .= Parse::NetApp::ASUP::extract_sas_expander_map($raw);
$dave .= Parse::NetApp::ASUP::extract_sas_expander_phy_state($raw);
$dave .= Parse::NetApp::ASUP::extract_sas_shelf($raw);
$dave .= Parse::NetApp::ASUP::extract_shelf_log_esh($raw);
$dave .= Parse::NetApp::ASUP::extract_shelf_log_iom($raw);
$dave .= Parse::NetApp::ASUP::extract_sis_stat($raw);
$dave .= Parse::NetApp::ASUP::extract_sis_stat_l($raw);
$dave .= Parse::NetApp::ASUP::extract_sis_status($raw);
$dave .= Parse::NetApp::ASUP::extract_sis_status_l($raw);
$dave .= Parse::NetApp::ASUP::extract_snap_list_n($raw);
$dave .= Parse::NetApp::ASUP::extract_snap_list_n_a($raw);
$dave .= Parse::NetApp::ASUP::extract_snap_reserve($raw);
$dave .= Parse::NetApp::ASUP::extract_snap_reserve_a($raw);
$dave .= Parse::NetApp::ASUP::extract_snap_sched_a($raw);
$dave .= Parse::NetApp::ASUP::extract_snap_status($raw);
$dave .= Parse::NetApp::ASUP::extract_snap_status_a($raw);
$dave .= Parse::NetApp::ASUP::extract_snapmirror_destinations($raw);
$dave .= Parse::NetApp::ASUP::extract_snapmirror_status($raw);
$dave .= Parse::NetApp::ASUP::extract_sm_allow($raw);
$dave .= Parse::NetApp::ASUP::extract_sm_conf($raw);
$dave .= Parse::NetApp::ASUP::extract_snapvault_destinations($raw);
$dave .= Parse::NetApp::ASUP::extract_snapvault_snap_sched($raw);
$dave .= Parse::NetApp::ASUP::extract_snapvault_status_l($raw);
$dave .= Parse::NetApp::ASUP::extract_snaplock($raw);
$dave .= Parse::NetApp::ASUP::extract_snaplock_clock($raw);
$dave .= Parse::NetApp::ASUP::extract_ssh($raw);
$dave .= Parse::NetApp::ASUP::extract_storage($raw);
$dave .= Parse::NetApp::ASUP::extract_sysconfig_ac($raw);
$dave .= Parse::NetApp::ASUP::extract_sysconfig_hardware_ids($raw);
$dave .= Parse::NetApp::ASUP::extract_sysconfig_m($raw);
$dave .= Parse::NetApp::ASUP::extract_usermap_cfg($raw);
$dave .= Parse::NetApp::ASUP::extract_vfiler_startup_times($raw);
$dave .= Parse::NetApp::ASUP::extract_vfilers($raw);
$dave .= Parse::NetApp::ASUP::extract_vscan($raw);
$dave .= Parse::NetApp::ASUP::extract_vscan_options($raw);
$dave .= Parse::NetApp::ASUP::extract_vscan_scanners($raw);
$dave .= Parse::NetApp::ASUP::extract_messages($raw);
return $dave;
}
=head3 Parse::NetApp::ASUP::extract($raw)
Extract the raw sections of the data into a hash structure.
=cut
sub extract {
my $raw = shift @_;
my $version = Parse::NetApp::ASUP::asup_version($raw);
$version =~ /^(\d)\.(\d)/;
my $maj = $1;
my $min = $2;
my $extracts;
if ( $maj == 8 and $min > 0 ) {
my $export = Parse::NetApp::ASUP::extract_exports($raw);
my $lun_conf = Parse::NetApp::ASUP::extract_lun_configuration($raw);
my $qtree_stat = Parse::NetApp::ASUP::extract_qtree_status($raw);
my $xheader = Parse::NetApp::ASUP::extract_xheader($raw);
$extracts = ASUP::iterative_extract($raw);
$extracts->{_METHOD} = 'Progressive';
$extracts->{export} = $export;
$extracts->{lun_conf} = $lun_conf;
$extracts->{qtree_stat} = $qtree_stat;
$extracts->{xheader} = $xheader;
} else {
$extracts->{_METHOD} = 'Singular';
$extracts->{xml} = [];
$extracts->{df} = Parse::NetApp::ASUP::extract_df($raw);
$extracts->{export} = Parse::NetApp::ASUP::extract_exports($raw);
$extracts->{header} = Parse::NetApp::ASUP::extract_headers($raw);
$extracts->{lun_conf} = Parse::NetApp::ASUP::extract_lun_configuration($raw);
$extracts->{qtree_stat} = Parse::NetApp::ASUP::extract_qtree_status($raw);
$extracts->{sysconfig_a} = Parse::NetApp::ASUP::extract_sysconfig_a($raw);
$extracts->{vol_status} = Parse::NetApp::ASUP::extract_vol_status($raw);
$extracts->{xheader} = Parse::NetApp::ASUP::extract_xheader($raw);
}
$extracts->{_VERSION} = $version;
return $extracts;
}
=head3 Parse::NetApp::Parse::NetApp::ASUP::parse($raw)
Given the entire text of an ASUP, it returns an array of hash references
that are used in the LOE generator:
( \%header, \%luns, \%qtree, \%vols )
=cut
sub parse {
my $asup = shift @_;
my $extracts = ASUP::extract($asup);
my $df = $extracts->{df};
my $export = $extracts->{export};
my $header = $extracts->{header};
my $lun_conf = $extracts->{lun_conf};
my $qtree_stat = $extracts->{qtree_stat};
my $sysconfig_a = $extracts->{sysconfig_a};
my $vol_status = $extracts->{vol_status};
my $xheader = $extracts->{xheader};
Interface::warning("NO DF DATA IN ASUP") unless $df;
Interface::warning("NO EXPORT DATA IN ASUP") unless $export;
Interface::warning("NO HEADER DATA IN ASUP") unless $header;
# It's ok not to have LUN conf data
Interface::warning("NO QTREE STATUS IN ASUP") unless $qtree_stat;
Interface::warning("NO SYSYCONFIG-A DATA IN ASUP") unless $sysconfig_a;
Interface::warning("NO VOL-STATUS DATA IN ASUP") unless $vol_status;
Interface::warning("NO X-HEADER DATA IN ASUP") unless $xheader;
# Parse header data;
my %header = Parse::NetApp::ASUP::parse_header($header);
Interface::message("Filer version is $header{short_version}");
my %xheader = Parse::NetApp::ASUP::parse_xheader($xheader);
for my $key ( keys %xheader ) { $header{$key} = $xheader{$key} unless defined $header{$key}; }
# Parse sysconfig data
my %sysconfig = Parse::NetApp::ASUP::parse_sysconfig($sysconfig_a);
# Add to header info, unless already there
for my $key ( keys %sysconfig ) {
if ( defined $header{$key} and $key ne 'SERIAL_NUM' ) {
Interface::warning("Skipping duplicate sysconfig data of type $key alread found in \%header");
push(@Parse::NetApp::ASUP::concerns,"Duplicate header data of type $key");
} elsif ( defined $header{$key} and $header{$key} ne $sysconfig{$key} ) {
Interface::warning("Duplicate header key of $key has varying data: [$header{$key}] vs [$sysconfig{$key}]");
push(@Parse::NetApp::ASUP::concerns,"Duplicate and varied header data of type $key");
} else {
$header{$key} = $sysconfig{$key};
}
}
# Parse LUN CONFiguration
my %luns = Parse::NetApp::ASUP::parse_lun($lun_conf);
Interface::message("No lun data found.") unless scalar( keys %luns ) or not defined $lun_conf;
# Parse DF
my %vols = Parse::NetApp::ASUP::parse_df($df);
Interface::warning("NO VOLUME DATA!") unless scalar( keys %vols );
# Parse qtree status data
my %qtree = Parse::NetApp::ASUP::parse_qtree($qtree_stat);
# Form a deduped list of styles of qtree on each volume for the Volume tab
my %dedupe;
for my $key ( keys %qtree ) {
my $vol = $qtree{$key}{volume};
my $style = $qtree{$key}{style};
$dedupe{$vol}{$style}++;
}
for my $vol ( keys %dedupe ) {
my @qtree_styles = sort keys %{ $dedupe{$vol} };
$vols{$vol}{qtree} = join( ', ', @qtree_styles );
}
# parse Volstatus data
my %volstatus = Parse::NetApp::ASUP::parse_volstatus($vol_status);
# Add to vol info, unless already there
for my $volume ( keys %volstatus ) {
for my $key ( keys %{ $volstatus{$volume} } ) {
if ( defined $vols{$volume}{$key} ) {
Interface::warning("Skipping duplicate volstatus data of type $key alread found in \%vols");
} else {
$vols{$volume}{$key} = $volstatus{$volume}{$key};
}
}
}
# Parse Export dara
my %export = Parse::NetApp::ASUP::parse_export($export);
for my $exported ( keys %export ) {
for my $volume ( keys %vols ) {
my $test = defined $vols{$volume}{mounted_on} ? $vols{$volume}{mounted_on} : '';
chop $test if $test =~ /\/$/; # The export can have a closing slash
if ( $exported =~ /^$test$/ ) {
$vols{$volume}{export} = $export{$exported};
}
}
}
return ( \%header, \%luns, \%qtree, \%vols );
}
1;
=head1 AUTHORSHIP:
Parse::NetApp::ASUP v1.07 2013/02/07
(c) 2012-2013, Phillip Pollard <bennie@cpan.org>
Released under the Perl Artistic License