0

I am learning Python and the Python script in my learning road is to run remote SSH commands The script itself runs fine, but it breaks when I want to experiment class inheritance feature.

Original Script pyssh.py:

#!/usr/bin/env python
import sys
import socket
import paramiko
#=================================
# Class: PySSH
#=================================
class PySSH:


    def __init__ (self):
        self.ssh = None
        self.transport = None  

    def disconnect (self):
        if self.transport is not None:
           self.transport.close()
        if self.ssh is not None:
           self.ssh.close()

    def connect(self,hostname,username,password,port=22):
        self.hostname = hostname
        self.username = username
        self.password = password

        self.ssh = paramiko.SSHClient()
        #Don't use host key auto add policy for production servers
        self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        self.ssh.load_system_host_keys()
        try:
            self.ssh.connect(hostname,port,username,password)
            self.transport=self.ssh.get_transport()
        except (socket.error,paramiko.AuthenticationException) as message:
            print "ERROR: SSH connection to "+self.hostname+" failed: " +str(message)
            sys.exit(1)
        return  self.transport is not None

    def runcmd(self,cmd,sudoenabled=False):
        if sudoenabled:
            fullcmd="echo " + self.password + " |   sudo -S -p '' " + cmd
        else:
            fullcmd=cmd
        if self.transport is None:
            return "ERROR: connection was not established"
        session=self.transport.open_session()
        session.set_combine_stderr(True)
        #print "fullcmd ==== "+fullcmd
        if sudoenabled:
            session.get_pty()
        session.exec_command(fullcmd)
        stdout = session.makefile('rb', -1)
        #print stdout.read()
        output=stdout.read()
        session.close()
        return output

#===========================================
# MAIN
#===========================================        
if __name__ == '__main__':
    hostname = 'server1'
    username = 'admin'
    password = 'Password123'
    ssh = PySSH()
    ssh.connect(hostname,username,password)
    output=ssh.runcmd('date')
    print output
    output=ssh.runcmd('service sshd status',True)
    print output
    ssh.disconnect()

now I want to test class inheritance by wring new script pyssh2.sh

#!/usr/bin/env python
from pyssh import PySSH
class PySSHT(PySSH):
    def connect(self,hostname):
        self.ssh = PySSH()
        self.username = 'admin'
        self.password = 'Password1'
        self.ssh.connect(hostname,self.username,self.password)

host = 'server1'
ssh = PySSHT()
ssh.connect(host)
output=ssh.runcmd('date')
print output
output=ssh.runcmd('service sshd status',True)
print output
ssh.disconnect()

It gave this error,It seems the value of self.transport assigned in ssh.connect() is lost in runcmd(). Is there something simple class inheritance rule I am missing?

[root@server  ~]# ./pyssh2.py
ERROR: connection was not established
ERROR: connection was not established
Traceback (most recent call last):
  File "./pyssh2.py", line 17, in <module>
    ssh.disconnect()
  File "/root/pyssh.py", line 19, in disconnect
    self.ssh.close()
AttributeError: PySSH instance has no attribute 'close
Cœur
  • 37,241
  • 25
  • 195
  • 267
honglus
  • 3
  • 1
  • In order to work you should change your last line `ssh.disconnect()` to `ssh.ssh.disconnect()`. – snahor Oct 30 '14 at 02:05

1 Answers1

0

Looks like your problem is here:

class PySSHT(PySSH):
    def connect(self,hostname):
        self.ssh = PySSH()   # <=== problem here?
        self.username = 'admin'
        self.password = 'Password1'
        self.ssh.connect(hostname,self.username,self.password)

In the first block of code you set self.ssh to a paramiko.SSHClient() in the second block (above) you set it to a PySSH

I assume that paramiko.SSHClient has a .close method. PySSH does not.

You shouldn't be setting self.ssh to PySSH I don't think. A better approach is something like this:

class PySSHT(PySSH):
   def connect(self, hostname):
       PySSH.connect(self, hostname = hostname, username = 'admin', password = 'Password1')
       return

Also you should read up on old style vs new style classes in Python. PySSH should probably get declared as:

class PySSH(object):
demented hedgehog
  • 7,007
  • 4
  • 42
  • 49
  • Thanks, it fixed the issue. It is basic in class inheritance, I shouldn't have created an instance – honglus Oct 30 '14 at 03:09
  • Good. Should also add that you can use super() to avoid referencing the base class explicitly. http://stackoverflow.com/questions/576169/understanding-python-super-and-init-methods – demented hedgehog Oct 30 '14 at 03:21
  • I will check that, Is there other room for improvement in the pyssh.py script? given it is my first python script – honglus Oct 30 '14 at 03:36
  • Other than the subclass weirdness it's pretty good. Excellent for a first python script I reckon. – demented hedgehog Oct 30 '14 at 03:59