Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Console Server Login via Console Port #909

Closed
bgile opened this issue Aug 9, 2018 · 15 comments
Closed

Console Server Login via Console Port #909

bgile opened this issue Aug 9, 2018 · 15 comments

Comments

@bgile
Copy link

bgile commented Aug 9, 2018

Hello

I have been looking all over with no luck as to whether I can telnet to a console server with a specific port so I can access devices in my lab. I have noticed there is a terminalserver driver, but I couldn't find much on it. I also saw in BaseConnection there is some serial_settings, but the 'read the docs' page didn't have any info on it. What I am looking to do is this:

telnet exmaple.com 2121 -- where 2121 is the port on the console server I need to access

Anything you can point me to would be appreciated.

@ktbyers
Copy link
Owner

ktbyers commented Aug 23, 2018

Use a device_type='generic_termserver_telnet' and port=2121 in your ConnectHandler arguments.

@bgile
Copy link
Author

bgile commented Aug 24, 2018

Thanks for the update. Added that into my code but my command is returning None.

When logging into my console server, once you are in you then need to enter in another set of admin and password for the juniper device.

Here is the code I am using:

def console_connect (host, username, password, admin_pass):
    '''Make connection to the console server on a particular port'''
    console = {
            'device_type': 'generic_termserver_telnet',
            'ip': host,
            'username': username,
            'password': password,
            'port': '2002'
        }
    net_connect = ConnectHandler(**console)
    print("LOGIN Successful **\n")
    net_connect.write_channel('\r')
    time.sleep(1)
    net_connect.write_channel('\r')
    time.sleep(1)
    print("Entering in the admin username **\n")
    net_connect.write_channel('admin' + '\n')
    print("Entering in the admin password **\n")
    net_connect.write_channel(admin_pass + '\n')
    output = net_connect.write_channel('show version' + '\n')

    print(output)

def main ():
    username = input("what is the username to the console server? --> ")
    password = getpass("What is the password to the console server? -->")
    admin_pass = getpass("what is the admin password --> ")
    console_connect('198.27.200.30', username, password, admin_pass)

if __name__ == "__main__":
        main()

@ktbyers
Copy link
Owner

ktbyers commented Aug 24, 2018

Yes, you won't be able to do that:

    output = net_connect.write_channel('show version' + '\n')
    print(output)

You are not reading anything back from the device. Your output there is from the output of write_channel. Also you really shouldn't be using write_channel/read_channel for anything beyond handling the login process.

What type of device is this that you are logging into on port 2002 (i.e. what vendor + platform)?

@bgile
Copy link
Author

bgile commented Aug 24, 2018

Normally I would use send_command, but there was always exception issues.

I apologize that I am not understanding how this is suppose to work when using this specific device_type.
After the device connection, should I be able to switch over to using send_command to pass the admin and admin_pass?

The specific device that I am telneting to is a opengear console server. From there, port 2002 connects to a juniper device

@ktbyers
Copy link
Owner

ktbyers commented Aug 24, 2018

@bgile So assuming that I am understanding correctly what you are doing. I would try this:

  1. Add a session_log so you can see better what is happening.
    console = {
            'device_type': 'generic_termserver_telnet',
            'ip': host,
            'username': username,
            'password': password,
            'port': '2002',
            'session_log': 'output_file.txt',
        }
  1. Change this:
    output = net_connect.write_channel('show version' + '\n')
    print(output)

To this (to see where we are at)

    output = net_connect.find_prompt()
    print(output)

You should then be able to look at both the session_log and what find_prompt gets you back to get a better understanding of where in the process you are getting to.

@bgile
Copy link
Author

bgile commented Aug 24, 2018

Kirk

For reference here is the standard readout when logging into the console server via normal telnet:

telnet console.snrtcalb 2002
Trying 198.27.200.30...
Connected to console.snrtcalb.
Escape character is '^]'.
login: xxxx
CONSOLE.SNRTCALB Welcome to the sandbox
Password:

When using the adjustment to find the prompt I get:

CONSOLE.SNRTCALB Welcome to the sandbox

I added in a global_delay_factor and it seems to not help. I am not certain but it seems the initial username and password from the device_type definition is being sent before its even seen. I say this because the outfile is passing in the second set of passwords that should be for the Juniper device once the telnet login to the console server establishes.

The outfile reads:

login:
admin
XXXXXX
CONSOLE.SNRTCALB Welcome to the sandbox

@bgile
Copy link
Author

bgile commented Aug 27, 2018

@ktbyers

Not sure if it would be better to call std_login directly? I tried myself with no luck but maybe it can be used differently?

class TerminalServerTelnet(TerminalServer):
    """Generic Terminal Server driver telnet."""
    def telnet_login(self, *args, **kwargs):
        # Disable automatic handling of username and password when using terminal server driver
        pass

    def std_login(self, *args, **kwargs):
        return super(TerminalServerTelnet, self).telnet_login(*args, **kwargs)

It really seems like the first function is hitting "pass" for the ConnectHandler object username and password and then the function telnet_login happens, and it tries to use my secondary username and password for the Juniper device instead based on the outputfile. Thoughts?

Update:
pexpect works pretty decent. I decided to test telnetlib itself and was also having connect issues. Unless you can think of something that is adjustable with netmiko I may just opt for pexpect to perform the telnet console action and then use netmiko once I have IP connectivity configured.

@ktbyers
Copy link
Owner

ktbyers commented Aug 29, 2018

Yes, usually I will step through the login process...step-by-step. By this I will use writes and reads to make sure I am getting the 'login' request, and the 'Password' request and sending the right information at the right time.

A lot of times I couple this with loops (i.e. the timing can get out sync so loops can help to make sure you only move on if you are in the right state).

You very likely need to sleep between these two actions as your program will be faster than the network device:

    print("Entering in the admin username **\n")
    net_connect.write_channel('admin' + '\n')
    print("Entering in the admin password **\n")
    net_connect.write_channel(admin_pass + '\n')

You can try to call the telnet_login(), but you would have to do a few things to call it.

Here is the telnet_login signature (in cisco_bas

    def telnet_login(self, pri_prompt_terminator=r'#\s*$', alt_prompt_terminator=r'>\s*$',
                     username_pattern=r"(?:user:|username|login|user name)", pwd_pattern=r"assword",
                     delay_factor=1, max_loops=20):

Note, the std_login and telnet_login are disabled in the terminal_server driver class itself (as terminal servers have a huge variety in the login process). So you would need to call the parent class...I can show you how to do this (if you are still working on it).

@bgile
Copy link
Author

bgile commented Aug 29, 2018

I'm still interested in making this work with Netmiko. I can try some loops to match on read output, it's not a bad idea. I'm still a little puzzled why in the session logging I never see the username and password from the device_type dictionary entered in.

I'll try out calling the parent class if you want, I'm open to anything.

Thanks,

@ktbyers
Copy link
Owner

ktbyers commented Aug 29, 2018

@bgile This is quick so you might have to make modifications to it...but see where this gets you.

    net_connect = ConnectHandler(**console)
    print("LOGIN Successful **\n")

    net_connect.write_channel('\r')
    time.sleep(1)
    net_connect.write_channel('\r')
    time.sleep(1)

    output = net_connect.read_channel()
    if 'login' not in output:
        raise ValueError("login not found")

    print("Entering in the admin username **\n")
    net_connect.write_channel('admin' + '\n')
    time.sleep(2)

    output = net_connect.read_channel()
    if 'Password' not in output:
        raise ValueError("password prompt not found")

    print("Entering in the admin password **\n")
    net_connect.write_channel(admin_pass + '\n')

    net_connect.write_channel('\n')
    time.sleep(1)
    output = net_connect.read_channel()
    print("Current status")
    print(output)

@bgile
Copy link
Author

bgile commented Aug 30, 2018

@ktbyers

So I have narrowed this down to a terminal issue. I never got past the first conditional as I suspected was the case so decided to tcpdump the session and upon looking at the TELNET data I see this from my machine: Won't Terminal Type etc..

This I believe is linked to telnetlib, which kind of explains why I couldn't get telnetlib to work on its own when I was testing without netmiko. If I look at telnetlib interaction, the console server sets up the terminal definitions like you would expect, but telnetlib is responding "Won't" to all of them.

If I look at a tcpdump of pexpect, the same terminal requests come from the console server, but in this instance, all the parameters are replied with a "Will" which completes the connection.

I am not certain why telnetlib is sending a Won't in this case. I don't see anything that can be adjusted in the lib.

Any thoughts?

@cgruelle
Copy link

cgruelle commented Aug 30, 2018 via email

@ktbyers
Copy link
Owner

ktbyers commented Aug 30, 2018

@cgruelle Can you link to your code that you were using for that? I think that might help @bgile.

@bgile
Copy link
Author

bgile commented Aug 31, 2018

Ok this gives me something to mess around with. Plenty of other people experiencing the same issue and using the callback function so I have some more examples to look at to make this work. I'm not looking to do any class work in this script, trying to keep it really simple since its just for ansible to use for a quick initial login and IP config for an interface so I can get IP reachability.

Thanks I feel we are good to close this issue @ktbyers Hopefully if anyone experiences this issue this thread will help.

@bgile bgile closed this as completed Aug 31, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants