Posted by & filed under Programming & Sysadmin.

wxPython lets you use python code on Windows, Mac or Linux to build GUI applications.

The example below uses wxPython to build a simple ssh application that sends a command and displays the response in the GUI. It uses Paramiko for the ssh bits.

Because this was built this on windows, using Python 2.7, and I wanted to generate a standalone exe file, there are some lines of source that are there to work around an issue with Paramiko + PyInstaller. Those lines can be removed if you are not targeting the windows platform using PyInstaller or py2exe, or if that issue is fixed by the time you read this.

If you run the below code, you should get something like this. Enter a hostname, username, password and a command, you should see the output from the command in the textctrl window when you press the “Go” button.

Clipboard01

Code:

import wx
import paramiko

# fix for problems with paramiko from
# https://github.com/pyinstaller/pyinstaller/issues/2013
from cryptography.hazmat import backends
try:
    from cryptography.hazmat.backends.commoncrypto.backend import backend as be_cc
except ImportError:
    be_cc = None
try:
    from cryptography.hazmat.backends.openssl.backend import backend as be_ossl
except ImportError:
    be_ossl = None
backends._available_backends_list = [
    be for be in (be_cc, be_ossl) if be is not None
    ]
# end fix
paramiko.util.log_to_file("transport_log.txt")
class SSHFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "SSHCMD")
        panel = wx.Panel(self)
        topLbl = wx.StaticText(panel, -1, "Connection Information")
        topLbl.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
        menuBar = wx.MenuBar()
        menu = wx.Menu()
        menu.Append(wx.ID_EXIT, "E&xit\tAlt-X", "Exit")
        self.Bind(wx.EVT_MENU, self.close, id=wx.ID_EXIT)
        menuBar.Append(menu, "&File")
        self.SetMenuBar(menuBar)
        hostLbl = wx.StaticText(panel, -1, "Host:")
        host = wx.TextCtrl(panel, -1, "");
        portLbl = wx.StaticText(panel, -1, "Port:")
        port = wx.TextCtrl(panel, -1, "22");
        usernameLbl = wx.StaticText(panel, -1, "Username:")
        username = wx.TextCtrl(panel, -1, "");
        passwordLbl = wx.StaticText(panel, -1, "Password:")
        password = wx.TextCtrl(panel, -1, "", style=wx.TE_PASSWORD);
        commandLbl = wx.StaticText(panel, -1, "Command:")
        command = wx.TextCtrl(panel, -1, "");
        output = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE|wx.EXPAND|wx.BORDER_SUNKEN|wx.TE_DONTWRAP,size=(500, 400))
        # works on linux
        # outputfont = wx.Font(10, wx.MODERN, wx.TELETYPE, wx.NORMAL, False,"")
        # works on windows
        outputfont = wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL, False, u'Consolas')
        output.SetFont(outputfont)
        self.command = command
        self.password = password
        self.username = username
        self.host = host
        self.port = port
        self.output = output
        goBtn = wx.Button(panel, -1, "Go")
        clearBtn = wx.Button(panel, -1, "Clear")
        mainSizer = wx.BoxSizer(wx.VERTICAL)
        mainSizer.Add(topLbl, 0, wx.ALL, 5)
        mainSizer.Add(wx.StaticLine(panel), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
        addrSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
        addrSizer.AddGrowableCol(1)
        addrSizer.Add(hostLbl, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
        addrSizer.Add(host, 0, wx.EXPAND)
        addrSizer.Add(portLbl, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
        addrSizer.Add(port, 0, wx.EXPAND)
        addrSizer.Add(usernameLbl, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
        addrSizer.Add(username, 0, wx.EXPAND)
        addrSizer.Add(passwordLbl, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
        addrSizer.Add(password, 0, wx.EXPAND)
        addrSizer.Add(commandLbl, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
        addrSizer.Add(command, 0, wx.EXPAND)
        mainSizer.Add(addrSizer, 0, wx.EXPAND|wx.ALL, 10)
        addrSizer.Add((10, 10))  # some empty space
        addrSizer.Add(output, 0, wx.EXPAND)
        addrSizer.Add((10, 10))  # some empty space
        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        btnSizer.Add((20,20), 1)
        btnSizer.Add(goBtn)
        btnSizer.Add((20,20), 1)
        btnSizer.Add(clearBtn)
        btnSizer.Add((20,20), 1)
        mainSizer.Add(btnSizer, 0, wx.EXPAND|wx.BOTTOM, 10)
        panel.SetSizer(mainSizer)
        mainSizer.Fit(self)
        mainSizer.SetSizeHints(self)
        goBtn.Bind(wx.EVT_BUTTON, self.inserttext)
        clearBtn.Bind(wx.EVT_BUTTON, self.clear)

    def clear(self, event):
        self.output.SetValue("")

    def inserttext(self, event):
        command = self.command.GetValue()
        host = self.host.GetValue()
        port = int(self.port.GetValue())
        username = self.username.GetValue()
        password = self.password.GetValue()
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.load_system_host_keys()
        try:
            ssh.connect(host, port=port, username=username, password=password)
            stdin, stdout, stderr = ssh.exec_command(command)
            for line in stdout.read().splitlines():
                self.output.AppendText(line + "\n")
            for line in stderr.read().splitlines():
                self.output.AppendText(line + "\n")
            stdin.close()
            stderr.close()
        except paramiko.AuthenticationException as error:
            self.output.AppendText(str(error)+'\n')
        except IOError as error:
            self.output.AppendText(str(error)+'\n')
        except:
            self.output.AppendText("Generic Fail\n")
        ssh.close()

    def close(self, evt):
        self.Close()

app = wx.App()
SSHFrame().Show()
app.MainLoop()