Search code examples
pythonlinuxsshsubprocessparamiko

Python script stdout is empty while trying to recover logs from remote device


I'm trying to recover logs from a remote LB, the script should:

Connect to the LB -> Execute a command -> Check if the stdout is not none -> If it is, update a web page with ALL_GOO -> If there are persistent sessions it should update the web page with NOT_GOOD and send an email with the script output as attachment -> It should then update the file statusEmail with the date of the sent email (this to avoid sending multiple email per day).

When I execute the script I have an empty return: []

% ./lb-logs.py  
SSH connection established successfully.
[]
Command executed.

This is the main script:

#! /usr/bin/env python3

import logging
import os
from src.utils import run_command, get_results
from datetime import datetime

lbUser = "lb_user"
lbIp = "lb_ip"
lbPass = "lb_pass"
attachment = "p-sessions.txt"
date = datetime.now().strftime("%d/%m/%Y")
mailList = "mail_list"

logging.basicConfig(
    filename="logs.log",
    encoding="utf-8",
    level=logging.DEBUG,
    format="%(asctime)s:%(levelname)s:%(message)s",
)

result = get_results(lbIp, lbUser, lbPass)

status = 'UNKNOWN'

if result:
    run_command(
        "sudo sed -i 's/^<h1>.*/<h1>NOT_GOOD-TEST<\/h1>/' /var/www/html/index1.html"
    )
    status = "NOT_GOOD"
    logging.info(f"Status: {status}")
else:
    run_command(
        "sudo sed -i 's/^<h1>.*/<h1>ALL_GOOD-TEST<\/h1>/' /var/www/html/index1.html"
    )
    status = "ALL_GOOD"
    logging.info(f"Status: {status}")

if status == "NOT_GOOD":
    if os.path.exists(attachment):
        logging.info(f"File {attachment} exists.")
        print("File exists.")
    else:
        # Send email if date in statusEmail is different from today's date
        with open("src/statusEmail", "r") as statusEmailFileHandle:
            if date == statusEmailFileHandle.read():
                logging.info("Email already sent.")
            else:
                # Create file
                for line in result:
                    print(line)
                    with open(attachment, "a") as attachmentFileHandle:
                        attachmentFileHandle.write(line + "\n")
                logging.info(f"File {attachment} created.")

                result1 = run_command(
                    f"echo 'Generated from vm: ' | mailx -r 'vm' 'mail_relay' -s 'Persistent sessions found on LB - {date}' -t {mailList} -A {attachment}"
                )

                print(result1)

                with open("src/statusEmail", "w") as f:
                    f.write(f"NOT_GOOD: {date}")
                logging.info("Email sent.")

And this is the utils.py:

import paramiko
import subprocess
import logging


def connect(lb_ip, lb_user, lb_passwd):
    try:
        _ssh = paramiko.SSHClient()
        _ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        _ssh.load_system_host_keys()
        _ssh.connect(hostname=lb_ip, username=lb_user, password=lb_passwd)
        return _ssh
        print(_ssh)
    except Exception as exceptHandler:
        logging.error(f"Failed to connect to {ip}: {exceptHandler}")
        raise


def run_command(command):
    _process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
    _output, _error = _process.communicate()
    print(_output.decode())
    return _output.decode().strip()


def get_results(lb_ip, lb_user, lb_pass):
    conn = connect(lb_ip, lb_user, lb_pass)
    if conn is not None:
        print("SSH connection established successfully.")
        stdin, stderr, stdout = conn.exec_command(
            'shell nsconmsg -K /var/nslog/newnslog -g dht_ns_tot_max_limit_exceeds -d current -s disptime=1 | grep dht_ns_tot_max_limit_exceeds'
        )
        print(stdin, stdout, stderr)
        logging.info(f"stdin={stdin}, stdout={stdout}, stderr={stderr}")
        conn.close()
        return stdout.readlines()
    else:
        print("Failed to establish SSH connection.")
        return None

I've already added checks in all the funtions to make sure that the SSH connections is established, the command executed on the remote LB and yet, the stdout is empty.

I should receive the list of persistent sessions (the output of the command).


Solution

  • I solved the issued this way, adding the stdout to the variable result, this way it is saved as a variable.

    Basically, before I was reading it (so consuming his stream) and then try to read it once again, and of course it was empty.

    def get_results(lb_ip, lb_user, lb_pass):
        conn = connect(lb_ip, lb_user, lb_pass)
        if conn is not None:
            logging.info("SSH connection established successfully.")
            stdin, stdout, stderr = conn.exec_command(
                'shell nsconmsg -K /var/nslog/newnslog -g dht_ns_tot_max_limit_exceeds -d current -s disptime=1 | grep dht_ns_tot_max_limit_exceeds'
            )
            result = stdout.read().decode('utf-8')
            logging.info(f"stdout={result}, stderr={stderr.read()}")
            conn.close()
            return result
        else:
            logging.error("Failed to establish SSH connection.")
            return None