Getting Installed Software on Red Hat Servers Remotely

The other day I was asked to help get software installed on Red Hat servers. It would likely be easier with Satellite, maybe? I don’t know as I actually don’t like Red Hat.

Anyway, I wanted to do some Paramiko thing like I had done in the past but getting that installed in our environment is a pain and getting Paramiko installed manually is a bigger pain so I went the poor man’s route. It works, it uses stock Python libraries, and only requires Putty‘s PLINK utility, included with their awesome tools, that we are allowed to use in our shop. Oh yeah, this is fucking free and you own it.

This will likely work for any Linux distro, server or otherwise, as long as you can SSH to the box and give it the right command, right? Right. Apt, Yum, Pacman, or what ever. This is meant to run on Windows but changing the plink command to SSH would be just as easy on nix. Without further ado…

import os
from subprocess import Popen, PIPE

'''
plink is a Putty utility. Putty can be downloaded here:

https://www.putty.org/

C. Nichols, Feb. 2021
'''

userid = 'ssh_user'
passwd = 'ssh_passwd'

HOSTS = ['server1','server2']

putty = r'c:\Program Files (x86)\PuTTY\plink.exe'
command = '/bin/rpm -qa --qf "%{NAME},%{VERSION}-%{RELEASE},%{INSTALLTIME:date}~\n"'

output = r'c:\inventory'
log = r'c:\inventory\linux_inventory.log' %

with open(log, 'w') as logfile: # could use the logging lib.

    logfile.write('Name,Version,Installed\n')

    for host in HOSTS:
        try:

            #host = "%s %s@%s -i key.ppk" % (putty,userid,host)

            host_fingerprint = 'echo y | "{0}" -ssh -l "{1}" -pw "{2}" "{3}" "exit"'.format(putty,userid,passwd,host)
            host_cmd = '"{0}" -ssh -l "{1}" -pw "{2}" "{3}" {4}'.format(putty,userid,passwd,host,command)

            o,e = Popen(host_fingerprint, shell=True, stdout=PIPE, stderr=PIPE).communicate()

            proc = Popen(host_cmd, shell=True, stdout=PIPE, stderr=PIPE)

            out,err = proc.communicate()

            if e or err:
                error_line = '{0}\t{1}\t{2}\n'.format(host, str(e), str(err))
                logfile.write(error_line)

            raw = out.decode()
            sw_list = raw.split('~')

            output_file = os.path.join(output,'{0}.csv'.format(host))

            with open(output_file,'w') as stream:
                for line in sorted(sw_list):
                    stream.write('%s\n' % line)

        except Exception as perror:
            error_line = '{0}\t{1}\t{2}\t{3}\n'.format(host, str(e), str(err), str(perror))
            logfile.write(error_line)