[python] Improving get_project_dirs method of SSHClient subclass

I noticed I did not have enough testing on my code for getting directories under base project directory.
This is part of the code snippet of my SSHClient subclass:

    def get_project_dirs(self, dirname: str = "/var/lib/awx/projects") -> Union[Dict[str, str], Dict[str, List]]:
        """
        To get a list of directories under the Ansible AWX base project directory.
        :param dirname:
            Project base directory. Ansible searches the yaml file from base directory.
        :return:
            dictionary of response.
        """
        try:
            # exec_command throws up a tuple(stdin, stdout, stderr)
            stdin, stdout, _ = self.exec_command(f"sudo ls -lah {dirname}", get_pty=True)
            stdin.write(self.password + "\n")
            stdin.flush()
            stdout_results = stdout.read().decode("utf-8")
            pbdirs = list()
            for d in stdout_results.splitlines()[3:]:  # Not interested in password, sudo prompt and total 0
                pbdirs.append(d.split()[-1])  # Only directory name.
            return {
                "status": "success",
                "playbook_dirs": pbdirs[2:] if len(pbdirs) > 2 else []  # not interested in . and ..
            }
        except CONN_EXCEPTION as CE:
            return {
                "status": "failed",
                "message": str(CE)
            }

The problem

The method gets all things under the base directory that is files and directories, that is because I have sliced and diced too much and inadvertently ignored the directory marking in linux hence whatever is inside the directory will be collected in my list.
Here is an example to illustrate on what I am talking about.
This is the content of the home directory of my CentOS server hosting Ansible AWX:
p10

This is the code to extract the contents of the defined base directory, my intention is to get the list of directories but apparently it collects files as well as directories.

from helper.linux import LinuxSSH
from getpass import getpass

username = input("Username: ")
password = getpass()

with LinuxSSH(username=username, password=password, hostname="192.168.100.174") as linux:
    response = linux.get_project_dirs(dirname="/home/cyruslab")
    print(response)

p11

Minor modification

So instead of getting anything excluding . and .. I put in check if “d” exist in the row[0] which is the first index of row after split().
This is the modified code to check the directory marking in order to collect just the directories.

    def get_project_dirs(self, dirname: str = "/var/lib/awx/projects") -> Union[Dict[str, str], Dict[str, List]]:
        """
        To get a list of directories under the Ansible AWX base project directory.
        :param dirname:
            Project base directory. Ansible searches the yaml file from base directory.
        :return:
            dictionary of response.
        """
        try:
            # exec_command throws up a tuple(stdin, stdout, stderr)
            stdin, stdout, _ = self.exec_command(f"sudo ls -lah {dirname}", get_pty=True)
            stdin.write(self.password + "\n")
            stdin.flush()
            stdout_results = stdout.read().decode("utf-8")
            pbdirs = list()
            for row in stdout_results.splitlines()[3:]:  # Not interested in password, sudo prompt and total 0
                # if "d" is found in the row
                if "d" in row.split()[0]: 
                    pbdirs.append(row.split()[-1])  # the directory name is in the last index of the row.
            return {
                "status": "success",
                "playbook_dirs": pbdirs[2:] if len(pbdirs) > 2 else []  # not interested in . and ..
            }
        except CONN_EXCEPTION as CE:
            return {
                "status": "failed",
                "message": str(CE)
            }

So to test it, I purposefully touch a file that has “d” in the filename.
p12

And running the same test code above I got these:
p13

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s