Control-CLI-Extreme

 view release on metacpan or  search on metacpan

lib/Control/CLI/Extreme.pm  view on Meta::CPAN

		prompt			=>	undef,
		prompt_qr		=>	undef,
		morePrompt		=>	undef,
		morePrompt_qr		=>	undef,
		morePromptDelay_qr	=>	undef,
		last_cmd_success	=>	undef,
		last_cmd_errmsg		=>	undef,
		return_result		=>	$Default{return_result},
		cmd_confirm_prompt	=>	$Default{cmd_confirm_prompt},
		cmd_confirm_prompt_qr	=>	qr/$Default{cmd_confirm_prompt}/,
		cmd_initiated_prompt	=>	$Default{cmd_initiated_prompt},
		cmd_initiated_prompt_qr	=>	qr/$Default{cmd_initiated_prompt}/,
		cmd_feed_timeout	=>	$Default{cmd_feed_timeout},
		console			=>	undef,
		wake_console		=>	$Default{wake_console},
		noRefreshCmdPattern	=>	undef,
		noRefreshCmdSend	=>	undef,
		PROMPTTYPE		=>	undef,
		ENABLEPWD		=>	undef,
		ORIGBAUDRATE		=>	undef,
		ATTRIB			=>	undef,
		ATTRIBFLAG		=>	undef,
		CONFIGCONTEXT		=>	'',
		DEBUGLOGFH		=>	undef,
	};
	unless (defined $args{output_record_separator}) {	# If not already set in constructor...
		$self->output_record_separator($Default{ors});	# ...we override Control::CLI's default with our own default
	}
	foreach my $arg (keys %args) { # Accepted arguments on constructor
		if    ($arg eq 'prompt')			{ $self->prompt($args{$arg}) }
		elsif ($arg eq 'return_result')			{ $self->return_result($args{$arg}) }
		elsif ($arg eq 'more_paging')			{ $self->more_paging($args{$arg}) }
		elsif ($arg eq 'cmd_confirm_prompt')		{ $self->cmd_confirm_prompt($args{$arg}) }
		elsif ($arg eq 'cmd_initiated_prompt')		{ $self->cmd_initiated_prompt($args{$arg}) }
		elsif ($arg eq 'cmd_feed_timeout')		{ $self->cmd_feed_timeout($args{$arg}) }
		elsif ($arg eq 'console')			{ $self->console($args{$arg}) }
		elsif ($arg eq 'wake_console')			{ $self->wake_console($args{$arg}) }
		elsif ($arg eq 'debug_file')			{ $self->debug_file($args{$arg}) }
	}
	return $self;
}


# sub DESTROY {} # We don't need to override Control::CLI's destroy method


############################################### Object methods ###############################################

sub connect { # All the steps necessary to connect to a CLI session on an Extreme Networking device
	my $pkgsub = "${Package}::connect";
	my $self = shift;
	my %args;
	if (@_ == 1) { # Method invoked in the shorthand form
		$args{host} = shift;
		if ($args{host} =~ /^(.+?)\s+(\d+)$/) {
			($args{host}, $args{port}) = ($1, $2);
		}
	}
	else {
		my @validArgs = ('host', 'port', 'username', 'password', 'publickey', 'privatekey', 'passphrase',
				 'prompt_credentials', 'baudrate', 'parity', 'databits', 'stopbits', 'handshake',
				 'errmode', 'connection_timeout', 'timeout', 'read_attempts', 'wake_console',
				 'return_reference', 'blocking', 'data_with_error', 'terminal_type', 'window_size',
				 'callback', 'forcebaud', 'atomic_connect', 'non_recognized_login', 'generic_login');
		%args = parseMethodArgs($pkgsub, \@_, \@validArgs);
	}

	# Initialize the base POLL structure
	$self->poll_struct( # $methodName, $codeRef, $blocking, $timeout, $errmode, $outputType, $outputRequested, $returnReference, $returnList
				$pkgsub,
				__PACKAGE__->can('connect_poll'),
				defined $args{blocking} ? $args{blocking} : $self->{blocking},
				defined $args{connection_timeout} ? $args{connection_timeout} : $self->{connection_timeout},
				defined $args{errmode} ? parse_errmode($pkgsub, $args{errmode}) : undef,
				1,
				wantarray,
				defined $args{return_reference} ? $args{return_reference} : $self->{return_reference},
				undef,	# n/a
			);
	$self->{POLL}{$pkgsub} = { # Populate structure with method arguments/storage
		# Set method argument keys
		host			=>	$args{host},
		port			=>	$args{port},
		username		=>	$args{username},
		password		=>	$args{password},
		publickey		=>	$args{publickey},
		privatekey		=>	$args{privatekey},
		passphrase		=>	$args{passphrase},
		baudrate		=>	$args{baudrate},
		parity			=>	$args{parity},
		databits		=>	$args{databits},
		stopbits		=>	$args{stopbits},
		handshake		=>	$args{handshake},
		prompt_credentials	=>	defined $args{prompt_credentials} ? $args{prompt_credentials} : $self->{prompt_credentials},
		terminal_type		=>	$args{terminal_type},
		window_size		=>	$args{window_size},
		callback		=>	$args{callback},
		forcebaud		=>	$args{forcebaud},
		atomic_connect		=>	$args{atomic_connect},
		login_timeout		=>	defined $args{timeout} ? $args{timeout} : $self->{timeout},
		read_attempts		=>	defined $args{read_attempts} ? $args{read_attempts} : $LoginReadAttempts,
		data_with_error		=>	defined $args{data_with_error} ? $args{data_with_error} : $self->{data_with_error},
		wake_console		=>	defined $args{wake_console} ? $args{wake_console} : $self->{$Package}{wake_console},
		non_recognized_login	=>	defined $args{non_recognized_login} ? $args{non_recognized_login} : $NonRecognizedLogin,
		generic_login		=>	defined $args{generic_login} ? $args{generic_login} : $GenericLogin,
		# Declare method storage keys which will be used
		stage			=>	$self->{LOGINSTAGE} ? 1 : 0,
	};
	if (!$self->{LOGINSTAGE} && $self->{TYPE} ne 'SERIAL' && useIPv6 && defined $args{blocking} && !$args{blocking}) {
		carp "$pkgsub: IO::Socket::IP is required for non-blocking connect";
	}
	local $self->{POLLING} = 1; # True until we come out of this polling-capable method
	local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};
	return __PACKAGE__->can('poll_connect')->($self, $pkgsub); # Do not call a sub-classed version
}
		

sub connect_poll { # Poll status of connection (non-blocking mode)
	my $pkgsub = "${Package}::connect_poll";
	my $self = shift;
	carp "$pkgsub: No arguments expected" if @_; # No arguments expected

	unless (defined $self->{POLL} && $self->{POLL}{coderef} == __PACKAGE__->can('connect_poll')) {
		return $self->error("$pkgsub: Method connect() needs to be called first with blocking false");
	}
	$self->{POLL}{output_requested} = wantarray; # This might change at every call
	local $self->{POLLING} = 1; # True until we come out of this polling-capable method
	local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};

	# If already completed (1) or we got an error (undef) from previous call (errmsg is already set) then we go no further
	return $self->poll_return($self->{POLL}{complete}) unless defined $self->{POLL}{complete} && $self->{POLL}{complete} == 0;

	# We get here only if we are not complete: $self->{POLL}{complete} == 0
	return __PACKAGE__->can('poll_connect')->($self, $pkgsub); # Do not call a sub-classed version
}


sub disconnect { # Perform check on restoring buadrate on device before doing Control::CLI's disconnect
	my $self = shift;
	$self->_restoreDeviceBaudrate if $self->connection_type eq 'SERIAL';
	return $self->SUPER::disconnect(@_);
}


sub login { # Handles steps necessary to get to CLI session, including menu, banner and Telnet/Serial login
	my $pkgsub = "${Package}::login";
	my $self =shift;
	my @validArgs = ('username', 'password', 'prompt_credentials', 'timeout', 'errmode', 'return_reference',
			 'read_attempts', 'wake_console', 'blocking', 'data_with_error', 'non_recognized_login', 'generic_login');
	my %args = parseMethodArgs($pkgsub, \@_, \@validArgs);

	# Initialize the base POLL structure
	$self->poll_struct( # $methodName, $codeRef, $blocking, $timeout, $errmode, $outputType, $outputRequested, $returnReference, $returnList
				$pkgsub,
				__PACKAGE__->can('login_poll'),
				defined $args{blocking} ? $args{blocking} : $self->{blocking},
				defined $args{timeout} ? $args{timeout} : $self->{timeout},
				defined $args{errmode} ? parse_errmode($pkgsub, $args{errmode}) : undef,
				1,
				wantarray,
				defined $args{return_reference} ? $args{return_reference} : $self->{return_reference},
				undef,	# n/a
			);
	$self->{POLL}{$pkgsub} = { # Populate structure with method arguments/storage
		# Set method argument keys
		username		=>	$args{username},
		password		=>	$args{password},
		prompt_credentials	=>	defined $args{prompt_credentials} ? $args{prompt_credentials} : $self->{prompt_credentials},
		read_attempts		=>	defined $args{read_attempts} ? $args{read_attempts} : $LoginReadAttempts,
		data_with_error		=>	defined $args{data_with_error} ? $args{data_with_error} : $self->{data_with_error},
		wake_console		=>	defined $args{wake_console} ? $args{wake_console} : $self->{$Package}{wake_console},
		non_recognized_login	=>	defined $args{non_recognized_login} ? $args{non_recognized_login} : $NonRecognizedLogin,
		generic_login		=>	defined $args{generic_login} ? $args{generic_login} : $GenericLogin,
		# Declare method storage keys which will be used
		stage			=>	0,
		login_attempted		=>	undef,
		password_sent		=>	undef,
		login_error		=>	'',
		family_type		=>	undef,
		cpu_slot		=>	undef,
		detectionFromPrompt	=>	undef,
	};
	local $self->{POLLING} = 1; # True until we come out of this polling-capable method
	local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};
	return __PACKAGE__->can('poll_login')->($self, $pkgsub); # Do not call a sub-classed version
}


sub login_poll { # Poll status of login (non-blocking mode)
	my $pkgsub = "${Package}::login_poll";
	my $self = shift;
	carp "$pkgsub: No arguments expected" if @_; # No arguments expected

	unless (defined $self->{POLL} && $self->{POLL}{coderef} == __PACKAGE__->can('login_poll')) {
		return $self->error("$pkgsub: Method login() needs to be called first with blocking false");
	}
	$self->{POLL}{output_requested} = wantarray; # This might change at every call
	local $self->{POLLING} = 1; # True until we come out of this polling-capable method
	local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};

	# If already completed (1) or we got an error (undef) from previous call (errmsg is already set) then we go no further
	return $self->poll_return($self->{POLL}{complete}) unless defined $self->{POLL}{complete} && $self->{POLL}{complete} == 0;

	# We get here only if we are not complete: $self->{POLL}{complete} == 0
	return __PACKAGE__->can('poll_login')->($self, $pkgsub); # Do not call a sub-classed version
}


sub cmd { # Sends a CLI command to host and returns result or output data
	my $pkgsub = "${Package}::cmd";
	my $self = shift;
	my %args;
	if (@_ == 1) { # Method invoked with just the command argument
		$args{command} = shift;
	}
	else {
		my @validArgs = ('command', 'prompt', 'reset_prompt', 'more_prompt', 'cmd_confirm_prompt', 'more_pages',
				 'timeout', 'errmode', 'return_reference', 'return_result', 'progress_dots', 'blocking', 'poll_syntax');
		%args = parseMethodArgs($pkgsub, \@_, \@validArgs);
	}
	$args{command} = '' unless defined $args{command};

	# Initialize the base POLL structure
	$self->poll_struct( # $methodName, $codeRef, $blocking, $timeout, $errmode, $outputType, $outputRequested, $returnReference, $returnList
				$pkgsub,
				__PACKAGE__->can('cmd_poll'),
				defined $args{blocking} ? $args{blocking} : $self->{blocking},
				defined $args{timeout} ? $args{timeout} : $self->{timeout},

lib/Control/CLI/Extreme.pm  view on Meta::CPAN

				undef,	# n/a
			);
	$self->{POLL}{$pkgsub} = { # Populate structure with method arguments/storage
		# Set method argument keys
		baudrate		=>	$args{baudrate},
		parity			=>	$args{parity},
		databits		=>	$args{databits},
		stopbits		=>	$args{stopbits},
		handshake		=>	$args{handshake},
		forcebaud		=>	$args{forcebaud},
		local_side_only		=>	$args{local_side_only},
		# Declare method storage keys which will be used
		stage			=>	0,
		userExec		=>	undef,
		privExec		=>	undef,
		maxMode			=>	$args{baudrate} eq 'max' ? 1:0,
	};
	$self->{POLL}{output_requested} = !$args{poll_syntax} || wantarray; # Always true in legacy syntax and in poll_syntax if wantarray
	local $self->{POLLING} = 1; # True until we come out of this polling-capable method
	local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};

	my ($ok, $baudrate) = __PACKAGE__->can('poll_change_baudrate')->($self, $pkgsub); # Do not call a sub-classed version
	# We have a different syntax for scalar output in blocking and non-blocking modes
	if ($args{poll_syntax}) { # New syntax
		return wantarray ? ($ok, $baudrate) : $ok;
	}
	else { # Old syntax
		return wantarray ? ($ok, $baudrate) : $baudrate;
	}
}


sub change_baudrate_poll { # Poll status of change_baudrate (non-blocking mode)
	my $pkgsub = "${Package}::change_baudrate_poll";
	my $self = shift;
	carp "$pkgsub: No arguments expected" if @_; # No arguments expected

	unless (defined $self->{POLL} && $self->{POLL}{coderef} == __PACKAGE__->can('change_baudrate_poll')) {
		return $self->error("$pkgsub: Method change_baudrate() needs to be called first with blocking false");
	}
	$self->{POLL}{output_requested} = wantarray; # This might change at every call
	local $self->{POLLING} = 1; # True until we come out of this polling-capable method
	local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};

	# If already completed (1) or we got an error (undef) from previous call (errmsg is already set) then we go no further
	return $self->poll_return($self->{POLL}{complete}) unless defined $self->{POLL}{complete} && $self->{POLL}{complete} == 0;

	# We get here only if we are not complete: $self->{POLL}{complete} == 0
	return __PACKAGE__->can('poll_change_baudrate')->($self, $pkgsub); # Do not call a sub-classed version
}


sub enable { # Enter PrivExec mode (handle enable password for WLAN2300)
	my $pkgsub = "${Package}::enable";
	my $self = shift;
	my %args;
	if (@_ == 1) { # Method invoked with just the command argument
		$args{password} = shift;
	}
	else {
		my @validArgs = ('password', 'prompt_credentials', 'timeout', 'errmode', 'blocking');
		%args = parseMethodArgs($pkgsub, \@_, \@validArgs);
	}

	# Initialize the base POLL structure
	$self->poll_struct( # $methodName, $codeRef, $blocking, $timeout, $errmode, $outputType, $outputRequested, $returnReference, $returnList
				$pkgsub,
				__PACKAGE__->can('enable_poll'),
				defined $args{blocking} ? $args{blocking} : $self->{blocking},
				defined $args{timeout} ? $args{timeout} : $self->{timeout},
				defined $args{errmode} ? parse_errmode($pkgsub, $args{errmode}) : undef,
				0,	# no output
				0,	# no output
				undef,	# n/a
				undef,	# n/a
			);
	$self->{POLL}{$pkgsub} = { # Populate structure with method arguments/storage
		# Set method argument keys
		enable_password		=>	defined $args{password} ? $args{password} : $self->{$Package}{ENABLEPWD},
		prompt_credentials	=>	defined $args{prompt_credentials} ? $args{prompt_credentials} : $self->{prompt_credentials},
		# Declare method storage keys which will be used
		stage			=>	0,
		login_attempted		=>	undef,
		password_sent		=>	undef,
		login_failed		=>	undef,
	};
	local $self->{POLLING} = 1; # True until we come out of this polling-capable method
	local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};
	return __PACKAGE__->can('poll_enable')->($self, $pkgsub); # Do not call a sub-classed version
}


sub enable_poll { # Poll status of enable (non-blocking mode)
	my $pkgsub = "${Package}::enable_poll";
	my $self = shift;
	carp "$pkgsub: No arguments expected" if @_; # No arguments expected

	unless (defined $self->{POLL} && $self->{POLL}{coderef} == __PACKAGE__->can('enable_poll')) {
		return $self->error("$pkgsub: Method enable() needs to be called first with blocking false");
	}
	local $self->{POLLING} = 1; # True until we come out of this polling-capable method
	local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};

	# If already completed (1) or we got an error (undef) from previous call (errmsg is already set) then we go no further
	return $self->poll_return($self->{POLL}{complete}) unless defined $self->{POLL}{complete} && $self->{POLL}{complete} == 0;

	# We get here only if we are not complete: $self->{POLL}{complete} == 0
	return __PACKAGE__->can('poll_enable')->($self, $pkgsub); # Do not call a sub-classed version
}


sub device_more_paging { # Enable/Disable more paging on host device
	my $pkgsub = "${Package}::device_more_paging";
	my $self = shift;
	my (%args, $familyType);
	if (@_ == 1) { # Method invoked with just the command argument
		$args{enable} = shift;
	}
	else {
		my @validArgs = ('enable', 'timeout', 'errmode', 'blocking');
		%args = parseMethodArgs($pkgsub, \@_, \@validArgs);
	}

	# Initialize the base POLL structure
	$self->poll_struct( # $methodName, $codeRef, $blocking, $timeout, $errmode, $outputType, $outputRequested, $returnReference, $returnList
				$pkgsub,
				__PACKAGE__->can('device_more_paging_poll'),
				defined $args{blocking} ? $args{blocking} : $self->{blocking},
				defined $args{timeout} ? $args{timeout} : $self->{timeout},
				defined $args{errmode} ? parse_errmode($pkgsub, $args{errmode}) : undef,
				0,	# no output
				0,	# no output
				undef,	# n/a
				undef,	# n/a
			);
	$self->{POLL}{$pkgsub} = { # Populate structure with method arguments/storage
		# Set method argument keys
		enable			=>	$args{enable},
		# Declare method storage keys which will be used
		stage			=>	0,
		cmdString		=>	undef,
	};
	local $self->{POLLING} = 1; # True until we come out of this polling-capable method
	local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};
	return __PACKAGE__->can('poll_device_more_paging')->($self, $pkgsub); # Do not call a sub-classed version
}


sub device_more_paging_poll { # Poll status of device_more_paging (non-blocking mode)
	my $pkgsub = "${Package}::device_more_paging_poll";
	my $self = shift;
	carp "$pkgsub: No arguments expected" if @_; # No arguments expected

	unless (defined $self->{POLL} && $self->{POLL}{coderef} == __PACKAGE__->can('device_more_paging_poll')) {
		return $self->error("$pkgsub: Method device_more_paging() needs to be called first with blocking false");
	}
	local $self->{POLLING} = 1; # True until we come out of this polling-capable method
	local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};

	# If already completed (1) or we got an error (undef) from previous call (errmsg is already set) then we go no further
	return $self->poll_return($self->{POLL}{complete}) unless defined $self->{POLL}{complete} && $self->{POLL}{complete} == 0;

	# We get here only if we are not complete: $self->{POLL}{complete} == 0
	return __PACKAGE__->can('poll_device_more_paging')->($self, $pkgsub); # Do not call a sub-classed version
}


sub device_peer_cpu { # Connect to peer CPU on ERS8x00 / VSP9000
	my $pkgsub = "${Package}::device_peer_cpu";
	my $self = shift;
	my $familyType;
	my @validArgs = ('username', 'password', 'prompt_credentials', 'timeout', 'errmode', 'blocking');
	my %args = parseMethodArgs($pkgsub, \@_, \@validArgs);

	# Initialize the base POLL structure
	$self->poll_struct( # $methodName, $codeRef, $blocking, $timeout, $errmode, $outputType, $outputRequested, $returnReference, $returnList
				$pkgsub,
				__PACKAGE__->can('device_peer_cpu_poll'),
				defined $args{blocking} ? $args{blocking} : $self->{blocking},
				defined $args{timeout} ? $args{timeout} : $self->{timeout},
				defined $args{errmode} ? parse_errmode($pkgsub, $args{errmode}) : undef,
				0,	# no output
				0,	# no output
				undef,	# n/a
				undef,	# n/a
			);
	$self->{POLL}{$pkgsub} = { # Populate structure with method arguments/storage
		# Set method argument keys
		username		=>	defined $args{username} ? $args{username} : $self->username,
		password		=>	defined $args{password} ? $args{password} : $self->password,
		prompt_credentials	=>	defined $args{prompt_credentials} ? $args{prompt_credentials} : $self->{prompt_credentials},
		# Declare method storage keys which will be used
		stage			=>	0,
	};
	local $self->{POLLING} = 1; # True until we come out of this polling-capable method
	local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};
	return __PACKAGE__->can('poll_device_peer_cpu')->($self, $pkgsub); # Do not call a sub-classed version
}


sub device_peer_cpu_poll { # Poll status of device_peer_cpu (non-blocking mode)
	my $pkgsub = "${Package}::device_peer_cpu_poll";
	my $self = shift;
	carp "$pkgsub: No arguments expected" if @_; # No arguments expected

	unless (defined $self->{POLL} && $self->{POLL}{coderef} == __PACKAGE__->can('device_peer_cpu_poll')) {
		return $self->error("$pkgsub: Method device_peer_cpu() needs to be called first with blocking false");
	}
	local $self->{POLLING} = 1; # True until we come out of this polling-capable method
	local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};

	# If already completed (1) or we got an error (undef) from previous call (errmsg is already set) then we go no further
	return $self->poll_return($self->{POLL}{complete}) unless defined $self->{POLL}{complete} && $self->{POLL}{complete} == 0;

	# We get here only if we are not complete: $self->{POLL}{complete} == 0
	return __PACKAGE__->can('poll_device_peer_cpu')->($self, $pkgsub); # Do not call a sub-classed version
}


sub debug_file { # Set debug output file
	my ($self, $fh) = @_;
	my $pkgsub = "${Package}::debug_file";

	unless (defined $fh) { # No input = return current filehandle
		return $self->{$Package}{DEBUGLOGFH};
	}
	unless (ref $fh or length $fh) { # Empty input = stop logging
		$self->{$Package}{DEBUGLOGFH} = undef;
		return;
	}
	if (!ref($fh) && !defined(fileno $fh)) { # Open a new filehandle if input is a filename
		my $logfile = $fh;
		$fh = IO::Handle->new;
		open($fh, '>', "$logfile") or return $self->error("$pkgsub: Unable to open output log file: $!");
	}
	$fh->autoflush();
	$self->{$Package}{DEBUGLOGFH} = $fh;
	return $fh;
}


#################################### Methods to set/read Object variables ####################################

sub flush_credentials { # Clear the stored username, password, passphrases, and enable password, if any
	my $self = shift;
	$self->SUPER::flush_credentials;
	$self->{$Package}{ENABLEPWD} = undef;
	return 1;
}


sub prompt { # Read/Set object prompt
	my ($self, $newSetting) = @_;
	my $currentSetting = $self->{$Package}{prompt};
	if (defined $newSetting) {
		$self->debugMsg(4, "\nPrompt Regex set to:\n$newSetting\n");
		$self->{$Package}{prompt} = $newSetting;
		$self->{$Package}{prompt_qr} = qr/$newSetting/;
	}
	return $currentSetting;
}


sub more_prompt { # Read/Set object more prompt
	my ($self, $newSetting, $delayPrompt) = @_;
	my $currentSetting = $self->{$Package}{morePrompt};
	if (defined $newSetting) {
		$self->debugMsg(4, "More Prompt Regex set to:\n$newSetting\n");
		$self->{$Package}{morePrompt} = $newSetting;
		$self->{$Package}{morePrompt_qr} = $newSetting ? qr/$newSetting/ : undef;
		$self->{$Package}{morePromptDelay_qr} = $delayPrompt ? qr/$delayPrompt/ : undef;
	}
	return $currentSetting;
}


sub more_paging { # Set the number of pages to read in the resence of --more-- prompts from host
	my ($self, $newSetting) = @_;
	my $currentSetting = $self->{$Package}{morePaging};
	$self->{$Package}{morePaging} = $newSetting if defined $newSetting;
	return $currentSetting;
}


sub progress_dots { # Enable/disable activity dots
	my ($self, $newSetting) = @_;
	my $currentSetting = $self->{$Package}{progressDots};
	$self->{$Package}{progressDots} = $newSetting if defined $newSetting;
	return $currentSetting;
}


sub return_result { # Set/read return_result mode
	my ($self, $newSetting) = @_;
	my $currentSetting = $self->{$Package}{return_result};
	$self->{$Package}{return_result} = $newSetting if defined $newSetting;
	return $currentSetting;
}


sub cmd_confirm_prompt { # Read/Set object cmd_confirm_prompt prompt
	my ($self, $newSetting) = @_;
	my $currentSetting = $self->{$Package}{cmd_confirm_prompt};
	if (defined $newSetting) {
		$self->{$Package}{cmd_confirm_prompt} = $newSetting;
		$self->{$Package}{cmd_confirm_prompt_qr} = qr/$newSetting/;

lib/Control/CLI/Extreme.pm  view on Meta::CPAN

	return $currentSetting;
}


sub last_cmd_success { # Return the result of the last command sent via cmd methods
	my ($self, $newSetting) = @_;
	my $currentSetting = $self->{$Package}{last_cmd_success};
	$self->{$Package}{last_cmd_success} = $newSetting if defined $newSetting;
	return $currentSetting;
}


sub last_cmd_errmsg { # Set/read the last generated error message from host
	my ($self, $newSetting) = @_;
	my $currentSetting = $self->{$Package}{last_cmd_errmsg};
	$self->{$Package}{last_cmd_errmsg} = $newSetting if defined $newSetting;
	return $currentSetting;
}


sub no_refresh_cmd { # Read/Set object no_refresh_cmd pattern
	my ($self, $newSetting, $sendChar) = @_;
	my $currentSetting = $self->{$Package}{noRefreshCmdPattern};
	if (defined $newSetting && (defined $sendChar || !$newSetting)) {
		$self->debugMsg(4, "NoRefreshCmdPattern Regex set to:\n$newSetting\n");
		$self->{$Package}{noRefreshCmdPattern} = $newSetting ? $newSetting : undef;
		$self->{$Package}{noRefreshCmdSend} = "\n" eq $sendChar ? $self->{ors} : $sendChar;
	}
	return $currentSetting;
}


################################# Methods to read read-only Object variables #################################

sub config_context { # Return the configuration context contained in the last prompt
	my $self = shift;
	return $self->{$Package}{CONFIGCONTEXT};
}


sub enable_password { # Read the enable password (WLAN2300)
	my $self = shift;
	return $self->{$Package}{ENABLEPWD};
}


#################################### Private poll methods for sub classes ####################################

sub poll_connect { # Internal method to connect to host and perform login (used for both blocking & non-blocking modes)
	my $self = shift;
	my $pkgsub = shift;
	my $pollsub = "${Package}::connect";

	unless ($self->{POLLING}) { # Sanity check
		my (undef, $fileName, $lineNumber) = caller;
		croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
	}

	unless (defined $self->{POLL}{$pollsub}) { # Only applicable if called from another method already in polling mode
		my @validArgs = ('host', 'port', 'username', 'password', 'publickey', 'privatekey', 'passphrase',
				 'prompt_credentials', 'baudrate', 'parity', 'databits', 'stopbits', 'handshake',
				 'errmode', 'connection_timeout', 'login_timeout', 'read_attempts', 'wake_console',
				 'data_with_error', 'terminal_type', 'window_size', 'callback', 'forcebaud',
				 'atomic_connect', 'non_recognized_login', 'generic_login');
		my %args = parseMethodArgs($pkgsub, \@_, \@validArgs, 1);
		if (@_ && !%args) { # Legacy syntax
			($args{host}, $args{port}, $args{username}, $args{password}, $args{publickey}, $args{privatekey},
			 $args{passphrase}, $args{baudrate}, $args{parity}, $args{databits}, $args{stopbits},
			 $args{handshake}, $args{prompt_credentials}, $args{read_attempts}, $args{wake_console},
			 $args{connection_timeout}, $args{login_timeout}, $args{errmode}) = @_;
		}
		# In which case we need to setup the poll structure for them here (the main poll structure remains unchanged)
		$self->{POLL}{$pollsub} = { # Populate structure with method arguments/storage
			# Set method argument keys
			host			=>	$args{host},
			port			=>	$args{port},
			username		=>	defined $args{username} ? $args{username} : $self->{USERNAME},
			password		=>	defined $args{password} ? $args{password} : $self->{PASSWORD},
			publickey		=>	$args{publickey},
			privatekey		=>	$args{privatekey},
			passphrase		=>	defined $args{passphrase} ? $args{passphrase} : $self->{PASSPHRASE},
			baudrate		=>	$args{baudrate},
			parity			=>	$args{parity},
			databits		=>	$args{databits},
			stopbits		=>	$args{stopbits},
			handshake		=>	$args{handshake},
			prompt_credentials	=>	defined $args{prompt_credentials} ? $args{prompt_credentials} : $self->{prompt_credentials},
			terminal_type		=>	$args{terminal_type},
			window_size		=>	$args{window_size},
			callback		=>	$args{callback},
			forcebaud		=>	$args{forcebaud},
			atomic_connect		=>	$args{atomic_connect},
			login_timeout		=>	defined $args{login_timeout} ? $args{login_timeout} : $self->{timeout},
			read_attempts		=>	defined $args{read_attempts} ? $args{read_attempts} : $LoginReadAttempts,
			data_with_error		=>	defined $args{data_with_error} ? $args{data_with_error} : $self->{data_with_error},
			wake_console		=>	defined $args{wake_console} ? $args{wake_console} : $self->{$Package}{wake_console},
			non_recognized_login	=>	defined $args{non_recognized_login} ? $args{non_recognized_login} : $NonRecognizedLogin,
			generic_login		=>	defined $args{generic_login} ? $args{generic_login} : $GenericLogin,
			# Declare method storage keys which will be used
			stage			=>	$self->{LOGINSTAGE} ? 1 : 0,
			# Declare keys to be set if method called from another polled method
			errmode			=>	$args{errmode},
		};
		# Cache poll structure keys which this method will use
		$self->poll_struct_cache($pollsub, $args{connection_timeout});
	}
	my $connect = $self->{POLL}{$pollsub};
	local $self->{errmode} = $connect->{errmode} if defined $connect->{errmode};

	if ($connect->{stage} < 1) { # Connect stage
		my $ok = $self->SUPER::poll_connect($pkgsub,
			Host			=> $connect->{host},
			Port			=> $connect->{port},
			Username		=> $connect->{username},
			Password		=> $connect->{password},
			PublicKey		=> $connect->{publickey},
			PrivateKey		=> $connect->{privatekey},
			Passphrase		=> $connect->{passphrase},
			BaudRate		=> $connect->{baudrate},
			ForceBaud		=> $connect->{forcebaud},
			Parity			=> $connect->{parity},
			DataBits		=> $connect->{databits},
			StopBits		=> $connect->{stopbits},
			Handshake		=> $connect->{handshake},
			Prompt_credentials	=> $connect->{prompt_credentials},
			Terminal_type		=> $connect->{terminal_type},
			Window_size		=> $connect->{window_size},
			Callback		=> $connect->{callback},
			Atomic_connect		=> $connect->{atomic_connect},
		);
		return $self->poll_return($ok) unless $ok; # Come out if error (if errmode='return'), or if nothing to read in non-blocking mode
		# Unless console already set, set it now; will determine whether or not wake_console is sent upon login
		$self->console(	 $self->connection_type eq 'SERIAL' ||
				($self->connection_type eq 'TELNET' && $self->port != 23) ||
				($self->connection_type eq 'SSH'    && $self->port != 22) ) unless defined $self->console;
		$connect->{stage}++; # Ensure we don't come back here in non-blocking mode
	}

	# Login stage
	my ($ok, $outRef) = $self->poll_login($pkgsub,
			Username		=> $connect->{username},
			Password		=> $connect->{password},
			Read_attempts		=> $connect->{read_attempts},
			Wake_console		=> $connect->{wake_console},
			Data_with_error		=> $connect->{data_with_error},
			Non_recognized_login	=> $connect->{non_recognized_login},
			Generic_login		=> $connect->{generic_login},
			Prompt_credentials	=> $connect->{prompt_credentials},
			Timeout			=> $connect->{login_timeout},
	);
	$self->{POLL}{output_buffer} = $$outRef if $ok;
	return $self->poll_return($ok);
}


sub poll_login { # Method to handle login for poll methods (used for both blocking & non-blocking modes)
	my $self = shift;
	my $pkgsub = shift;
	my $pollsub = "${Package}::login";

	unless ($self->{POLLING}) { # Sanity check
		my (undef, $fileName, $lineNumber) = caller;
		croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
	}

	unless (defined $self->{POLL}{$pollsub}) { # Only applicable if called from another method already in polling mode
		my @validArgs = ('username', 'password', 'prompt_credentials', 'timeout', 'errmode', 'read_attempts', 'wake_console',
				 'data_with_error', 'non_recognized_login', 'generic_login');
		my %args = parseMethodArgs($pkgsub, \@_, \@validArgs, 1);
		if (@_ && !%args) { # Legacy syntax
			($args{username}, $args{password}, $args{read_attempts}, $args{wake_console},
			 $args{prompt_credentials}, $args{data_with_error}, $args{timeout}, $args{errmode}) = @_;
		}
		# In which case we need to setup the poll structure for them here (the main poll structure remains unchanged)
		$self->{POLL}{$pollsub} = { # Populate structure with method arguments/storage
			# Set method argument keys
			username		=>	defined $args{username} ? $args{username} : $self->{USERNAME},
			password		=>	defined $args{password} ? $args{password} : $self->{PASSWORD},
			prompt_credentials	=>	defined $args{prompt_credentials} ? $args{prompt_credentials} : $self->{prompt_credentials},
			read_attempts		=>	defined $args{read_attempts} ? $args{read_attempts} : $LoginReadAttempts,
			data_with_error		=>	defined $args{data_with_error} ? $args{data_with_error} : $self->{data_with_error},
			wake_console		=>	defined $args{wake_console} ? $args{wake_console} : $self->{$Package}{wake_console},
			non_recognized_login	=>	defined $args{non_recognized_login} ? $args{non_recognized_login} : $NonRecognizedLogin,
			generic_login		=>	defined $args{generic_login} ? $args{generic_login} : $GenericLogin,
			# Declare method storage keys which will be used
			stage			=>	0,
			login_attempted		=>	undef,
			password_sent		=>	undef,
			login_error		=>	'',
			family_type		=>	undef,
			cpu_slot		=>	undef,
			detectionFromPrompt	=>	undef,
			# Declare keys to be set if method called from another polled method
			errmode			=>	$args{errmode},
		};
		# Cache poll structure keys which this method will use
		$self->poll_struct_cache($pollsub, $args{timeout});
	}
	my $login = $self->{POLL}{$pollsub};
	local $self->{errmode} = $login->{errmode} if defined $login->{errmode};
	return $self->poll_return($self->error("$pkgsub: No connection to login to")) if $self->eof;

	my $usernamePrompt = $self->username_prompt;
	my $passwordPrompt = $self->password_prompt;

	if ($login->{stage} < 1) { # Initial loginstage & setup - do only once
		$login->{stage}++; # Ensure we don't come back here in non-blocking mode
		if ($self->{LOGINSTAGE}) {
			$login->{family_type} = $self->{$Package}{ATTRIB}{'family_type'}; # Might be already set from previous login attempt
		}
		else {	# Flush all attributes, as we assume we are connecting to a new device
			$self->{$Package}{ATTRIB} = undef;
			$self->{$Package}{ATTRIBFLAG} = undef;
		}
		# Handle resuming previous login attempt
		if ($self->{LOGINSTAGE} eq 'username' && $login->{username}) { # Resume login from where it was left
			$self->print(line => $login->{username}, errmode => 'return')
				or return $self->poll_return($self->error("$pkgsub: Unable to send username // ".$self->errmsg));
			$self->{LOGINSTAGE} = '';
			$login->{login_attempted} = 1;
		}
		elsif ($self->{LOGINSTAGE} eq 'password' && $login->{password}) { # Resume login from where it was left
			$self->print(line => $login->{password}, errmode => 'return')
				or return $self->poll_return($self->error("$pkgsub: Unable to send password // ".$self->errmsg));
			$self->{LOGINSTAGE} = '';
			$login->{login_attempted} = 1;
		}
		elsif ($self->console && $login->{wake_console}) {
			$self->debugMsg(8,"\nlogin() Sending wake_console sequence >$login->{wake_console}<\n");
			$self->put(string => $login->{wake_console}, errmode => 'return') # Bring connection into life
				or return $self->poll_return($self->error("$pkgsub: Unable to send bring alive character sequence // ".$self->errmsg));
		}
	}
	if ($login->{stage} < 2) { # Main login loop
		my ($pattern, $patdepth, $deepest);
		my ($promptType, $capturedPrompt, $switchName, $cliType, $configContext);
		LOGINLOOP: while (1) {
			# Wait until we have read in all available data
			my $ok = $self->poll_readwait($pkgsub, 1, $login->{read_attempts}, $ReadwaitTimer, $login->{login_error}.'Failed reading login prompt', $login->{data_with_error});

lib/Control/CLI/Extreme.pm  view on Meta::CPAN

				$self->debugMsg(8,"\nlogin() Matched Password prompt\n\n");
				$pattern = 'password';
			}

			# Now handle any pattern matches we had above
			if ($pattern eq 'oneosbanner') { # We end up here when, sometimes, OneOS puts the prompt before the banner
				$self->print(); # So we need to force a new prompt for login to succeed
				next;
			}
			elsif ($pattern eq 'banner' || $pattern eq 'bell') { # We got the banner, send a CTRL-Y to get in
				$self->debugMsg(8,"\nlogin() Processing Stackable Banner\n\n");
				$self->put(string => $CTRL_Y, errmode => 'return')
					or return $self->poll_return($self->error("$pkgsub: Unable to send CTRL-Y sequence // ".$self->errmsg));
				next;
			}
			elsif ($pattern eq 'menu') { # We got the menu, send a 'c' and get into CLI
				$self->debugMsg(8,"\nlogin() Processing Stackable Menu\n\n");
				$self->put(string => 'c', errmode => 'return')
					or return $self->poll_return($self->error("$pkgsub: Unable to select 'Command Line Interface...' // ".$self->errmsg));
				next;
			}
			elsif ($pattern eq 'submenu') { # We are in a sub-menu page, send a 'CTRL_C' to get to main menu page
				$self->debugMsg(8,"\nlogin() Processing Stackable Sub-Menu page\n\n");
				$self->put(string => $CTRL_C, errmode => 'return')
					or return $self->poll_return($self->error("$pkgsub: Unable to go back to main menu page // ".$self->errmsg));
				next;
			}
			elsif ($pattern =~ /^more\d$/) { # We are connecting on the console port, and we are in the midst of more-paged output
				$self->debugMsg(8,"\nlogin() Quitting residual more-paged output for serial port access\n");
				$self->put(string => 'q', errmode => 'return')
					or return $self->poll_return($self->error("$pkgsub: Unable to quit more-paged output found after serial connect // ".$self->errmsg));
				next;
			}
			elsif ($pattern =~ /^consoleLogMsg\d$/) { # We are connecting on the console port, and this log message is spoiling our 1st prompt
				$self->debugMsg(8,"\nlogin() Sending extra carriage return after password for serial port access\n");
				# On Modular VSPs Console port, immediately after login you get log message :SW INFO user rwa connected via console port
				# As this message is appended to the very 1st prompt, we are not able to lock on that initial prompt
				# So we feed an extra carriage return so that we can lock on a fresh new prompt
				$self->print(errmode => 'return')
					or return $self->poll_return($self->error("$pkgsub: Unable to get new prompt after console log message // ".$self->errmsg));
				next;
			}
			elsif ($pattern eq 'lastlogin') { # Last login splash screen; skip it with RETURN key
				# This screen appears on ERS4800 release 5.8
				$self->debugMsg(8,"\nlogin() Processing Last Login screen\n\n");
				$self->print(errmode => 'return')
					or return $self->poll_return($self->error("$pkgsub: Unable to send Carriage Return // ".$self->errmsg));
				next;
			}
			elsif ($pattern eq 'username') { # Handle login prompt
				$self->debugMsg(8,"\nlogin() Processing Login/Username prompt\n\n");
				if ($login->{login_attempted}) {
					$self->{LOGINSTAGE} = 'username';
					return $self->poll_return($self->error("$pkgsub: Incorrect Username or Password"));
				}
				unless ($login->{username}) {
					if ($self->{TYPE} eq 'SSH') { # If an SSH connection, we already have the username
						$login->{username} = $self->{USERNAME};
					}
					else {
						unless ($login->{prompt_credentials}) {
							$self->{LOGINSTAGE} = 'username';
							return $self->poll_return($self->error("$pkgsub: Username required"));
						}
						$login->{username} = promptCredential($login->{prompt_credentials}, 'Clear', 'Username');
					}
				}
				$self->print(line => $login->{username}, errmode => 'return')
					or return $self->poll_return($self->error("$pkgsub: Unable to send username // ".$self->errmsg));
				$self->{LOGINSTAGE} = '';
				$login->{login_attempted} = 1;
				next;
			}
			elsif ($pattern eq 'password') { # Handle password prompt
				$self->debugMsg(8,"\nlogin() Processing Password prompt\n\n");
				if ($login->{password_sent}) {
					$self->{LOGINSTAGE} = 'password';
					return $self->poll_return($self->error("$pkgsub: Incorrect Username or Password"));
				}
				unless (defined $login->{password}) {
					unless ($login->{prompt_credentials}) {
						$self->{LOGINSTAGE} = 'password';
						return $self->poll_return($self->error("$pkgsub: Password required"));
					}
					$login->{password} = promptCredential($login->{prompt_credentials}, 'Hide', 'Password');
				}
				$self->print(line => $login->{password}, errmode => 'return')
					or return $self->poll_return($self->error("$pkgsub: Unable to send password // ".$self->errmsg));
				$self->{LOGINSTAGE} = '';
				$login->{password_sent} = 1;
				next;
			}
			elsif ($pattern =~ /^localfail/) { # Login failure
				return $self->poll_return($self->error("$pkgsub: Incorrect Username or Password"));
			}
			elsif ($pattern eq 'radiusfail') { # Radius Login failure
				return $self->poll_return($self->error("$pkgsub: Switch got access denied from RADIUS"));
			}
			elsif ($pattern =~ /^radiustimeout\d$/) { # Radius timeout
				$login->{login_error} = "Switch got no response from RADIUS servers\n";
				next; # In this case don't error, as radius falback might still get us in
			}
			if (!$login->{family_type} && $login->{non_recognized_login}) { # If we have some complete output, which does not match any of the above, we can come out if we asked to
				return $self->poll_return($self->error("$pkgsub: Non recognized login output"));
			}
		} # LOGINLOOP
		if (!$login->{generic_login} && ($login->{family_type} eq $Prm{generic} || ($login->{detectionFromPrompt} && $self->{LASTPROMPT} !~ /^@/)) ) { # Can't tell, need extended discovery
			$login->{stage}++; # Move to next section in non-blocking mode
		}
		else {
			$login->{stage} += 2; # Move to section after next
		}
		return $self->poll_return(0) unless $self->{POLL}{blocking};
	}
	if ($login->{stage} < 3) { # Extended discovery
		my ($ok, $familyType) = $self->discoverDevice($pkgsub);
		return $self->poll_return($ok) unless $ok; # Come out if error or if not done yet in non-blocking mode
		$login->{family_type} = $familyType;
		if ($login->{family_type} eq $Prm{generic} && ($self->{errmode} eq 'croak' || $self->{errmode} eq 'die')) {
			carp "\n$pkgsub Warning! Device type not detected; using $Prm{generic}\n";
		}
		$login->{stage} += 2; # Move to final section
	}
	if ($login->{stage} < 4) { # Generic_login OR family type was detected, not just from the prompt (though we do rely on prompt alone for Standby CPUs on PassportERS)
		if ($login->{family_type} eq $Prm{pers} || $login->{family_type} eq $Prm{xlr}) {
			$self->_setAttrib('is_master_cpu', $self->{LASTPROMPT} =~ /^@/ ? 0 : 1);
			$self->_setAttrib('is_dual_cpu', 1) if $self->{LASTPROMPT} =~ /^@/;
		}
		$self->_setFamilyTypeAttrib($login->{family_type}) if $login->{detectionFromPrompt};
	}

	# Store credentials if these were used
	($self->{USERNAME}, $self->{PASSWORD}) = ($login->{username}, $login->{password}) if $login->{login_attempted};
	return $self->poll_return(1);
}


sub poll_cmd { # Method to handle cmd for poll methods (used for both blocking & non-blocking modes)
	my $self = shift;
	my $pkgsub = shift;
	my $pollsub = "${Package}::cmd";

	unless ($self->{POLLING}) { # Sanity check
		my (undef, $fileName, $lineNumber) = caller;
		croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
	}

	unless (defined $self->{POLL}{$pollsub}) { # Only applicable if called from another method already in polling mode
		my @validArgs = ('command', 'feed_list', 'prompt', 'reset_prompt', 'more_prompt', 'cmd_confirm_prompt',
				  'cmd_initiated_prompt', 'more_pages', 'timeout', 'errmode', 'progress_dots');
		my %args = parseMethodArgs($pkgsub, \@_, \@validArgs, 1);
		if (@_ && !%args) { # Legacy syntax
			($args{command}, $args{more_pages}, $args{prompt}, $args{reset_prompt}, $args{timeout}, $args{errmode},
			 $args{feed_list}, $args{cmd_confirm_prompt}, $args{cmd_initiated_prompt}) = @_;
		}
		$args{feed_list} = [$args{feed_list}] if defined $args{feed_list} && ref($args{feed_list}) ne "ARRAY";	# We want it as an array reference
		# In which case we need to setup the poll structure for them here (the main poll structure remains unchanged)
		$self->{POLL}{$pollsub} = { # Populate structure with method arguments/storage
			# Set method argument keys
			command			=>	$args{command},
			prompt			=>	defined $args{prompt} ? $args{prompt} : $self->{$Package}{prompt_qr},
			more_prompt		=>	defined $args{more_prompt} ? $args{more_prompt} : $self->{$Package}{morePrompt_qr},
			more_prompt_delay	=>	defined $args{more_prompt} ? undef : $self->{$Package}{morePromptDelay_qr},
			more_pages		=>	defined $args{more_pages} ? $args{more_pages} : $self->{$Package}{morePaging},
			reset_prompt		=>	$args{reset_prompt} && defined $self->{$Package}{PROMPTTYPE},
			yn_prompt		=>	defined $args{cmd_confirm_prompt} ? $args{cmd_confirm_prompt} : $self->{$Package}{cmd_confirm_prompt_qr},
			cmd_prompt		=>	defined $args{cmd_initiated_prompt} ? $args{cmd_initiated_prompt} : $self->{$Package}{cmd_initiated_prompt_qr},
			feed_data		=>	$args{feed_list},
			progress_dots		=>	defined $args{progress_dots} ? $args{progress_dots} : $self->{$Package}{progressDots},
			# Declare method storage keys which will be used
			stage			=>	0,
			lastLine		=>	'',
			outputNewline		=>	'',
			progress		=>	undef,
			alreadyCmdTimeout	=>	0,
			ynPromptCount		=>	undef,
			cmdPromptCount		=>	undef,
			cmdEchoRemoved		=>	0,
			lastPromptEchoedCmd	=>	undef,
			cache_timeout		=>	defined $args{timeout} ? $args{timeout} : $self->{POLL}{timeout},
			noRefreshCmdDone	=>	undef,
			morePromptDelayed	=>	undef,
			morePromptRemoved	=>	undef,
			# Declare keys to be set if method called from another polled method
			errmode			=>	$args{errmode},
		};
		# Cache poll structure keys which this method will use
		$self->poll_struct_cache($pollsub, $args{timeout});
	}

	my $cmd = $self->{POLL}{$pollsub};
	local $self->{errmode} = $cmd->{errmode} if defined $cmd->{errmode};

lib/Control/CLI/Extreme.pm  view on Meta::CPAN


	if ($changeBaud->{stage} < 8) { # 8th stage
		my $ok = $self->poll_cmd($pkgsub, ''); # Send carriage return + ensure we get valid prompt back
		return $self->poll_return($ok) unless $ok; # Come out if error or if not done yet in non-blocking mode
		$changeBaud->{stage}++; # Move to 9th stage
	}

	if ($changeBaud->{stage} < 9) { # 9th stage
		if ( ($familyType eq $Prm{pers} && $self->{$Package}{ATTRIB}{'is_nncli'}) || $familyType eq $Prm{s200}) {
			if ($changeBaud->{privExec}) {
				my ($ok, undef, $resref) = $self->poll_cmd($pkgsub, 'end');
				return $self->poll_return($ok) unless $ok; # Come out if error or if not done yet in non-blocking mode
				return $self->poll_return($self->error("$pkgsub: Error while changing baud rate")) unless $$resref;
			}
		}
		$changeBaud->{stage}++; # Move to 10th stage
	}

	if ($changeBaud->{stage} < 10) { # 10th stage
		$changeBaud->{stage}++; # Move to 1th stage
		if ( ($familyType eq $Prm{pers} && $self->{$Package}{ATTRIB}{'is_nncli'}) || $familyType eq $Prm{s200}) {
			if ($changeBaud->{userExec}) {
				my $disableCmd;
				if (defined $ExitPrivExec{$familyType}) {
					$disableCmd = $ExitPrivExec{$familyType};
					$self->put($disableCmd);
				}
				else {
					$disableCmd = 'disable';
					$self->print($disableCmd);
				}
				$self->debugMsg(8,"\npoll_change_baudrate() Sending command:>", \$disableCmd, "<\n");
			}
		}
	}
	if ($changeBaud->{stage} < 11) { # 11th stage
		if ( ($familyType eq $Prm{pers} && $self->{$Package}{ATTRIB}{'is_nncli'}) || $familyType eq $Prm{s200}) {
			if ($changeBaud->{userExec}) {
				my ($ok, undef, $resref) = $self->poll_cmd($pkgsub);
				return $self->poll_return($ok) unless $ok; # Come out if error or if not done yet in non-blocking mode
				return $self->poll_return($self->error("$pkgsub: Error while changing baud rate")) unless $$resref;
			}
		}
	}
	$self->{POLL}{output_result} = $changeBaud->{baudrate};
	return $self->poll_return(1);
}


sub poll_enable { # Method to handle enable for poll methods (used for both blocking & non-blocking modes)
	my $self = shift;
	my $pkgsub = shift;
	my $pollsub = "${Package}::enable";

	unless ($self->{POLLING}) { # Sanity check
		my (undef, $fileName, $lineNumber) = caller;
		croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
	}

	unless (defined $self->{POLL}{$pollsub}) { # Only applicable if called from another method already in polling mode
		my @validArgs = ('password', 'prompt_credentials', 'timeout', 'errmode');
		my %args = parseMethodArgs($pkgsub, \@_, \@validArgs, 1);
		if (@_ && !%args) { # Legacy syntax
			($args{password}, $args{prompt_credentials}, $args{timeout}, $args{errmode}) = @_;
		}
		# In which case we need to setup the poll structure for them here (the main poll structure remains unchanged)
		$self->{POLL}{$pollsub} = { # Populate structure with method arguments/storage
			# Set method argument keys
			enable_password		=>	defined $args{password} ? $args{password} : $self->{$Package}{ENABLEPWD},
			prompt_credentials	=>	defined $args{prompt_credentials} ? $args{prompt_credentials} : $self->{prompt_credentials},
			# Declare method storage keys which will be used
			stage			=>	0,
			login_attempted		=>	undef,
			login_failed		=>	undef,
			# Declare keys to be set if method called from another polled method
			errmode			=>	$args{errmode},
		};
		# Cache poll structure keys which this method will use
		$self->poll_struct_cache($pollsub, $args{timeout});
	}
	my $enable = $self->{POLL}{$pollsub};
	local $self->{errmode} = $enable->{errmode} if defined $enable->{errmode};
	return $self->poll_return($self->error("$pkgsub: No connection to enable")) if $self->eof;
	my $familyType = $self->{$Package}{ATTRIB}{'family_type'} || '';
	my $prompt = $self->{$Package}{prompt_qr};
	my $passwordPrompt = $self->{password_prompt_qr};
	my $enablePwd;

	if ($enable->{stage} < 1) { # 1st stage
		$enable->{stage}++; # Ensure we don't come back here in non-blocking mode
		return $self->poll_return($self->error("$pkgsub: No connection established")) unless $familyType;
		return $self->poll_return(1) unless $self->{$Package}{ATTRIB}{'is_nncli'}; # Come out if not in NNCLI mode
		return $self->poll_return(1) unless $self->last_prompt =~ />\s?$/; # Come out if not in UserExec mode
		# Flush any unread data which might be pending
		$self->read(blocking => 0);
		# Send enable command
		$self->print(line => 'enable', errmode => 'return')
			or return $self->poll_return($self->error("$pkgsub: Unable to send CLI command: enable // ".$self->errmsg));
	}

	# Main loop
	do {
		my $ok = $self->poll_read($pkgsub, 'Failed after enable command');
		return $self->poll_return($ok) unless $ok;

		$self->{POLL}{local_buffer} .= $self->{POLL}{read_buffer};
		$enable->{login_failed}++ if $self->{POLL}{local_buffer} =~ /error: Access denied/;
		if ($self->{POLL}{local_buffer} =~ /$passwordPrompt/) { # Handle password prompt
			$enable->{login_attempted}++;
			if (defined $enable->{enable_password}) { # An enable password is supplied
				if ($enable->{login_attempted} == 1) {	# First try; use supplied
					$enablePwd = $enable->{enable_password};
					$self->debugMsg(4,"enable() Sending supplied password\n");
					$self->print(line => $enablePwd, errmode => 'return')
						or return $self->poll_return($self->error("$pkgsub: Unable to send enable password // ".$self->errmsg));
				}
				else {				# Next tries, enter blanks
					$enablePwd = '';
					$self->debugMsg(4,"enable() Sending carriage return instead of supplied password\n");
					$self->print(errmode => 'return')
						or return $self->poll_return($self->error("$pkgsub: Unable to send blank password // ".$self->errmsg));
				}
			}
			else { # No password supplied
				if ($enable->{login_attempted} == 1) {	# First try; use blank
					$enablePwd = '';
					$self->debugMsg(4,"enable() Sending carriage return for password\n");
					$self->print(errmode => 'return')
						or return $self->poll_return($self->error("$pkgsub: Unable to send blank password // ".$self->errmsg));
				}
				elsif ($enable->{login_attempted} == 2) {	# Second try; use cached login password
					$enablePwd = $self->password || '';
					$self->debugMsg(4,"enable() Sending login password for enable password\n");
					$self->print(line => $enablePwd, errmode => 'return')
						or return $self->poll_return($self->error("$pkgsub: Unable to send cached password // ".$self->errmsg));
				}
				else {				# Third try; prompt?
					if ($enable->{prompt_credentials}) {
						$enablePwd = promptCredential($enable->{prompt_credentials}, 'Hide', 'Enable Password');
						$self->print(line => $enablePwd, errmode => 'return')
							or return $self->poll_return($self->error("$pkgsub: Unable to send enable password // ".$self->errmsg));
					}
					else {			# Enter blanks
						$enablePwd = '';
						$self->debugMsg(4,"enable() Sending carriage return instead of prompting for password\n");
						$self->print(errmode => 'return')
							or return $self->poll_return($self->error("$pkgsub: Unable to send blank password // ".$self->errmsg));
					}
				}
			}
			$self->{POLL}{local_buffer} = '';
		}
	} until ($self->{POLL}{local_buffer} =~ /($prompt)/);
	$self->_setLastPromptAndConfigContext($1, $2);
	return $self->poll_return($self->error("$pkgsub: Password required")) if $enable->{login_failed};
	return $self->poll_return($self->error("$pkgsub: Failed to enter PrivExec mode")) if $self->last_prompt =~ />\s?$/; # If still in UserExec mode
	$self->{$Package}{ENABLEPWD} = $enablePwd if defined $enablePwd;
	return $self->poll_return(1);
}


sub poll_device_more_paging { # Method to handle device_more_paging for poll methods (used for both blocking & non-blocking modes)
	my $self = shift;
	my $pkgsub = shift;
	my $pollsub = "${Package}::device_more_paging";

	unless ($self->{POLLING}) { # Sanity check
		my (undef, $fileName, $lineNumber) = caller;
		croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
	}

	unless (defined $self->{POLL}{$pollsub}) { # Only applicable if called from another method already in polling mode
		my @validArgs = ('enable', 'timeout', 'errmode');
		my %args = parseMethodArgs($pkgsub, \@_, \@validArgs, 1);
		if (@_ && !%args) { # Legacy syntax
			($args{enable}, $args{timeout}, $args{errmode}) = @_;
		}
		# In which case we need to setup the poll structure for them here (the main poll structure remains unchanged)
		$self->{POLL}{$pollsub} = { # Populate structure with method arguments/storage
			# Set method argument keys
			enable			=>	$args{enable},
			# Declare method storage keys which will be used
			stage			=>	0,
			cmdString		=>	undef,
			# Declare keys to be set if method called from another polled method
			errmode			=>	$args{errmode},
		};
		# Cache poll structure keys which this method will use
		$self->poll_struct_cache($pollsub, $args{timeout});
	}
	my $devMorePage = $self->{POLL}{$pollsub};
	local $self->{errmode} = $devMorePage->{errmode} if defined $devMorePage->{errmode};
	return $self->poll_return($self->error("$pkgsub: No connection to set more paging on")) if $self->eof;
	my $familyType = $self->{$Package}{ATTRIB}{'family_type'} || '';

	return $self->poll_return($self->error("$pkgsub: No connection established")) unless $familyType;
	if ($familyType eq $Prm{bstk}) {
		$devMorePage->{cmdString} = $devMorePage->{enable} ? 23 : 0 unless defined $devMorePage->{cmdString};
		my ($ok, undef, $resref) = $self->poll_cmd($pkgsub, "terminal length $devMorePage->{cmdString}");

lib/Control/CLI/Extreme.pm  view on Meta::CPAN

	elsif ($familyType eq $Prm{isw}) {
		$devMorePage->{cmdString} = $devMorePage->{enable} ? '24' : '0' unless defined $devMorePage->{cmdString};
		my ($ok, undef, $resref) = $self->cmdPrivExec($pkgsub, undef, ($self->config_context ? 'do ':'') . "terminal length $devMorePage->{cmdString}");
		return $self->poll_return($ok) unless $ok;
		return $self->poll_return($self->error("$pkgsub: Failed to set more-paging mode")) unless $$resref;
	}
	elsif ($familyType eq $Prm{iswMarv}) {
		$devMorePage->{cmdString} = $devMorePage->{enable} ? '1' : '0' unless defined $devMorePage->{cmdString};
		my ($ok, undef, $resref) = $self->cmdConfig($pkgsub, '', "setenv pagefilter $devMorePage->{cmdString}");
		return $self->poll_return($ok) unless $ok;
		return $self->poll_return($self->error("$pkgsub: Failed to set more-paging mode")) unless $$resref;
	}
	elsif ($familyType eq $Prm{wing}) {
		$devMorePage->{cmdString} = $devMorePage->{enable} ? '24' : '0' unless defined $devMorePage->{cmdString};
		my ($ok, undef, $resref) = $self->cmdPrivExec($pkgsub, undef, ($self->config_context ? 'do ':'') . "terminal length $devMorePage->{cmdString}");
		return $self->poll_return($ok) unless $ok;
		return $self->poll_return($self->error("$pkgsub: Failed to set more-paging mode")) unless $$resref;
	}
	elsif ($familyType eq $Prm{slx}) {
		$devMorePage->{cmdString} = $devMorePage->{enable} ? 'no length' : 'length 0' unless defined $devMorePage->{cmdString};
		my ($ok, undef, $resref) = $self->cmdPrivExec($pkgsub, undef, ($self->config_context ? 'do ':'') . "terminal $devMorePage->{cmdString}");
		return $self->poll_return($ok) unless $ok;
		return $self->poll_return($self->error("$pkgsub: Failed to set more-paging mode")) unless $$resref;
	}
	elsif ($familyType eq $Prm{hive}) {
		$devMorePage->{cmdString} = $devMorePage->{enable} ? '22' : '0' unless defined $devMorePage->{cmdString};
		my ($ok, undef, $resref) = $self->poll_cmd($pkgsub, "console page $devMorePage->{cmdString}");
		return $self->poll_return($ok) unless $ok;
		return $self->poll_return($self->error("$pkgsub: Failed to set more-paging mode")) unless $$resref;
	}
	elsif ($familyType eq $Prm{eos}) {
		$devMorePage->{cmdString} = $devMorePage->{enable} ? '23' : '0' unless defined $devMorePage->{cmdString};
		my ($ok, undef, $resref) = $self->poll_cmd($pkgsub, "set length $devMorePage->{cmdString}");
		return $self->poll_return($ok) unless $ok;
		return $self->poll_return($self->error("$pkgsub: Failed to set more-paging mode")) unless $$resref;
	}
	elsif ($familyType eq $Prm{oneos}) {
		$devMorePage->{cmdString} = $devMorePage->{enable} ? '24' : '0' unless defined $devMorePage->{cmdString};
		my ($ok, undef, $resref) = $self->poll_cmd($pkgsub, "terminal length $devMorePage->{cmdString}");
		return $self->poll_return($ok) unless $ok;
		return $self->poll_return($self->error("$pkgsub: Failed to set more-paging mode")) unless $$resref;
	}
	else {
		return $self->poll_return($self->error("$pkgsub: Cannot configure more paging on family type $familyType"));
	}
	return $self->poll_return(1);
}


sub poll_device_peer_cpu { # Method to handle device_peer_cpu for poll methods (used for both blocking & non-blocking modes)
	my $self = shift;
	my $pkgsub = shift;
	my $pollsub = "${Package}::device_peer_cpu";

	unless ($self->{POLLING}) { # Sanity check
		my (undef, $fileName, $lineNumber) = caller;
		croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
	}

	unless (defined $self->{POLL}{$pollsub}) { # Only applicable if called from another method already in polling mode
		my @validArgs = ('username', 'password', 'prompt_credentials', 'timeout', 'errmode');
		my %args = parseMethodArgs($pkgsub, \@_, \@validArgs, 1);
		if (@_ && !%args) { # Legacy syntax
			($args{username}, $args{password}, $args{prompt_credentials}, $args{timeout}, $args{errmode}) = @_;
		}
		# In which case we need to setup the poll structure for them here (the main poll structure remains unchanged)
		$self->{POLL}{$pollsub} = { # Populate structure with method arguments/storage
			# Set method argument keys
			username		=>	defined $args{username} ? $args{username} : $self->username,
			password		=>	defined $args{password} ? $args{password} : $self->password,
			prompt_credentials	=>	defined $args{prompt_credentials} ? $args{prompt_credentials} : $self->{prompt_credentials},
			# Declare method storage keys which will be used
			stage			=>	0,
			# Declare keys to be set if method called from another polled method
			errmode			=>	$args{errmode},
		};
		# Cache poll structure keys which this method will use
		$self->poll_struct_cache($pollsub, $args{timeout});
	}
	my $devPeerCpu = $self->{POLL}{$pollsub};
	local $self->{errmode} = $devPeerCpu->{errmode} if defined $devPeerCpu->{errmode};
	return $self->poll_return($self->error("$pkgsub: No connection established")) if $self->eof;
	my $familyType = $self->{$Package}{ATTRIB}{'family_type'} || '';

	if ($devPeerCpu->{stage} < 1) { # 1st stage
		unless ($familyType) {
			return $self->poll_return($self->error("$pkgsub: Attribute family_type not set"));
		}
		unless ($familyType eq $Prm{pers}) {
			return $self->poll_return($self->error("$pkgsub: No peer CPU on family_type $familyType"));
		}
		unless (($devPeerCpu->{username} && $devPeerCpu->{password}) || $devPeerCpu->{prompt_credentials}) {
			return $self->poll_return($self->error("$pkgsub: Username & password required"));
		}
		$devPeerCpu->{stage}++; # Move to 2nd stage
	}

	if ($devPeerCpu->{stage} < 2) { # 2nd stage
		my $ok = $self->poll_enable($pkgsub); # If in nncli mode, need to be in PrivExec
		return $self->poll_return($ok) unless $ok;

		$self->print(line => 'peer telnet', errmode => 'return')
			or return $self->poll_return($self->error("$pkgsub: Unable to send peer telnet command // ".$self->errmsg));
		$devPeerCpu->{stage}++; # Move to 3rd stage
	}

	if ($devPeerCpu->{stage} < 3) { # 3rd stage
		my $ok = $self->poll_waitfor($pkgsub, 'Login: $', undef, 'return');
		return $self->poll_return($self->error("$pkgsub: Never got peer login prompt // ".$self->errmsg)) unless defined $ok;
		return $self->poll_return($ok) unless $ok;

		$devPeerCpu->{username} = promptCredential($devPeerCpu->{prompt_credentials}, 'Clear', 'Username') unless defined $devPeerCpu->{username};
		$self->print(line => $devPeerCpu->{username}, errmode => 'return')
			or return $self->poll_return($self->error("$pkgsub: Unable to send username // ".$self->errmsg));
		$devPeerCpu->{stage}++; # Move to 4th stage
	}

	if ($devPeerCpu->{stage} < 4) { # 4th stage
		my $ok = $self->poll_waitfor($pkgsub, 'Password: $', undef, 'return');
		return $self->poll_return($self->error("$pkgsub: Never got peer password prompt // ".$self->errmsg)) unless defined $ok;
		return $self->poll_return($ok) unless $ok;

		$devPeerCpu->{password} = promptCredential($devPeerCpu->{prompt_credentials}, 'Hide', 'Password') unless defined $devPeerCpu->{password};
		$self->print(line => $devPeerCpu->{password}, errmode => 'return')
			or return $self->poll_return($self->error("$pkgsub: Unable to send password // ".$self->errmsg));
		$devPeerCpu->{stage}++; # Move to last stage
	}

	# Use cmd() to expect a new prompt now
	my $ok = $self->poll_cmd($pkgsub, More_pages => 0, Reset_prompt => 1);
	return $self->poll_return($ok) unless $ok;

	$self->{LASTPROMPT} =~ /$InitPrompt{$self->{$Package}{PROMPTTYPE}}/;
	$self->_setAttrib('cpu_slot', $2);
	$self->_setAttrib('is_master_cpu', $self->{LASTPROMPT} =~ /^@/ ? 0 : 1);
	$self->_setAttrib('is_dual_cpu', 1) if $self->{LASTPROMPT} =~ /^@/;
	return $self->poll_return(1);
}


sub cmdPrivExec { # If nncli send command in PrivExec mode and restore mode on exit; if not nncli just sends command; used for show commands
	my ($self, $pkgsub, $cmdcli, $cmdnncli, $morePages) = @_;
	my $pollsub = "${Package}::cmdPrivExec";
	my ($ok, $outref, $resref);

	unless (defined $self->{POLL}{$pollsub}) { # Create polling structure on 1st call
		$self->{POLL}{$pollsub} = {
			stage		=>	0,
			userExec	=>	undef,
			outref		=>	undef,
			resref		=>	undef,
		};
	}
	my $cmdPrivExec = $self->{POLL}{$pollsub};
	my $familyType = $self->{$Package}{ATTRIB}{'family_type'} || '';

	if ($self->{$Package}{ATTRIB}{'is_nncli'}) {
		if ($cmdPrivExec->{stage} < 1) { # 1st stage
			if ($self->{WRITEFLAG}) { # Direct writes were performed, need a new prompt to be sure about last_prompt
				$ok = $self->poll_cmd($pkgsub, '');	# Send just carriage return
				return $ok unless $ok;
			}
			$cmdPrivExec->{stage}++; # Move to 2nd stage
		}
		if ($cmdPrivExec->{stage} < 2) { # 2nd stage
			if ($cmdPrivExec->{userExec} = $self->last_prompt =~ />\s?$/) {
				$ok = $self->poll_enable($pkgsub);
				return $ok unless $ok;
			}
			$cmdPrivExec->{stage}++; # Move to 3rd stage
		}
		if ($cmdPrivExec->{stage} < 3) { # 3rd stage
			($ok, $outref, $resref) = $self->poll_cmd($pkgsub, Command => $cmdnncli, More_pages => $morePages);
			return $ok unless $ok;
			$cmdPrivExec->{outref} = $outref;
			$cmdPrivExec->{resref} = $resref;
			$cmdPrivExec->{stage}++; # Move to 4th stage
		}
		if ($cmdPrivExec->{stage} < 4) { # 4th stage
			$cmdPrivExec->{stage}++; # Move to 5th stage - we only spend one cycle here
			if ($cmdPrivExec->{userExec}) {
				my $disableCmd;
				if (defined $ExitPrivExec{$familyType}) {

lib/Control/CLI/Extreme.pm  view on Meta::CPAN


On the stackable BaystackERS products the connect & login methods will automatically steer through the banner and menu interface (if seen) to reach the desired CLI interface.

=item *

There is no need to set the prompt string in any of this module's methods since it knows exactly what to expect from any of the supported Extreme products. Furthermore the prompt string is automatically internally set to match the actual prompt of th...

=item *

The connect method of this module automatically takes care of login for Telnet and Serial port access (where authentication is not part of the actual connection, unlike SSH) and so provides a consistent scripting approach whether the underlying conne...

=item *

Automatic handling of output paged with --more-- prompts, including the ability to retrieve an exact number of pages of output.

=item *

A number of attributes are made available to find out basic information about the connected Extreme device.

=item *

Ability to detect whether a CLI command generated an error on the remote host and ability to report success or failure of the issued command as well as the error message details.

=back

Note that all the extra functionality that this module offers over and above Control::CLI, is only possible if connected to an Extreme (or ex Avaya/Nortel) device. To make sure that the connected device is supported, the family_type attribute can be ...

In the syntax layout below, square brackets B<[]> represent optional parameters.
All Control::CLI::Extreme method arguments are case insensitive.




=head1 OBJECT CONSTRUCTOR

Used to create an object instance of Control::CLI::Extreme

=over 4

=item B<new()> - create a new Control::CLI::Extreme object

  $obj = new Control::CLI::Extreme ('TELNET'|'SSH'|'<COM_port_name>');

  $obj = new Control::CLI::Extreme (

  	# same as in Control::CLI :
  	Use			 => 'TELNET'|'SSH'|'<COM_port_name>',
  	[Timeout		 => $secs,]
  	[Connection_timeout	 => $secs,]
  	[Binmode		 => $binmode,]
  	[Errmode		 => $errmode,]
  	[Errmsg_format		 => $msgFormat,]
  	[Return_reference	 => $flag,]
  	[Prompt			 => $prompt,]
  	[Username_prompt	 => $usernamePrompt,]
  	[Password_prompt	 => $passwordPrompt,]
  	[Input_log		 => $fhOrFilename,]
  	[Output_log		 => $fhOrFilename,]
  	[Dump_log		 => $fhOrFilename,]
  	[Blocking		 => $flag,]
  	[Prompt_credentials	 => $flag,]
  	[Read_attempts		 => $numberOfReadAttemps,]
  	[Readwait_timer		 => $millisecs,]
  	[Data_with_error	 => $flag,]
  	[Read_block_size	 => $bytes,]
  	[Output_record_separator => $ors,]
  	[Terminal_type		 => $string,]
  	[Window_size		 => [$width, $height],]
  	[Report_query_status	 => $flag,]
  	[Debug			 => $debugFlag,]

  	# added in Control::CLI::Extreme :
  	[Return_result		 => $flag,]
  	[More_paging		 => $numberOfPages,]
  	[Cmd_confirm_prompt	 => $string,]
  	[Cmd_initiated_prompt	 => $string,]
  	[Cmd_feed_timeout	 => $value,]
  	[Console		 => $string,]
  	[Wake_console		 => $string,]
  	[Debug_file		 => $fhOrFilename,]
  );

This is the constructor for Control::CLI::Extreme objects. A new object is returned on success. On failure the error mode action defined by "errmode" argument is performed. If the "errmode" argument is not specified the default is to croak. See errmo...
The first parameter, or "use" argument, is required and should take value either "TELNET" or "SSH" (case insensitive) or the name of the Serial port such as "COM1" or "/dev/ttyS0". The other arguments are optional and are just shortcuts to methods of...
The Control::CLI::Extreme constructor accpets all arguments supported by the Control::CLI constructor (which are passed to it) and defines some new arguments specific to itself.

=back




=head1 OBJECT METHODS

Methods which can be run on a previously created Control::CLI::Extreme instance



=head2 Main I/O Object Methods

=over 4

=item B<connect() & connect_poll()> - connect to host

  $ok = $obj->connect("$host[ $port]");

  ($ok, $output || $outputRef) = $obj->connect("$host[ $port]");

  $ok = $obj->connect(
  	[Host			=> $host,]
  	[Port			=> $port,]
  	[Username		=> $username,]
  	[Password		=> $password,]
  	[PublicKey		=> $publicKey,]
  	[PrivateKey		=> $privateKey,]
  	[Passphrase		=> $passphrase,]
  	[Prompt_credentials	=> $flag,]
  	[BaudRate		=> $baudRate,]
  	[ForceBaud		=> $flag,]
  	[Parity			=> $parity,]
  	[DataBits		=> $dataBits,]
  	[StopBits		=> $stopBits,]
  	[Handshake		=> $handshake,]
  	[Timeout		=> $secs,]
  	[Connection_timeout	=> $secs,]
  	[Read_attempts		=> $numberOfLoginReadAttemps,]
  	[Data_with_error	=> $flag,]
  	[Wake_console		=> $string,]
  	[Blocking               => $flag,]
  	[Errmode		=> $errmode,]
  	[Terminal_type		=> $string,]
  	[Window_size		=> [$width, $height],]
  	[Callback		=> \&codeRef,]
  	[Atomic_connect		=> $flag,]
  	[Non_recognized_login	=> $flag,]
  	[Generic_login		=> $flag,]
  );

  ($ok, $output || $outputRef) = $obj->connect(
  	[Host			=> $host,]
  	[Port			=> $port,]
  	[Username		=> $username,]
  	[Password		=> $password,]
  	[PublicKey		=> $publicKey,]
  	[PrivateKey		=> $privateKey,]
  	[Passphrase		=> $passphrase,]
  	[Prompt_credentials	=> $flag,]
  	[BaudRate		=> $baudRate,]
  	[ForceBaud		=> $flag,]
  	[Parity			=> $parity,]
  	[DataBits		=> $dataBits,]
  	[StopBits		=> $stopBits,]
  	[Handshake		=> $handshake,]
  	[Timeout		=> $secs,]
  	[Connection_timeout	=> $secs,]
  	[Return_reference	=> $flag,]
  	[Read_attempts		=> $numberOfLoginReadAttemps,]
  	[Data_with_error	=> $flag,]
  	[Wake_console		=> $string,]
  	[Blocking               => $flag,]
  	[Errmode		=> $errmode,]
  	[Terminal_type		=> $string,]
  	[Window_size		=> [$width, $height],]
  	[Callback		=> \&codeRef,]
  	[Atomic_connect		=> $flag,]
  	[Non_recognized_login	=> $flag,]
  	[Generic_login		=> $flag,]
  );

Polling method (only applicable in non-blocking mode):

  $ok = $obj->connect_poll();

  ($ok, $output || $outputRef) = $obj->connect_poll();

This method connects to the host device. The connection will use either Telnet, SSH or Serial port, depending on how the object was created with the new() constructor.
On success a true (1) value is returned. On time-out or other connection failures the error mode action is performed. See errmode().
In the first & third forms only a success/failure value is returned in scalar context, while in the second & fourth forms, in list context, both the success/failure value is returned as well as any output received from the host device during the conn...

This method overrides Control::CLI::connect() and calls both the Control::CLI::connect() method as well as the login() method from this class. This allows the connect() method to seamlessly handle connection and login for both SSH (which normally han...

In non-blocking mode (blocking disabled) the connect() method will immediately return with a false, but defined, value of 0. You will then need to call the connect_poll() method at regular intervals until it returns a true (1) value indicating that t...

The "host" argument is required by both Telnet and SSH. All the other arguments are optional.
If username/password or SSH Passphrase are not provided but are required and prompt_credentials is true, the method will automatically prompt the user for them; otherwise the error mode action is performed. The "errmode" argument is provided to overr...
The "prompt_credentials" argument is provided to override the global setting of the parameter by the same name which is by default false. See prompt_credentials().
The "read_attempts" argument is simply fed to the login() method. See login().
The "connection_timeout" argument can be used to set a connection timeout when establishing Telnet and SSH TCP connections; this is fed to Control::CLI::connect(). Whereas the "timeout" argument is the normal timeout used for reading the connection o...
The "terminal_type" and "window_size" arguments are Control::CLI arguments and are not overrides, they will change the object parameter as these settings are only applied during a connection. It is not necessary to set these for Extreme devices.
Which other arguments are used depends on the whether the object was created for Telnet, SSH or Serial port. 

=over 4

=item *

For Telnet, these arguments are used:

  $ok = $obj->connect("$host[ $port]");

  $ok = $obj->connect(
  	Host			=> $host,
  	[Port			=> $port,]
  	[Username		=> $username,]
  	[Password		=> $password,]
  	[Prompt_credentials	=> $flag,]
  	[Timeout		=> $secs,]
  	[Connection_timeout	=> $secs,]
  	[Read_attempts		=> $numberOfLoginReadAttemps,]
  	[Data_with_error	=> $flag,]
  	[Wake_console		=> $string,]
  	[Blocking               => $flag,]
  	[Errmode		=> $errmode,]
  	[Terminal_type		=> $string,]
  	[Window_size		=> [$width, $height],]
  	[Atomic_connect		=> $flag,]
  	[Non_recognized_login	=> $flag,]
  	[Generic_login		=> $flag,]
  );

If not specified, the default port number for Telnet is 23. The wake_console argument is only relevant when connecting to a Telnet port other than 23 (i.e. to a Terminal Server device) or if console() has been manually set; see console(). In which ca...
Another reason to use the wake_console is when connecting via Telnet to an XOS switch which is configured with a 'before-login' banner which has to be acknowledged. In this case the XOS switch will not request a login until the user has hit a key. In...

=item *

For SSH, these arguments are used:

  $ok = $obj->connect("$host[ $port]");

  $ok = $obj->connect(
  	Host			=> $host,
  	[Port			=> $port,]
  	[Username		=> $username,]
  	[Password		=> $password,]
  	[PublicKey		=> $publicKey,]
  	[PrivateKey		=> $privateKey,]
  	[Passphrase		=> $passphrase,]
  	[Prompt_credentials	=> $flag,]
  	[Timeout		=> $secs,]
  	[Connection_timeout	=> $secs,]
  	[Read_attempts		=> $numberOfLoginReadAttemps,]
  	[Data_with_error	=> $flag,]
  	[Wake_console		=> $string,]
  	[Blocking               => $flag,]
  	[Errmode		=> $errmode,]
  	[Terminal_type		=> $string,]
  	[Window_size		=> [$width, $height],]
  	[Callback		=> \&codeRef,]
  	[Atomic_connect		=> $flag,]
  	[Non_recognized_login	=> $flag,]
  	[Generic_login		=> $flag,]
  );

If not specified, the default port number for SSH is 22. The wake_console argument is only relevant when connecting to a SSH port other than 22 (i.e. to a Terminal Server device) or if console() has been manually set; see console(). In which case, th...

A username must always be provided for all SSH connections. If not provided and prompt_credentials is true then this method will prompt for it.
Once the SSH conection is established, this method will attempt one of two possible authentication types, based on the accepted authentications of the remote host:

=over 4

=item *

B<Publickey authentication> : If the remote host accepts it and the method was supplied with public/private keys. The public/private keys need to be in OpenSSH format. If the private key is protected by a passphrase then this must also be provided or...

=item *

B<Password authentication> : If the remote host accepts either 'password' or 'keyboard-interactive' authentication methods. A password must be provided or, if prompt_credentials is true, this method will prompt for the password. If password authentic...

=back


=item *

For Serial port, these arguments are used:

  $ok = $obj->connect(
  	[BaudRate		=> $baudRate,]
  	[ForceBaud		=> $flag,]
  	[Parity			=> $parity,]
  	[DataBits		=> $dataBits,]
  	[StopBits		=> $stopBits,]
  	[Handshake		=> $handshake,]
  	[Username		=> $username,]
  	[Password		=> $password,]
  	[Prompt_credentials	=> $flag,]
  	[Timeout		=> $secs,]
  	[Read_attempts		=> $numberOfLoginReadAttemps,]
  	[Data_with_error	=> $flag,]
  	[Wake_console		=> $string,]
  	[Blocking		=> $flag,]
  	[Errmode		=> $errmode,]
  	[Non_recognized_login	=> $flag,]
  	[Generic_login		=> $flag,]
  );

If arguments "baudrate", "parity", "databits", "stopbits" and "handshake" are not specified, the defaults are: Baud Rate = 9600, Data Bits = 8, Parity = none, Stop Bits = 1, Handshake = none. These default values will work on all Extreme Networking p...
Allowed values for these arguments are the same allowed by Control::CLI::connect().

On Windows systems the underlying Win32::SerialPort module can have issues with some serial ports, and fail to set the desired baudrate (see bug report https://rt.cpan.org/Ticket/Display.html?id=120068); if hitting that problem (and no official Win32...

For a serial connection, this method - or to be precise the login() method which is called by connect() - will automatically send the wake_console string sequence to the attached device to alert it of the connection. The default sequence will work ac...

=back

If using the connect() method in non-blocking mode, the following example illustrates how this works:

	$ok = $obj->connect(Host => $ip-address, Blocking => 0);
	until ($ok) { # This loop will be executed while $ok = 0
		
		<do other stuff here..>
	
		$ok = $obj->connect_poll;
	}

Or, if you have set an error mode action of 'return':

	$ok = $obj->connect(Host => $ip-address, Blocking => 0, Errmode => 'return');
	die $obj->errmsg unless defined $ok;	# Error connecting
	until ($ok) { # This loop will be executed while $ok = 0
		
		<do other stuff here..>
	
		$ok = $obj->connect_poll;
		die $obj->errmsg unless defined $ok;	# Error or timeout connecting
	}


=item B<login() & login_poll()> - handle login for Telnet / Serial port; also set the host CLI prompt

  $ok = $obj->login(
  	[Username		=> $username,]
  	[Password		=> $password,]
  	[Prompt_credentials	=> $flag,]
  	[Timeout		=> $secs,]
  	[Read_attempts		=> $numberOfLoginReadAttemps,]
  	[Data_with_error	=> $flag,]
  	[Wake_console		=> $string,]
  	[Blocking		=> $flag,]
  	[Errmode		=> $errmode,]
  	[Non_recognized_login	=> $flag,]
  	[Generic_login		=> $flag,]
  );

  ($ok, $output || $outputRef) = $obj->login(
  	[Username		=> $username,]
  	[Password		=> $password,]
  	[Prompt_credentials	=> $flag,]
  	[Timeout		=> $secs,]
  	[Return_reference	=> $flag,]
  	[Read_attempts		=> $numberOfLoginReadAttemps,]
  	[Data_with_error	=> $flag,]
  	[Wake_console		=> $string,]
  	[Blocking		=> $flag,]
  	[Errmode		=> $errmode,]
  	[Non_recognized_login	=> $flag,]
  	[Generic_login		=> $flag,]
  );

Polling method (only applicable in non-blocking mode):

  $ok = $obj->login_poll();

  ($ok, $output || $outputRef) = $obj->login_poll();

This method handles login authentication for Telnet and Serial port access (also for SSH access in the case of the WLAN2300 WSS controllers, since they use no SSH authentication but instead use an interactive login once the SSH connection is establis...

On success the method returns a true (1) value. On failure the error mode action is performed. See errmode().
In non-blocking mode (blocking disabled) the login() method will most likely immediately return with a false, but defined, value of 0. You will then need to call the login_poll() method at regular intervals until it returns a true (1) value indicatin...
In the first form only a success/failure value is returned in scalar context, while in the second form, in list context, both the success/failure value is returned as well as any output received from the host device during the login sequence; the lat...
This method internally uses the readwait() method and by default sets the read_attemps for it to 10 (which is a safe value to ensure proper connection to any Extreme Networking device); the read_attempts argument provided by login() can be used to ov...

Once a valid Extreme Networking CLI prompt is detected (using pre-configured pattern match strings), this method records the actual CLI prompt of the host device for the remainder of the session by automatically invoking the prompt() method with a ne...
At the same time this method will also set the --more-- prompt used by the device when paging output as well as a number of attributes depending on what family_type was detected for the host device. See attribute().

Note that this method is automatically invoked by the connect() method and therefore should seldom need to be invoked by itself. A possible reason to invoke this method on its own could be if initially connecting to, say, an ERS8800 device and from t...

	# Initial connection could use Telnet or SSH, depending on how object was constructed
	# Connect to 1st device, e.g. via out-of-band mgmt
	$cli->connect(
		Host		=> '<ERS8800 IP address>',
		Username	=> 'rwa',
		Password	=> 'rwa',
	);
	# From there connect to another device, perhaps on inband mgmt
	# NOTE: use print() not cmd() as there is no prompt coming back, but the login screen of the stackable
	$cli->print("telnet <Stackable IP address>");
	# Call login() to authenticate, detect the device, reset appropriate attributes 
	$cli->login(
		Username	=> 'RW',
		Password	=> 'RW',
	);
	# Execute commands on target stackable device
	$output = $cli->cmd("show running-config");
	print $output;
	[...]
	# If you want to return to the first device..
	# NOTE: use print() not cmd() as the next prompt will be from the ERS8800, not the stackable anymore
	$cli->print("logout");
	# Call login() to detect the device and reset appropriate attributes (no authentication needed though)
	$cli->login;
	# Now we are back on the 1st device
	$output = $cli->cmd("show sys info");
	print $output;
	[...]


If using the login() method in non-blocking mode, the following examples illustrate how this works:

lib/Control/CLI/Extreme.pm  view on Meta::CPAN

=over 4

=item *

B<BaystackERS>: 9600, 19200, 38400 or 'max' (where 'max' = 38400)

=item *

B<PassportERS>: 9600, 19200, 38400, 57600, 115200 or 'max' (where 'max' = 115200)

=back

Follows an example:

	use Control::CLI;
	# Create the object instance for Serial port
	$cli = new Control::CLI('COM1');
	# Connect to switch
	$cli->connect(
			Baudrate 	=> 9600,
			Username	=> $username,
			Password	=> $password,
		);
	# Get the config
	$output = $cli->cmd(
			Command		=> "show running-config",
			Progress_dots	=> 100,
		);
	# Increase the baudrate
	$maxBaudrate = $cli->change_baudrate('max');
	print "Baudrate increased to $maxBaudrate" if $maxBaudrate;
	# Get the config a 2nd time (4 times faster on BaystackERS; 12 times faster PassportERS)
	$output = $cli->cmd(
			Command		=> "show running-config",
			Progress_dots	=> 100,
		);
	# Restore the baudrate
	$cli->change_baudrate(9600);
	# Disconnect
	$cli->disconnect;


In non-blocking mode (blocking disabled), the change_baudrate() method will most likely immediately return with a false, but defined, value of 0. You will then need to call the change_baudrate_poll() method at regular intervals until it returns a tru...

	($ok, $baudrate) = $obj->change_baudrate(BaudRate => $baudrate, Blocking => 0);
	until ($ok) {
		
		<do other stuff here..>
	
		($ok, $baudrate) = $obj->change_baudrate_poll;
	}
	print "New baudrate = ", $baudrate, "\n";


=item B<enable() & enable_poll()> - Enter PrivExec mode

  $ok = $obj->enable($enablePassword);

  $ok = $obj->enable(
  	[Password		=> $enablePassword,]
  	[Prompt_credentials	=> $flag,]
  	[Blocking		=> $flag,]
  	[Timeout		=> $secs,]
  	[Errmode		=> $errmode,]
  );

  $ok = $obj->enable_poll();	# Only applicable in non-blocking mode

This method checks whether the 'is_acli' attribute is set and, if so, whether the last prompt ends with '>'; if both conditions are true, it will flush any unread pending input from the device and will just send an 'enable' command to enter Priviledg...
The method can take a password argument which only applies to the WLAN2300 series and in some older software versions of the ERS-8300 in NNCLI mode.
If a password is required, but not supplied, this method will try supplying first a blank password, then the same password which was used to connect/login and finally, if prompt_credentials is true for the object, prompt for it. On I/O failure, the e...
The optional "prompt_credentials" argument is provided to override the global setting of the parameter by the same name which is by default false. See prompt_credentials().

In non-blocking mode (blocking disabled), the enable() method will most likely immediately return with a false, but defined, value of 0. You will then need to call the enable_poll() method at regular intervals until it returns a true (1) value indica...

	$ok = $obj->enable(Blocking => 0);
	until ($ok) {
		
		<do other stuff here..>
	
		$ok = $obj->enable_poll;
	}



=item B<device_more_paging() & device_more_paging_poll()> - Enable/Disable more paging on host device

  $ok = $obj->device_more_paging($flag);

  $ok = $obj->device_more_paging(
  	Enable			=> $flag,
  	[Blocking		=> $flag,]
  	[Timeout		=> $secs,]
  	[Errmode		=> $errmode,]
  );

  $ok = $obj->device_more_paging_poll();	# Only applicable in non-blocking mode

This method issues the necessary CLI commands to turn on/off --more-- paging on the connected device. It relies on the setting of family_type attribute - see attribute() - to send the appropriate commands.
If an error occurs while sending the necessary CLI commands, then the error mode action is performed. See errmode().
Returns a true value (1) on success.

In non-blocking mode (blocking disabled), the device_more_paging() method will most likely immediately return with a false, but defined, value of 0. You will then need to call the device_more_paging_poll() method at regular intervals until it returns...

	$ok = $obj->device_more_paging(Enable => 0, Blocking => 0);
	until ($ok) {
		
		<do other stuff here..>
	
		$ok = $obj->device_more_paging_poll;
	}


=item B<device_peer_cpu() & device_peer_cpu_poll()> - Connect to peer CPU on ERS8x00 / VSP9000

  $ok = $obj->device_peer_cpu(
  	[Username		=> $username,]
  	[Password		=> $password,]
  	[Prompt_credentials	=> $flag,]
  	[Blocking		=> $flag,]
  	[Timeout		=> $secs,]
  	[Errmode		=> $errmode,]
  );

  $ok = $obj->device_peer_cpu_poll();	# Only applicable in non-blocking mode

This method, only applicable on ERS8x00 and VSP9000, will try to connect to the peer CPU. On success a true (1) value is returned otherwise the error mode action is performed. See errmode().
It should not normally be necessary to provide username/password since the credentials used to connect to the current CPU will automatically be used. If not so, or to override the cached ones, optional "username" & "password" arguments can be provide...
Attributes 'cpu_slot' and 'is_master_cpu' are automatically updated once the connection to the peer CPU succeeds. See attribute().

In non-blocking mode (blocking disabled), the device_peer_cpu() method will most likely immediately return with a false, but defined, value of 0. You will then need to call the device_peer_cpu_poll() method at regular intervals until it returns a tru...

	$ok = $obj->device_peer_cpu(Blocking => 0);
	until ($ok) {
		
		<do other stuff here..>
	
		$ok = $obj->device_peer_cpu_poll;
	}


=back



=head2 Methods to set/read Object variables

=over 4

=item B<flush_credentials> - flush the stored username, password, passphrase and enable password credentials

  $obj->flush_credentials;

The connect(), login() and enable() methods, if successful in authenticating, will automatically store the username/password/enable-password or SSH passphrase supplied to them.
These can be retrieved via the username, password, passphrase and enable_password methods. If you do not want these to persist in memory once the authentication has completed, use this method to flush them. This method always returns 1.


=item B<prompt()> - set the CLI prompt match pattern for this object

  $string = $obj->prompt;

  $prev = $obj->prompt($string);

This method sets the CLI prompt match patterns for this object. In the first form the current pattern match string is returned. In the second form a new pattern match string is set and the previous setting returned.
If no prompt has yet been set (connection not yet established) undef is returned.
The object CLI prompt pattern is automatically set by the connect(), login() and cmd(reset_prompt => 1) methods and normally does not need to be set manually unless the CLI prompt is expected to change.
Once set, the object CLI prompt match pattern is only used by the cmd() and cmd_prompted() methods.


=item B<more_prompt()> - set the CLI --More-- prompt match pattern for this object

  $string = $obj->more_prompt;

  $prev = $obj->more_prompt($string [, $delayPrompt]);

This method sets the CLI --More-- prompt match patterns for this object. In the first form the current pattern match string is returned. In the second form a new pattern match string is set and the previous setting returned (the $delayPrompt can be s...
If no prompt has yet been set (connection not yet established) undef is returned.
The object's CLI --More-- prompt pattern is automatically set by the connect() and login() methods based upon the device type detected during login. Normally there should be no need to set this manually.
On family types which do not have any more prompt support (Ipanema) this will be automatically set to the empty string. 
Once set, the object CLI --More-- prompt match patterns is only used by the cmd() and cmd_prompted() methods.


=item B<more_paging()> - sets the number of pages to read when device output is paged by --more-- prompts

  $numberOfPages = $obj->more_paging;

  $prev = $obj->more_paging($numberOfPages);

When issuing CLI commands, using cmd() or cmd_prompted(), which generate large amount of output, the host device will automatically page the output with --more-- prompts where the user can either view the next page, by sending a Space character, or t...
This method sets the number of pages of output that both cmd() and cmd_prompted() will retrieve before sending a q character and thus terminating the CLI command. Hence if more_paging is set to 1, only one page of output will be collected and a q cha...
By default more_paging is set to 0, which means that the entire output of any issued command will be retrieved, by always feeding Space characters to every --more-- prompt encountered.
Note however that for best performance, if the entire output of a command is required, it is best to disable --more-- paging direcly on the host device rather than letting cmd() or cmd_prompted() feed a Space to every --more-- prompt encountered; see...
This setting can also be overridden directly in cmd() or cmd_prompted() using the 'more_pages' argument.
In the first form the current setting of more_paging is returned; in the second form a more_paging setting is configured and the previous setting returned.


=item B<progress_dots()> - configure activity dots for cmd() and cmd_prompted() methods

  $prevBytesPerDot = $obj->progress_dots($bytesPerDot);

With this method it is possible to enable cmd() - and cmd_prompted() - to print activity dots (....) as input data is read from the host device. This is useful if the command sent to the host device returns large amount of data (e.g. "show tech") and...
To enable the functionality set $bytesPerDot to a non zero value; this value will represent every how many bytes of input data read an activity dot will be printed. For example set a value of 1000.
To disable the functionality simply configure it with a zero value.
By default this functionality is disabled.


=item B<return_result()> - set whether cmd methods should return output or the success/failure of the command 

  $flag = $obj->return_result;

  $prev = $obj->return_result($flag);

lib/Control/CLI/Extreme.pm  view on Meta::CPAN

=item B<printlist()> - write multiple lines to object each with trailing output_record_separator

=item B<input_log()> - log all input sent to host

=item B<output_log()> - log all output received from host

=item B<dump_log()> - log hex and ascii for both input and output stream

=item B<eof> - end-of-file indicator

=item B<break> - send the break signal

=item B<close> - disconnect from host

=item B<poll> - poll object(s) for completion

=item B<debug()> - set debugging

=back


=head2 Error Handling Methods inherited from Control::CLI

=over 4

=item B<errmode()> - define action to be performed on error/timeout 

=item B<errmsg()> - last generated error message for the object 

=item B<errmsg_format()> - set the format to be used for object error messages 

=item B<error()> - perform the error mode action

=back


=head2 Methods to set/read Object variables inherited from Control::CLI

=over 4

=item B<timeout()> - set I/O time-out interval 

=item B<connection_timeout()> - set Telnet and SSH connection time-out interval 

=item B<read_block_size()> - set read_block_size for either SSH or Serial port 

=item B<blocking()> - set blocking mode for read methods and polling capable methods

=item B<read_attempts()> - set number of read attempts used in readwait() method

=item B<readwait_timer()> - set the polling timer used in readwait() method

=item B<data_with_error()> - set the readwait() method behaviour in case a read error occurs after some data was read

=item B<return_reference()> - set whether read methods should return a hard reference or not 

=item B<binmode()> - enable/disable newline translation

=item B<output_record_separator()> - set the Output Record Separator automatically appended by print & cmd methods (Note that unlike Control::CLI this class will default to "\r")

=item B<prompt_credentials()> - set whether connect() and login() methods should be able to prompt for credentials 

=item B<username_prompt()> - set the login() username prompt match pattern for this object

=item B<password_prompt()> - set the login() password prompt match pattern for this object

=item B<terminal_type()> - set the terminal type for the connection

=item B<window_size()> - set the terminal window size for the connection

=item B<report_query_status()> - set if read methods should automatically respond to Query Device Status escape sequences 

=back


=head2 Methods to access Object read-only variables inherited from Control::CLI

=over 4

=item B<parent> - return parent object

=item B<ssh_channel> - return ssh channel object

=item B<ssh_authentication> - return ssh authentication type performed

=item B<connection_type> - return connection type for object

=item B<host> - return the host for the connection

=item B<port> - return the TCP port / COM port for the connection

=item B<last_prompt> - returns the last CLI prompt received from host

=item B<username> - read username provided

=item B<password> - read password provided

=item B<passphrase> - read passphrase provided

=item B<handshake> - read handshake used by current serial connection

=item B<baudrate> - read baudrate used by current serial connection

=item B<parity> - read parity used by current serial connection

=item B<databits> - read databits used by current serial connection

=item B<stopbits> - read stopbits used by current serial connection

=back



=head2 Methods for modules sub-classing Control::CLI::Extreme inherited from Control::CLI

=over 4

=item B<poll_struct()> - sets up the polling data structure for non-blocking capable methods

=item B<poll_struct_cache()> - caches selected poll structure keys, if a nested polled method is called

=item B<poll_struct_restore()> - restores previously cached poll structure keys, if a nested polled method was called

=item B<poll_reset()> - resets poll structure

=item B<poll_return()> - return status and optional output while updating poll structure

=item B<poll_sleep()> - performs a sleep in blocking or non-blocking mode

=item B<poll_open_socket()> - opens TCP socket in blocking or non-blocking mode

=item B<poll_read()> - performs a non-blocking poll read and handles timeout in non-blocking polling mode

=item B<poll_readwait()> - performs a non-blocking poll readwait and handles timeout in non-blocking polling mode

=item B<poll_waitfor()> - performs a non-blocking poll for waitfor()

=back


=head2 Methods for modules sub-classing overridden from Control::CLI

=over 4

=item B<poll_connect()> - performs a non-blocking poll for connect()

=item B<poll_login()> - performs a non-blocking poll for login()

=item B<poll_cmd()> - performs a non-blocking poll for cmd()

=item B<poll_change_baudrate()> - performs a non-blocking poll for change_baudrate()

=item B<debugMsg()> - prints out a debug message

=back


=head2 Methods for modules sub-classing Control::CLI::Extreme

=over 4

=item B<poll_connect()> - performs a non-blocking poll for connect()

  $ok = $obj->poll_connect($pkgsub,
  	[Host                   => $host,]
  	[Port                   => $port,]
  	[Username               => $username,]
  	[Password               => $password,]
  	[PublicKey              => $publicKey,]
  	[PrivateKey             => $privateKey,]
  	[Passphrase             => $passphrase,]
  	[Prompt_credentials     => $flag,]
  	[BaudRate               => $baudRate,]
  	[Parity                 => $parity,]
  	[DataBits               => $dataBits,]
  	[StopBits               => $stopBits,]
  	[Handshake              => $handshake,]
  	[Login_Timeout          => $secs,]
  	[Connection_timeout     => $secs,]
  	[Read_attempts          => $numberOfLoginReadAttemps,]
  	[Data_with_error        => $flag,]
  	[Wake_console           => $string,]
  	[Errmode                => $errmode,]
  	[Terminal_type		=> $string,]
  	[Window_size		=> [$width, $height],]
  	[Non_recognized_login	=> $flag,]
  	[Generic_login		=> $flag,]
  );

  ($ok, $outputref) = $obj->poll_connect($pkgsub,
  	[Host                   => $host,]
  	[Port                   => $port,]
  	[Username               => $username,]
  	[Password               => $password,]
  	[PublicKey              => $publicKey,]
  	[PrivateKey             => $privateKey,]
  	[Passphrase             => $passphrase,]
  	[Prompt_credentials     => $flag,]
  	[BaudRate               => $baudRate,]
  	[Parity                 => $parity,]
  	[DataBits               => $dataBits,]
  	[StopBits               => $stopBits,]
  	[Handshake              => $handshake,]
  	[Login_Timeout          => $secs,]
  	[Connection_timeout     => $secs,]
  	[Read_attempts          => $numberOfLoginReadAttemps,]
  	[Data_with_error        => $flag,]
  	[Wake_console           => $string,]
  	[Errmode                => $errmode,]
  	[Terminal_type		=> $string,]
  	[Window_size		=> [$width, $height],]
  	[Non_recognized_login	=> $flag,]
  	[Generic_login		=> $flag,]
  );

Normally this is the internal method used by connect() and connect_poll() methods.
Arguments after $ok will only be defined if $ok is true(1).


=item B<poll_login()> - performs a non-blocking poll for login()

  $ok = $obj->poll_login($pkgsub,
  	[Username               => $username,]
  	[Password               => $password,]
  	[Prompt_credentials     => $flag,]
  	[Timeout                => $secs,]
  	[Read_attempts          => $numberOfLoginReadAttemps,]
  	[Data_with_error        => $flag,]
  	[Wake_console           => $string,]
  	[Errmode                => $errmode,]
  	[Non_recognized_login	=> $flag,]
  	[Generic_login		=> $flag,]
  );

  ($ok, $outputref) = $obj->poll_login($pkgsub,
  	[Username               => $username,]
  	[Password               => $password,]
  	[Prompt_credentials     => $flag,]
  	[Timeout                => $secs,]
  	[Read_attempts          => $numberOfLoginReadAttemps,]
  	[Data_with_error        => $flag,]
  	[Wake_console           => $string,]
  	[Errmode                => $errmode,]
  	[Non_recognized_login	=> $flag,]
  	[Generic_login		=> $flag,]
  );

Normally this is the internal method used by login() and login_poll() methods.
Arguments after $ok will only be defined if $ok is true(1).


=item B<poll_cmd()> - performs a non-blocking poll for cmd()

  $ok = $obj->poll_cmd($pkgsub, $cliCommand);

  $ok = $obj->poll_cmd($pkgsub,
  	[Command                => $cliCommand,]
  	[Feed_list              => \@arrayRef,]
  	[Prompt                 => $prompt,]
  	[Reset_prompt           => $flag,]
  	[More_prompt            => $morePrompt,]
  	[More_pages             => $numberOfPages,]
  	[Cmd_confirm_prompt     => $ynPrompt,]
  	[Cmd_initiated_prompt   => $cmdPrompt,]
  	[Timeout                => $secs,]
  	[Progress_dots          => $bytesPerDot,]
  	[Errmode                => $errmode,]
  );

  ($ok, $outputref[, $resultref]) = $obj->poll_cmd($pkgsub, $cliCommand);

  ($ok, $outputref[, $resultref]) = $obj->poll_cmd($pkgsub,
  	[Command                => $cliCommand,]
  	[Feed_list              => \@arrayRef,]
  	[Prompt                 => $prompt,]
  	[Reset_prompt           => $flag,]
  	[More_prompt            => $morePrompt,]
  	[More_pages             => $numberOfPages,]
  	[Cmd_confirm_prompt     => $ynPrompt,]
  	[Cmd_initiated_prompt   => $cmdPrompt,]
  	[Timeout                => $secs,]
  	[Progress_dots          => $bytesPerDot,]
  	[Errmode                => $errmode,]
  );

Normally this is the internal method used by cmd(), cmd_prompted() and cmd_poll() methods.
Arguments after $ok will only be defined if $ok is true(1).


=item B<poll_attribute()> - performs a non-blocking poll for attribute()

  $ok = $obj->poll_attribute($pkgsub, $attribute);

  $ok = $obj->poll_attribute($pkgsub,
  	[Attribute               => $attribute,]
  	[Reload                 => $flag,]
  	[Timeout                => $secs,]
  	[Errmode                => $errmode,]
  );

  ($ok, $valueref) = $obj->poll_attribute($pkgsub, $attribute);

  ($ok, $valueref) = $obj->poll_attribute($pkgsub,
  	[Attribute               => $attribute,]
  	[Reload                 => $flag,]
  	[Timeout                => $secs,]
  	[Errmode                => $errmode,]
  );

Normally this is the internal method used by attribute() and attribute_poll() methods.
Arguments after $ok will only be defined if $ok is true(1).


=item B<poll_change_baudrate()> - performs a non-blocking poll for change_baudrate()

  $ok = $obj->poll_change_baudrate($pkgsub, $baudrate);

  $ok = $obj->poll_change_baudrate($pkgsub,
  	[BaudRate               => $baudRate,]
  	[Timeout		=> $secs,]
  	[Errmode                => $errmode,]
  );

  ($ok, $baudrateref) = $obj->poll_change_baudrate($pkgsub, $baudrate);

  ($ok, $baudrateref) = $obj->poll_change_baudrate($pkgsub,
  	[BaudRate               => $baudRate,]
  	[Timeout		=> $secs,]
  	[Errmode                => $errmode,]
  );

Normally this is the internal method used by change_baudrate() and change_baudrate_poll() methods.
Arguments after $ok will only be defined if $ok is true(1).


=item B<poll_enable()> - performs a non-blocking poll for enable()

  $ok = $obj->poll_enable($pkgsub, $password);

  $ok = $obj->poll_enable($pkgsub,
  	[Password               => $enablePassword,]
  	[Prompt_credentials     => $flag,]
  	[Timeout                => $secs,]
  	[Errmode                => $errmode,]
  );

Normally this is the internal method used by enable() and enable_poll() methods.

=item B<poll_device_more_paging()> - performs a non-blocking poll for device_more_paging()

  $ok = $obj->poll_device_more_paging($pkgsub, $flag);

  $ok = $obj->poll_device_more_paging($pkgsub,
  	[Enable                 => $flag,]
  	[Timeout                => $secs,]
  	[Errmode                => $errmode,]
  );

Normally this is the internal method used by device_more_paging() and device_more_paging_poll() methods.


=item B<poll_device_peer_cpu()> - performs a non-blocking poll for device_peer_cpu()

  $ok = $obj->poll_device_peer_cpu($pkgsub,
  	[Username               => $username,]
  	[Password               => $password,]
  	[Prompt_credentials     => $flag,]
  	[Timeout                => $secs,]
  	[Errmode                => $errmode,]
  );

Normally this is the internal method used by device_peer_cpu() and device_peer_cpu_poll() methods.


=item B<cmdPrivExec()> - send a command requiring PrivExec mode

  ($ok, $outputref, $resultref) = $obj->cmdPrivExec($pkgsub, $cmdcli, $cmdnncli, $morePages);

If the connected device is in ACLI mode this method will enter PrivExec mode, if not already in that mode, and then send $cmdnncli; after sending the command, if PrivExec mode was enabled, then this method will disable it to leave the device in exact...
If instead the connected device is not in ACLI mode then it will simply send $cmdcli.
Arguments after $ok will only be defined if $ok is true(1).


=item B<cmdConfig()> - send a command requiring Config mode

  ($ok, $outputref, $resultref) = $obj->cmdConfig($pkgsub, $cmdcli, $cmdnncli);

If the connected device is in ACLI mode this method will enter PrivExec mode and then Config mode, if not already in that mode, and then send $cmdnncli; after sending the command, if PrivExec mode and/or Config mode were enabled, then this method wil...
If instead the connected device is not in ACLI mode then 'config ' is prepended to $cmdcli (if it is not already beginning with 'config ' string) and the resulting command is sent.
Arguments after $ok will only be defined if $ok is true(1).


=item B<cmdIpanema()> - send a command requiring not to be in virtual router context mode

  ($ok, $outputref, $resultref) = $obj->cmdIpanema($pkgsub, $cmdcli, $morePages);

This method is uniquely made for the Ipanema family type, which has a number of Linux shell contexts; if the connected Ipanema appliance was left in one of the WAN virtual router contexts, this method will exit that context and then send $cmdcli; aft...
Arguments after $ok will only be defined if $ok is true(1).


=item B<discoverDevice()> - discover the family type of connected device

  ($ok, $familyType) = $obj->discoverDevice($pkgsub);

This method will issue CLI commands to the attached device and based on the output received will determine what family type it belongs to.
Arguments after $ok will only be defined if $ok is true(1).


=item B<debugMsg()> - prints out a debug message

  $obj->debugMsg($msgLevel, $string1 [, $stringRef [,$string2]]);

A logical AND is performed between $msgLevel and the object debug level - see debug(); if the result is true, then the message is printed.
The message can be provided in 3 chunks: $string1 is always present, followed by an optional string reference (to dump large amout of data) and $string2.
If a debug file was set - see debug_file() - then the messages are printed to that file instead of STDOUT.


=back

The above methods are exposed so that sub classing modules can leverage the functionality within new methods themselves implementing polling.
These newer methods would have already set up a polling structure of their own.
When calling poll_login() directly for the 1st time, it will detect an already existing poll structure and add itself to it (as well as caching some of it's keys; see poll_struct_cache). It will also read in the arguments provided at this point.
On subsequent calls, the arguments provided are ignored and the method simply polls the progress of the current task.



=head1 CLASS METHODS inherited from Control::CLI



( run in 3.136 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )