pythonpython-3.xzos

Is there a reason why paramiko.SSHClient -> exec_command cannot find an executable when invoke_shell -> send does?


I'm creating a python (3.13.5) program on my pc that connects to our mainframe and runs a python (3.12.8) program from our z/os uss environment.

I can successfully connect using this code here:

remote_script_path = '/u/h39808'
script = 'helloworld.py'
try:
    with paramiko.SSHClient() as client:
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect(host_address,
                       username=username_entry.get(), 
                       password=passowrd_entry.get())

And when I use the following invoke_shell method to run my python program remotely, it does so fine:

shell = client.invoke_shell()
shell.send(f"python {remote_script_path}/{script}\n")

But since all I am doing is executing one program at any time and waiting for a response, I'd like to do this with exec_command; problem is, when I use the following:

**stdin, stdout, stderr = client.exec_command(f"python {remote_script_path}/{script}")
print(stderr.read().decode())**

It returns - python: FSUM7351 not found

And let's say I try using a command to go to the remote path and list the contents:

stdin, stdout, stderr = client.exec_command(f"cd {remote_script_path}; ls -l")

This comes back, which is what I am expecting: -rwxrwxr-x 1 BPXROOT 99999999 59 Jun 24 14:28 helloworld.py

Could this be due to a security restriction, or something else off with our uss environment, or is it my code that is to blame?


Solution

  • The error:

    python: FSUM7351 not found
    

    means that the shell cannot find the python command. This typically happens when:

    1. The PATH variable isn't set properly in non-interactive shells (like the one used by exec_command).

    2. exec_command doesn’t invoke a full login shell, so it may skip profile scripts like .profile, .bash_profile, or .bashrc (depending on shell type).

    On USS (z/OS UNIX System Services), the profile that sets up Python paths may only be loaded in interactive shells, which is why your invoke_shell() works but exec_command() doesn’t.

    Solution:

    Use the full path to Python

    Find out the absolute path to Python on USS by running:

    which python
    

    from your working interactive shell (invoke_shell). You might get something like:

    /usr/lpp/python3/bin/python
    

    Then change:

    stdin, stdout, stderr = client.exec_command(f"python {remote_script_path}/{script}")
    

    to:

    stdin, stdout, stderr = client.exec_command(f"/usr/lpp/python3/bin/python {remote_script_path}/{script}")
    

    This is the simplest and most robust solution.