Hi all,
I’m looking at building a module to talk to an HP Switch (1910). This switch only has a web UI (not REST nor SOAP) and ssh. I have scoured the Internet and only found info about devices that have nice REST APIs. I have tried to connect to it but get this error:
-
debug3: fd 0 is not O_NONBLOCK
-
debug3: fd 1 is not O_NONBLOCK
-
debug1: fd 2 clearing O_NONBLOCK
-
Connection to 192.168.1.14 closed by remote host.
-
Transferred: sent 2992, received 1864 bytes, in 0.1 seconds
-
Bytes per second: sent 23622.3, received 14716.6
-
debug1: Exit status -1
-
debug3: mux_client_read_packet: read header failed: Broken pipe
-
debug2: Control master terminated unexpectedly
-
Shared connection to 192.168.1.14 closed.
-
:
-
-
- Copyright (c) 2010-2013 Hewlett-Packard Development Company, L.P. *
-
- Without the owner’s prior written consent, *
-
- no decompiling or reverse-engineering shall be allowed. *
-
-
-
^
-
% Unrecognized command found at ‘^’ position.
-
If I dig into the code, the problem occurs in the _communicate method of Connection in ssh.py, p.returncode has a value of 255. Has anyone here created an SSH connection plugin or found a way to get the default one to deal nicely with a device like this?
Regards,
Patrick
Just trying to get the raw module to work I assume?
(The others definitely will not…)
Thanks for the suggestion, though I did try that idea and it still failed the same. It’s not even at the point I try to run any commands - it’s just logging into the switch that doesn’t work. If I do a simple ping of the device, that even fails. It does seem to log in since I get a prompt (which is simply legalese message and then a “”. I suspect its because when you log into the switch, it’s not a regular posix shell that accepts regular commands as well if I wish to do any work and not be driven crazy, I have to set the delete character for a backspace because otherwise, you have to use ^H. The question is - is there any setting of a term I need to do?
It may work in raw mode if your switch allows configuration of a shell, otherwise it’s probably not going to work.
You could make an action plugin that spoke to your “SSH-ish” API using paramiko, though it may be a bit “interesting” of an exercise.
So, a little more digging in code, experimenting - it has to do with _send_password(), which looks completely correct. All it does is:
os.write(self.wfd, “%s\n” % self.password)
I verified, and it does exactly what it should but for some reason, the message, which I’ve realized is from the switch "% Unrecognized command found at ‘^’ position” seems to be indicating something in addition to the password is being sent.
I think what I’ll need to do is whittle it down to a very simply piece of ssh code using paramiko, get that to connect, then fit it in as a connection plugin. It’s something probably insanely simple but I cannot de-couple it from other complexity
It is something sent to the switch after the password is sent. There is this code in ssh.py which looks perfectly simple, and I’m not sure if there is anything at all that would show up on the switch as a character when it runs-- note - if I type “?” at the switch prompt, it acts as a return character or as if getchar() is running, so …
while True:
rfd, wfd, efd = select.select(rpipes, , rpipes, 1)
if p.stdout in rfd:
dat = os.read(p.stdout.fileno(), 9000)
stdout += dat
if dat == ‘’:
rpipes.remove(p.stdout)
if p.stderr in rfd:
dat = os.read(p.stderr.fileno(), 9000)
stderr += dat
if dat == ‘’:
rpipes.remove(p.stderr)
Obviously, this is where genuine useful output as well as errors are read… Is there any way that something is sent over to the switch? Not that I see. I suppose I could tcpdump it and see what’s being passed.
Thanks for the suggestions, I really do appreciate the help.
–Patrick
I meant to say, that code is in _communicate()
Hi!
So, indeed, after much finagling, with paramiko (thank you for the suggestion!), I can connect to the switch, using “allow_agent=false” to make that part work. I think a big thing that was hanging me up also is the pagination on the router. That’s another bit I need to figure out as I can’t perform nice loops over the output of a command such as “summary”, where it stops after a certain number of lines.
Is there any part of ansible that deals with this?
Regards,
Patrick
Hi!
So, Paramiko was definitely it. I did a LOT of trial and error, looking at the code in paramiko-expect, etc. This is what I have that works- yes, it is crufty, but it works and I can go from here:
#!/usr/bin/env python
import re
import paramiko
prompt = '<HP>'
more_tag = ' ---- More ----'
cmd_line_mode = "_cmdline-mode on\n"
cmd_line_mode_resp = "Y\n512900\n"
summary_start = "Select menu option: Summary"
paramiko.util.log_to_file('/tmp/paramiko.log')
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('1.2.3.4',
username='goes',
password='toeleven',
allow_agent=False,
look_for_keys=False)
channel = ssh.invoke_shell()
channel.send(cmd_line_mode)
channel.send(cmd_line_mode_resp)
channel.send("summary\n")
output = ''
second_page = False
append_flag = False
while True:
str_buf = channel.recv(1024)
str_buf = str_buf.replace('/r', '')
if summary_start in str_buf:
append_flag = True
# need to hit space - second page of summary
if re.match('.*' + more_tag + '$', str_buf, re.DOTALL):
channel.send(' ')
str_buf = channel.recv(1024)
# what does this mean? It means we did all the other steps that are
# needed and are on the second page from the command "summary"
second_page = True
#if "<HP>" in str_buf and output_active is False:
if re.match('.*\n' + prompt + '$', str_buf, re.DOTALL) and second_page:
break
# only append what I am interested in
if append_flag:
output += str_buf
print output
“That’s another bit I need to figure out as I can’t perform nice loops over the output of a command such as “summary”, where it stops after a certain number of lines.”
If you’re doing this within what I assume is an ansible module using paramiko, this would be something your Python code would take care of.
If this is more like “my module returned 57 lines of output and I want to do something with the first 25”, that sounds like it would be a custom lookup plugin, but there are things like “with_items: command.stdout_lines” for the command module, and if you returned the lines in the array could do similar, and maybe control how many with a Jinja2 filter?