Control-CLI-Extreme

 view release on metacpan or  search on metacpan

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

			($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});
			return $self->poll_return($ok) unless $ok; # Come out if error (if errmode='return'), or if nothing to read in non-blocking mode

			$self->debugMsg(8,"\nlogin() Connection input to process:\n>", \$self->{POLL}{read_buffer}, "<\n");
			$self->{POLL}{output_buffer} .= $self->{POLL}{read_buffer}; # This buffer preserves all the output, in case it is requested
			$self->{POLL}{local_buffer} = $self->{POLL}{read_buffer} =~ /\n/ ? '' : stripLastLine(\$self->{POLL}{local_buffer}); # Flush or keep lastline
			$self->{POLL}{local_buffer} .= $self->{POLL}{read_buffer};  # If read was single line, this buffer appends it to lastline from previous read

			# Pattern matching; try and detect patterns, and record their depth in the input stream
			$pattern = '';
			$deepest = -1;
			foreach my $key (keys %LoginPatterns) {
				if (($patdepth = rindex($self->{POLL}{read_buffer}, $LoginPatterns{$key})) >= 0) { # We have a match
					$self->debugMsg(8,"\nlogin() Matched pattern $key @ depth $patdepth\n");
					unless ($login->{family_type}) { # Only if family type not already detected
						# If a banner is seen, try and extract attributes from it also
						if ($key eq 'banner' || $key eq 'menu' || $key eq 'submenu') {
							$login->{family_type} = $Prm{bstk};
							$self->debugMsg(8,"login() Detected family_type = $login->{family_type}\n");
							$self->_setFamilyTypeAttrib($login->{family_type}, is_nncli => 1);
							if ($key eq 'banner') {
								$self->{POLL}{read_buffer} =~ /\*\*\* ((?:[^\*\n]+?) (?:Switch|Controller|Platform) (?:WC)?\d+.*?)\s+/ &&
									$self->_setModelAttrib($1);
								$self->{POLL}{read_buffer} =~ /FW:([\d\.]+)\s+SW:v([\d\.]+)/ && do {
									$self->_setAttrib('fw_version', $1);
									$self->_setAttrib('sw_version', $2);
								};
							}
						}
						elsif ($key eq 'srbanner') {
							$login->{family_type} = $Prm{sr};
							$self->debugMsg(8,"login() Detected family_type = $login->{family_type}\n");
							$self->_setFamilyTypeAttrib($login->{family_type}, is_nncli => 1);
							$self->{POLL}{read_buffer} =~ /\((Secure Router \d+)\)/ && $self->_setModelAttrib($1);
							$self->{POLL}{read_buffer} =~ /Version: (.+)/ && $self->_setAttrib('sw_version', $1);
						}
						elsif ($key eq 'xlrbanner') {
							$login->{family_type} = $Prm{xlr};
							$self->debugMsg(8,"login() Detected family_type = $login->{family_type}\n");
							$self->_setFamilyTypeAttrib($login->{family_type}, is_nncli => 0);
							$self->{POLL}{read_buffer} =~ /\* Software Release (?i:v|REL)?(.+?) / && $self->_setAttrib('sw_version', $1);
						}
						elsif ($key eq 'ersbanner' || $key eq 'passportbanner' || $key eq 'pp1600banner') {
							$login->{family_type} = $Prm{pers};
							$self->debugMsg(8,"login() Detected family_type = $login->{family_type}\n");
							$self->_setFamilyTypeAttrib($login->{family_type}, is_nncli => 0);
							$self->{POLL}{read_buffer} =~ /\* Software Release (?i:v|REL)?(.+?) / && $self->_setAttrib('sw_version', $1);
						}
						elsif ($key eq 'vspbanner' || $key eq 'fabengbanner') {
							$login->{family_type} = $Prm{pers};
							$self->debugMsg(8,"login() Detected family_type = $login->{family_type}\n");
							$self->_setFamilyTypeAttrib($login->{family_type}, is_nncli => 1);
							$self->{POLL}{read_buffer} =~ /(?:Software(?: Release)?|Fabric Engine) Build (.+?) / && $self->_setAttrib('sw_version', $1);



( run in 1.558 second using v1.01-cache-2.11-cpan-39bf76dae61 )