Idea ID: 2871394

Attribute "unix_servicepack" is not discovered - only minor change in Script TTY_Connection_Utils.py is necessary

Status : New Idea

Current situation
HC by Shell Discovery parses the file /etc/os-release to determine the servicepack of the OS. See below snippet from TTY_Connection_Utils.py:

def discoverOsServicePack(self):
        patchLevel = None
        '''
        OS_PATCH_FILE_TO_REGEX = (
            ('/etc/SuSE-release', 'PATCHLEVEL = (.*)',),
            ('/etc/os-release', 'PRETTY_NAME="(.*[A-Za-z]+\s+)+(\d+\.?\d?)(.*)"',),
            )
        '''
        for (fileName, regex) in LinuxDiscoverer.OS_PATCH_FILE_TO_REGEX:
            output = self.getCommandsOutput(['cat %s' % fileName])
            if output and output.strip() and output.strip().split('\n'):
                if fileName.find("SuSE") > -1:
                    output = output.strip().split('\n')[2]
                    patchLevel = re.search(regex, output)
                    if patchLevel:
                        patchLevel = "SP" + patchLevel.group(1).strip()
                else:
                    output = output.strip().split('\n')[1]
                    patchLevel = re.search(regex, output)
                    if patchLevel and patchLevel.group(3) and patchLevel.group(3).find("SP"):
                            patchLevel = patchLevel.group(3).strip()

        self.hostDataObject.setOsServicePack(patchLevel)


At the moment parsing takes place in 2 steps:

step 1 (see line 4):

cat /etc/os-release

Output:

NAME="SLES"
VERSION="12-SP5"
VERSION_ID="12.5"
PRETTY_NAME="SUSE Linux Enterprise Server 12 SP5"
ID="sles"
ANSI_COLOR="0;32"
CPE_NAME="cpe:/o:suse:sles:12:sp5"

Step 2 (see line 12):

output.strip().split('\n')[1]

Output:

VERSION="12-SP5"

The actual method causes the regex in line 13 (PRETTY_NAME="(.*[A-Za-z]+\s+)+(\d+\.?\d?)(.*)") always to fail as the keyword PRETTY_NAME is not appearing in Line 2 (Index 1) .
Forcing the variable 'patchlevel' to be None and therefore never setting the Attribut 'unix_servicepack' to any value.

Functional requirement

IMHO there are multiple requirements:

- the output of 'cat /etc/os-release' should not be splitted into lines, as the order and size of this file may change in the future

- the regex expression should search for the keyword PRETTY_NAME in the whole output (more stable between versions)

- the match object returned by re.search should not use the same variable as the final returned variable
(in case the loop iterates more than 1 times the last iteration wins, as 'patchlevel' always gets overwritten by the last loop - I hope I am making any sense here ;) )

Proposal

I would propose to alter the method on just a few points, as following (feel free to correct or add any thoughts, as I only have tested the following in parts):

def discoverOsServicePack(self):

        patchLevel = None
        for (fileName, regex) in LinuxDiscoverer.OS_PATCH_FILE_TO_REGEX:
            output = self.getCommandsOutput(['cat %s' % fileName])
            if output and output.strip() and output.strip().split('\n'):
                if fileName.find("SuSE") > -1:
                    //output = output.strip().split('\n')[2]
                    //apply regex search to whole string
                    match = re.search(regex, output)
                    if match:
                        patchLevel = "SP" + match.group(1).strip()
                else:
                    //output = output.strip().split('\n')[1]
                    //apply regex search to whole string
                    match = re.search(regex, output)
                    if match and match.group(3) and match.group(3).find("SP"):
                        patchLevel = match.group(3).strip()

        self.hostDataObject.setOsServicePack(patchLevel)

Labels:

Discovery-Content
Discovery-infra
Optimization
  • Great find, note that the if condition below has a small bug

                        if match and match.group(3) and match.group(3).find("SP"):

    The match for match.group(3).find("SP") does not work correctly, and ends up matching on other OS such as Red hat 

    Example: PRETTY_NAME="Red Hat Enterprise Linux 8.2 (Ootpa)", this will set (Ootpa) as the Unix Service Pack

    I had to update to match.group(3).find("SP") != -1 in order to only get it to trigger for SuSE