<filename>module_linux.py
import os
import ast
import math

import paramiko

commands = ['cat /dev/null',
            'dmidecode -V',
            'fdisk -V',
            'find --version',
            'grep -V',
            'hdparm -V',
            'hostname',
            'id',
            'ifconfig -V',
            'ip -V',
            'lshal -V'
            'python2 -h',
            'python3 -V',
            'sort --version'
            'sudo -V',
            'wc --version']


class GetLinuxData:
    def __init__(self, base_url, username, secret, ip, ssh_port, timeout, usr, pwd, use_key_file, key_file,
                 get_serial_info, add_hdd_as_device_properties, add_hdd_as_parts, add_nic_as_parts,
                 get_hardware_info, get_os_details, get_cpu_info, get_memory_info,
                 ignore_domain, ignore_virtual_machines, upload_ipv6, give_hostname_precedence, debug):

        self.d42_api_url = base_url
        self.d42_username = username
        self.d42_password = <PASSWORD>
        self.machine_name = ip
        self.port = int(ssh_port)
        self.timeout = timeout
        self.username = usr
        self.password = <PASSWORD>
        self.use_key_file = use_key_file
        self.key_file = key_file
        self.get_serial_info = get_serial_info
        self.get_hardware_info = get_hardware_info
        self.get_os_details = get_os_details
        self.get_cpu_info = get_cpu_info
        self.get_memory_info = get_memory_info
        self.ignore_domain = ignore_domain
        self.ignore_virtual_machines = ignore_virtual_machines
        self.upload_ipv6 = upload_ipv6
        self.name_precedence = give_hostname_precedence
        self.add_hdd_as_devp = add_hdd_as_device_properties
        self.add_hdd_as_devp = False # do not edit, take a look at the inventory.config.example for details
        self.add_hdd_as_parts = add_hdd_as_parts
        self.add_nic_as_parts = add_nic_as_parts
        self.debug = debug
        self.root = True
        self.devicename = None
        self.disk_sizes = {}
        self.raids = {}
        self.hdd_parts = []
        self.nic_parts = []
        self.device_name = None
        self.os = None
        self.paths = {}
        self.nics = []
        self.alldata = []
        self.devargs = {}
        self.ssh = paramiko.SSHClient()
        self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    def main(self):
        self.connect()
        self.get_cmd_paths()
        self.are_u_root()
        if self.add_nic_as_parts:
            self.nic_parts = self.get_physical_nics()
            self.alldata.append(self.nic_parts)
        dtype = self.get_system()
        if dtype == 'virtual' and self.ignore_virtual_machines:
            return self.alldata
        if self.get_memory_info:
            self.get_ram()
        if self.get_cpu_info:
            self.get_cpu()
        if self.get_os_details:
            self.get_os()
        self.get_hdd()
        self.get_ip_ipaddr()
        self.get_ip_ipmi()
        self.alldata.append(self.devargs)
        if self.add_hdd_as_parts:
            self.alldata.append({'hdd_parts': self.hdd_parts})
        if self.add_nic_as_parts:
            self.alldata.append({'nic_parts': self.nic_parts})
        return self.alldata

    def connect(self):
        try:
            if not self.use_key_file:
                self.ssh.connect(str(self.machine_name), port=self.port,
                                 username=self.username, password=self.password, timeout=self.timeout)
            else:
                self.ssh.connect(str(self.machine_name), port=self.port,
                                 username=self.username, key_filename=self.key_file, timeout=self.timeout)
        except paramiko.AuthenticationException:
            print str(self.machine_name) + ': authentication failed'
            return None
        except Exception as err:
            print str(self.machine_name) + ': ' + str(err)
            return None

    def get_cmd_paths(self):
        search_paths = ['/usr/bin', '/bin', '/usr/local/bin', '/sbin', '/usr/sbin', '/usr/local/sbin']
        for cmd_to_find in commands:
            for search_path in search_paths:
                cmd_path = "%s/%s" % (search_path, cmd_to_find)
                data_out, data_err = self.execute(cmd_path, False)
                if not data_err:
                    self.paths.update({cmd_to_find.split()[0]: search_path})
                    break
                if 'command not found' in data_err:
                    if self.debug:
                        print '\t[-] Failed to find command "%s" at path "%s"' % (cmd_to_find, search_path)

    def find_command_path(self, cmd_to_find):
        search_paths = ['/usr/bin', '/bin', '/usr/local/bin', '/sbin', '/usr/sbin', '/usr/local/sbin']
        for search_path in search_paths:
            cmd_path = "%s/%s" % (search_path, cmd_to_find)
            data_out, data_err = self.execute(cmd_path, False)
            if not data_err:
                self.paths.update({cmd_to_find:search_path})
                return search_path
            if 'command not found' in data_err:
                if self.debug:
                    print '\t[-] Failed to find command "%s" at path "%s"' % (cmd_to_find, search_path)

    def execute(self, cmd, needroot=False):
        if needroot:
            if self.root:
                stdin, stdout, stderr = self.ssh.exec_command(cmd, timeout=30)
            else:
                if 'sudo' in self.paths:
                    cmd_sudo = "%s/sudo -S -p '' %s" % (self.paths['sudo'],cmd)
                cmd_sudo = "sudo -S -p '' %s" % cmd
                stdin, stdout, stderr = self.ssh.exec_command(cmd_sudo, timeout=30)
                stdin.write('%s\n' % self.password)
                stdin.flush()
        else:
            stdin, stdout, stderr = self.ssh.exec_command(cmd, timeout=30)
        data_err = stderr.readlines()
        try:
            data_out = stdout.readlines()
        except UnicodeDecodeError:
            data_x = stdout.read()
            data_out = data_x.split('\n')
        if data_err and 'sudo: command not found' in str(data_err):
            stdin, stdout, stderr = self.ssh.exec_command(cmd, timeout=30)
            data_err = stderr.readlines()
            data_out = stdout.readlines()
        return data_out, data_err

    def are_u_root(self):
        if 'id' in self.paths:
            cmd = '%s/id -u' % self.paths['id']
        else:
            cmd = 'id -u'
        data, err = self.execute(cmd)
        if data[0].strip() == '0':
            self.root = True
        else:
            self.root = False

    @staticmethod
    def to_ascii(s):
        try:
            return s.encode('ascii', 'ignore')
        except Exception as err:
            print '[?] to_ascii exception: ' + str(err)
            return None

    @staticmethod
    def closest_memory_assumption(v):
        if v < 512:
            v = 128 * math.ceil(v / 128.0)
        elif v < 1024:
            v = 256 * math.ceil(v / 256.0)
        elif v < 4096:
            v = 512 * math.ceil(v / 512.0)
        elif v < 8192:
            v = 1024 * math.ceil(v / 1024.0)
        else:
            v = 2048 * math.ceil(v / 2048.0)
        return int(v)

    def get_name(self):
        if 'hostname' in self.paths:
            cmd = '%s/hostname' % self.paths['hostname']
        else:
            cmd = 'hostname'
        data_out, data_err = self.execute(cmd)
        device_name = None
        if not data_err:
            if self.ignore_domain:
                device_name = self.to_ascii(data_out[0].rstrip()).split('.')[0]
            else:
                device_name = self.to_ascii(data_out[0].rstrip())
            if device_name != '':
                self.devargs.update({'name': device_name})
                if self.name_precedence:
                    self.devargs.update({'new_name': device_name})
                return device_name
        return device_name

    def get_system(self):
        self.device_name = self.get_name()
        if self.device_name not in ('', None):
            if 'dmidecode' in self.paths:
                cmd = '%s/dmidecode -t system' % self.paths['dmidecode']
            else:
                cmd = 'dmidecode -t system'
            data_out, data_err = self.execute(cmd, True)
            if not data_err:
                dev_type = None
                for rec in data_out:
                    if rec.strip() not in ('\n', ' ', '', None):
                        rec = rec.strip()
                        if rec.startswith('Manufacturer:'):
                            manufacturer = rec.split(':')[1].strip()
                            self.devargs.update({'manufacturer': manufacturer})
                            if manufacturer in ['VMware, Inc.', 'Bochs', 'KVM', 'QEMU',
                                                'Microsoft Corporation', 'Xen', 'innotek GmbH']:
                                dev_type = 'virtual'
                                if self.ignore_virtual_machines and dev_type == 'virtual':
                                    self.devargs.clear()
                                    return 'virtual'
                                else:
                                    self.devargs.update({'type': dev_type})
                        if rec.startswith('UUID:'):
                            uuid = rec.split(':')[1].strip()
                            self.devargs.update({'uuid': uuid})
                        if rec.startswith('Serial Number:'):
                            serial = rec.split(':')[1].strip()
                            if self.get_serial_info:
                                self.devargs.update({'serial_no': serial})
                        if rec.startswith('Product Name:') and dev_type != 'virtual':
                            hardware = rec.split(':')[1].strip()
                            self.devargs.update({'hardware': hardware})
            else:
                if self.debug:
                    print '\t[-] Failed to get sysdata from host: %s using dmidecode. Message was: %s' % \
                          (self.machine_name, str(data_err))
                self.get_system_2()

    def get_system_2(self):
        if 'grep' in self.paths:
            cmd = "%s/grep '' /sys/devices/virtual/dmi/id/*" % self.paths['grep']
        else:
            cmd = "grep '' /sys/devices/virtual/dmi/id/*"
        data_out, data_err = self.execute(cmd, True)
        if data_out:
            dev_type = 'physical'
            for rec in data_out:
                if 'sys_vendor:' in rec:
                    manufacturer = rec.split(':')[1].strip()
                    self.devargs.update({'manufacturer': manufacturer})
                    if manufacturer in ['VMware, Inc.', 'Bochs', 'KVM', 'QEMU',
                                        'Microsoft Corporation', 'Xen', 'innotek GmbH']:
                        dev_type = 'virtual'
                        if self.ignore_virtual_machines and dev_type == 'virtual':
                            self.devargs.clear()
                            return 'virtual'
                        else:
                            self.devargs.update({'type': dev_type})
                if 'product_uuid:' in rec:
                    uuid = rec.split(':')[1].strip()
                    self.devargs.update({'uuid': uuid})
                if 'product_serial:' in rec:
                    serial = rec.split(':')[1].strip()
                    if self.get_serial_info:
                        self.devargs.update({'serial_no': serial})
                if 'product_name:' in rec and dev_type != 'virtual':
                    hardware = rec.split(':')[1].strip()
                    self.devargs.update({'hardware': hardware})
        else:
            if self.debug:
                print '\t[-] Failed to get sysdata from host: %s using grep /sys.... Message was: %s' % \
                      (self.machine_name, str(data_err))
            self.get_system_3()

    def get_system_3(self):
        if 'lshal' in self.paths:
            cmd = "%s/lshal -l -u computer" % self.paths['lshal']
        else:
            cmd = "lshal -l -u computer"
        data_out, data_err = self.execute(cmd)
        if data_out:
            dev_type = None
            for rec in data_out:
                if 'system.hardware.vendor' in rec:
                    manufacturer = rec.split('=')[1].split('(')[0].strip()
                    self.devargs.update({'manufacturer': manufacturer})
                    if manufacturer in ['VMware, Inc.', 'Bochs', 'KVM', 'QEMU',
                                        'Microsoft Corporation', 'Xen', 'innotek GmbH']:
                        dev_type = 'virtual'
                        if self.ignore_virtual_machines and dev_type == 'virtual':
                            self.devargs.clear()
                            return 'virtual'
                        else:
                            self.devargs.update({'type': dev_type})
                if 'system.hardware.uuid' in rec:
                    uuid = rec.split('=')[1].split('(')[0].strip()
                    self.devargs.update({'uuid': uuid})
                if 'system.hardware.serial' in rec:
                    serial = rec.split('=')[1].split('(')[0].strip()
                    if self.get_serial_info:
                        self.devargs.update({'serial_no': serial})
                if 'system.hardware.product' in rec and dev_type != 'virtual':
                    hardware = rec.split('=')[1].split('(')[0].strip()
                    self.devargs.update({'hardware': hardware})
        else:
            if self.debug:
                print '\t[-] Failed to get sysdata from host: %s using lshal. Message was: %s' % \
                      (self.machine_name, str(data_err))

    def get_ram(self):
        if 'grep' in self.paths:
            cmd = '%s/grep MemTotal /proc/meminfo' % self.paths['grep']
        else:
            cmd = 'grep MemTotal /proc/meminfo'
        data_out, data_err = self.execute(cmd)
        if not data_err:
            memory_raw = ''.join(data_out).split()[1]
            memory = self.closest_memory_assumption(int(memory_raw) / 1024)
            self.devargs.update({'memory': memory})
        else:
            if self.debug:
                print '\t[-] Could not get RAM info from host %s. Message was: %s' % (self.machine_name, str(data_err))

    def get_os(self):
        if 'python2' in self.paths:
            cmd = '%s/python -c "import platform; raw = list(platform.dist());raw.append(platform.release());print raw"'\
                  % self.paths['python2']
        else:
            cmd = 'python -c "import platform; raw = list(platform.dist());raw.append(platform.release());print raw"'
        data_out, data_err = self.execute(cmd)
        if not data_err:
            if 'command not found' not in data_out[0]:  # because some distros sport python3 by default!
                self.os, ver, release, kernel_version = ast.literal_eval(data_out[0])
                self.devargs.update({'os': self.os})
                self.devargs.update({'osver': ver if ver else 'D42_NULL'})
                self.devargs.update({'osverno': kernel_version})
                return
            else:
                if 'python3' in self.paths:
                    cmd = '%s/python3 -c "import platform; raw = list(platform.dist());raw.append(platform.release());' \
                          'print (raw)"' % self.paths['python3']
                else:
                    cmd = 'python3 -c "import platform; raw = list(platform.dist());' \
                      'raw.append(platform.release());print (raw)"'
                data_out, data_err = self.execute(cmd)
                if not data_err:
                    self.os, ver, release, kernel_version = ast.literal_eval(data_out[0])
                    self.devargs.update({'os': self.os})
                    self.devargs.update({'osver': ver})
                    self.devargs.update({'osverno': kernel_version})
                    return
                else:
                    if self.debug:
                        print '\t[-] Could not get OS info from host %s. Message was: %s' % (
                            self.machine_name, str(data_err))
        if data_err and 'command not found' in data_err[0]:
            if 'python3' in self.paths:
                cmd = '%s/python3 -c "import platform; raw = list(platform.dist());' \
                        'raw.append(platform.release());print (raw)"' % self.paths['python3']
            else:
                cmd = 'python3 -c "import platform; raw = list(platform.dist());' \
                        'raw.append(platform.release());print (raw)"'
            data_out, data_err = self.execute(cmd)
            if not data_err:
                self.os, ver, release, kernel_version = ast.literal_eval(data_out[0])
                self.devargs.update({'os': self.os})
                self.devargs.update({'osver': ver})
                self.devargs.update({'osverno': kernel_version})
                return
            else:
                if self.debug:
                    print '\t[-] Could not get OS info from host %s. Message was: %s' % (
                        self.machine_name, str(data_err))
        else:
            if self.debug:
                print '\t[-] Could not get OS info from host %s. Message was: %s' % (self.machine_name, str(data_err))

    def get_cpu(self):
        processors = self.get_cpu_num()
        if 'cat' in self.paths:
            cmd = '%s/cat /proc/cpuinfo' % self.paths['cat']
        else:
            cmd = 'cat /proc/cpuinfo'
        data_out, data_err = self.execute(cmd)
        if not data_err:
            cores = 1
            cpuspeed = 0
            for rec in data_out:
                if rec.startswith('cpu MHz'):
                    cpuspeed = int((float(rec.split(':')[1].strip())))
                if rec.startswith('cpu cores'):
                    cores = int(rec.split(':')[1].strip())
            self.devargs.update({'cpucount': processors})
            self.devargs.update({'cpucore': cores})
            self.devargs.update({'cpupower': cpuspeed})

        else:
            if self.debug:
                print '\t[-] Could not get CPU info from host %s. Message was: %s' % (self.machine_name, str(data_err))

    def get_cpu_num(self):
        if 'cat' in self.paths:
            cat_path = self.paths['cat'] + '/cat'
        else:
            cat_path = 'cat'
        if 'grep' in self.paths:
            grep_path = self.paths['grep'] + '/grep'
        else:
            grep_path = 'grep'
        if 'sort' in self.paths:
            sort_path = self.paths['sort'] + '/sort'
        else:
            sort_path = 'sort'
        if 'wc' in self.paths:
            wc_path = self.paths['wc'] + '/wc'
        else:
            wc_path = 'wc'

        cmd = '%s /proc/cpuinfo | %s "physical id" | %s -u | %s -l' % (cat_path, grep_path, sort_path, wc_path)
        data_out, data_err = self.execute(cmd)
        if not data_err:
            cpu_num = ''.join(data_out).strip()
            return cpu_num
        else:
            return 0

    def get_ip_ipmi(self):
        data_out, data_err = self.execute('ipmitool lan print 1')
        mac = None
        ip = None
        if not data_err:
            for row in data_out:
                if 'MAC Address' in row:
                    mac_data = row.split()
                    if len(mac_data) > 2:
                        mac = mac_data[3]
                elif 'IP Address' in row and 'Source' not in row:
                    ip_data = row.split(':')
                    if len(ip_data) > 1:
                        ip = ip_data[1].strip()
            if ip and mac:
                self.ip_to_json('ipmi', mac, ip, '')
        else:
            if self.debug:
                print '\t[-] Could not get IPMI IP info from host %s. Message was: %s' % (self.machine_name, str(data_err))

    def get_ip_ifconfig(self):
        if 'ifconfig' in self.paths:
            cmd = '%s/ifconfig'
        else:
            cmd = '/sbin/ifconfig'
        data_out, data_err = self.execute(cmd)
        if not data_err:
            new = True
            nic = mac = ip = ip6 = ''
            for row in data_out:
                if row not in ('', '\n', None):
                    if not row.startswith('  '):
                        if new:
                            nic = row.split()[0].strip(':').strip()
                            new = False
                        else:
                            if not nic.startswith('lo'):
                                self.ip_to_json(nic, mac, ip, ip6)
                            nic = row.split()[0].strip(':')
                            new = True
                        if 'HWaddr ' in row:
                            words = row.split()
                            macindex = words.index('HWaddr') + 1
                            mac = words[macindex].strip()
                    else:
                        new = False
                        if 'inet addr:' in row:
                            words = row.split()
                            ipindex = words.index('inet') + 1
                            ip = words[ipindex].strip('addr:').strip()
                        elif 'inet ' in row and 'addr:' not in row:
                            words = row.split()
                            ipindex = words.index('inet') + 1
                            ip = words[ipindex].strip()
                        # debian/ubuntu
                        if 'inet6 addr:' in row and row.split()[-1].lower() != 'scope:link':
                            ip6 = row.split()[2]
                            if '%' in ip6:
                                ip6 = ip6.split('%')[0]
                            if '/' in ip6:
                                ip6 = ip6.split('/')[0]
                            if ip6 and ip6 == '::1':
                                ip6 = ''
                        # redhat/centos
                        elif 'inet6 ' in row and 'addr:' not in row and '<link>' not in row and '<host>' not in row:
                            ip6 = row.split()[1]
                            if '%' in ip6:
                                ip6 = ip6.split('%')[0]
                            if '/' in ip6:
                                ip6 = ip6.split('/')[0]
                            if ip6 and ip6 == '::1':
                                ip6 = ''
                        if 'ether ' in row:
                            words = row.split()
                            macindex = words.index('ether') + 1
                            mac = words[macindex].strip()

            if not nic.startswith('lo'):
                self.ip_to_json(nic, mac, ip, ip6)

        else:
            if self.debug:
                print '\t[-] Could not get IP info from host %s. Message was: %s' % (self.machine_name, str(data_err))

    def ip_to_json(self, nic, mac, ip, ip6):
        macdata = {}
        nicdata = {}
        nicdata_v6 = {}
        nicdata.update({'device': self.device_name})
        nicdata_v6.update({'device': self.device_name})
        macdata.update({'device': self.device_name})
        nicdata.update({'tag': nic})
        nicdata_v6.update({'tag': nic})
        macdata.update({'port_name': nic})
        nicdata.update({'macaddress': mac})
        nicdata_v6.update({'macaddress': mac})
        macdata.update({'macaddress': mac})
        nicdata.update({'ipaddress': ip})
        nicdata_v6.update({'ipaddress': ip6})
        # if ip != '':
        self.alldata.append(nicdata)
        if ip6 != '':
            self.alldata.append(nicdata_v6)
        if mac != '':
            self.alldata.append(macdata)

    def get_ip_ipaddr(self):
        if 'ip' in self.paths:
            cmd = '%s/ip addr show' % self.paths['ip']
        else:
            cmd = 'ip addr show'
        data_out, data_err = self.execute(cmd)
        if not data_err and 'command not found' not in data_out[0]:
            macmap = {}
            ipmap = {}
            ip6map = {}
            nics = []
            nicmap = {}
            current_nic = None
            for rec in data_out:
                # macs
                if not rec.startswith('  ') and rec not in ('', '\n'):
                    if ':' in rec:
                        mac = None
                        raw = rec.split(':')
                        try:
                            nic = raw[1].strip()
                            if '@' in nic:
                                nic = nic.split('@')[0]
                            current_nic = nic
                            rec_index = data_out.index(rec)
                            mac_word = data_out[rec_index + 1]
                            if 'link/ether' in mac_word:
                                parts = mac_word.split()
                                if len(parts) >= 4:
                                    mac = parts[1]
                            if nic != 'lo' and mac:
                                macmap.update({nic: mac})
                                if self.add_nic_as_parts:
                                    if nic in self.nic_parts:
                                        self.nic_parts[nic]["serial_no"]=mac
                        except IndexError:
                            pass
                # get nic names and ips
                elif rec.strip().startswith('inet ') and 'scope global' in rec:
                    inetdata = rec.split()
                    ip = inetdata[1].split('/')[0]
                    interface = inetdata[-1]
                    if ':' in interface:
                        macmap.update({interface: macmap[interface.split(':')[0]]})
                    nics.append(interface)
                    ipmap.update({interface: ip})
                elif rec.strip().startswith('inet6 ') and 'scope global' in rec:
                    inetdata = rec.split()
                    ip = inetdata[1].split('/')[0]
                    interface = current_nic
                    if ':' in interface:
                        macmap.update({interface: macmap[interface.split(':')[0]]})
                    nicmap.update({interface: current_nic})
                    ip6map.update({interface: ip})

            # jsonize
            for nic in nics:
                nicdata = {}
                nicdata_v6 = {}
                macdata = {}
                if nic in macmap:
                    mac = macmap[nic]
                    macdata.update({'device': self.device_name})
                    macdata.update({'port_name': nic})
                    macdata.update({'macaddress': mac})
                if nic in ipmap:
                    ip = ipmap[nic]
                    nicdata.update({'device': self.device_name})
                    nicdata.update({'tag': nic})
                    nicdata.update({'ipaddress': ip})
                    if nic in macmap:
                        mac = macmap[nic]
                        nicdata.update({'macaddress': mac})
                if nic in ip6map:
                    ip6 = ip6map[nic]
                    nicdata_v6.update({'device': self.device_name})
                    nicdata_v6.update({'tag': nic})
                    nicdata_v6.update({'ipaddress': ip6})
                    if nic in macmap:
                        mac = macmap[nic]
                        nicdata_v6.update({'macaddress': mac})

                if nicdata:
                    self.alldata.append(nicdata)
                if nicdata_v6:
                    self.alldata.append(nicdata_v6)
                if macdata:
                    self.alldata.append(macdata)

        else:
            if self.debug:
                print '\t[-] Could not get NIC info from host %s. Switching to "ifconfig".' \
                      '\n\t\t Message was: %s' % (self.machine_name, str(data_err))
            self.get_ip_ifconfig()

    def get_hdd(self):
        hdds = self.get_hdd_names()
        hw_hdds = [x for x in hdds if '/mapper' not in x]
        if hw_hdds:
            if self.add_hdd_as_devp :
                self.devargs.update({'hddcount': len(hw_hdds)})
            for hdd in hw_hdds:
                hdd_part = self.get_hdd_info_hdaparm(hdd)
                if hdd_part:
                    self.hdd_parts.append(hdd_part)

    def get_hdd_names(self):
        if 'fdisk' in self.paths:
            fdisk_path = self.paths['fdisk'] + '/fdisk'
        else:
            fdisk_path = 'fdisk'
        if 'grep' in self.paths:
            grep_path = self.paths['grep'] + '/grep'
        else:
            grep_path = 'grep'
        hdd_names = []
        cmd = '%s -l | %s -v "ram\|mapper" | %s "Disk /dev"' % (fdisk_path, grep_path, grep_path)
        data_out, data_err = self.execute(cmd, True)
        errhdds = []
        if data_err:
            for rec in data_err:
                if "doesn't contain a valid partition table" in rec:
                    disk = rec.split()[1]
                    errhdds.append(disk)

        for rec in data_out:
            try:
                mess = rec.strip().split()
                disk = mess[1]
                if disk.endswith(':'):
                    disk_name = disk.strip(':')
                else:
                    disk_name = disk
                sizeformat = mess[3].lower().strip(',')
                size = float(mess[2])
                if self.add_hdd_as_devp:
                    self.devargs.update({'hddsize': size})
                if sizeformat in ('mib', 'mb'):
                    size = int(math.ceil(size / 1024))
                    if self.add_hdd_as_devp:
                        self.devargs.update({'hddsize': size})
                hdd_names.append(disk_name)
                self.disk_sizes.update({disk_name: size})
            except Exception as err:
                print '[?] get_hdd_names exception: ' + str(err)

        return hdd_names

    def get_hdd_info_hdaparm(self, hdd):
        if 'hdparm' in self.paths:
            cmd = '%s/hdparm -I %s' % (self.paths['hdparm'], hdd)
        else:
            cmd = 'hdparm -I %s' % hdd
        data_out, data_err = self.execute(cmd, True)
        if data_err:
            if self.debug:
                print '[-] Error in get_hdd_info_hdaparm() for IP: %s . Message was: %s' % (self.machine_name, data_err)
            return
        else:
            hdd_part = {}
            for rec in data_out:
                if 'model number' in rec.lower():
                    model = rec.split(':')[1].strip()
                    size = self.disk_sizes[hdd]
                    hdd_part.update({'device': self.device_name, 'assignment': 'device'})
                    hdd_part.update({'name': model})
                    hdd_part.update({'type': 'hdd'})
                    hdd_part.update({'hddsize': size})
                if 'serial number' in rec.lower():
                    serial = rec.split(':')[1].strip()
                    hdd_part.update({'serial_no': serial})
                if 'transport:' in rec.lower():
                    if ',' in rec:
                        try:
                            transport = (rec.split(',')[-1]).split()[0]
                        except IndexError:
                            transport = (rec.split(',')[-1])
                    else:
                        transport = rec.lower()
                    hdd_part.update({'hddtype': transport})
                if 'rotation rate' in rec.lower():
                    rpm = rec.split(':')[1].strip()
                    if not rpm == 'Solid State Device':
                        hdd_part.update({'hddrpm': rpm})
                    else:
                        hdd_part.update({'hddtype': 'SSD'})
            return hdd_part

    def get_physical_nics(self):
        if 'find' in self.paths:
            cmd = "%s/find /sys/devices/pci0000:00 -name net -exec ls '{}' \; -exec dirname '{}' \;" % self.paths['find']
        else:
            cmd = "find /sys/devices/pci0000:00 -name net -exec ls '{}' \; -exec dirname '{}' \;"
        nics = {}
        device_name = self.get_name()

        data_out, data_err = self.execute(cmd)
        if not data_err:
            for i in range(0, len(data_out), 2):
                nic = data_out[i].strip()
                path = self.check_nic_path(data_out[i + 1].strip())
                vendor_code = self.get_nic_vendor_code(path)
                vendor_subcode = self.get_nic_vendor_subcode(path)
                model_code = self.get_nic_model_code(path)
                model_subcode = self.get_nic_model_subcode(path)
                nics.update({nic:{"manufacturer":vendor_code,
                                  "name": model_code,
                                  "serial_no": None,
                                  "device": device_name,
                                  "model_subcode": model_subcode,
                                  "manufacturer_subcode": vendor_subcode}})
        else:
            if self.debug:
                print '[!] Error in get_physical_nics(). Message was: %s' % data_err

        return nics

    def check_nic_path(self, path):
        path_parts = os.path.split(path)
        # ssb patch
        try:
            if 'ssb' in path_parts[-1]:
                new_path = '/'.join(path_parts[0:-1])
                return new_path
            else:
                return path
        except Exception as err:
            print '[?] check_nic_path exception: ' + str(err)

    def get_nic_vendor_code(self, path):
        if 'cat' in self.paths:
            cmd = "%s/cat %s/vendor" % (self.paths['cat'],path)
        else:
            cmd = "cat %s/vendor" % path
        data_out, data_err = self.execute(cmd)
        if not data_err:
            vendor_code = ''.join(data_out).strip()[2:]
            return vendor_code

    def get_nic_vendor_subcode(self, path):
        if 'cat' in self.paths:
            cmd = "%s/cat %s/subsystem_vendor" % (self.paths['cat'],path)
        else:
            cmd = "cat %s/subsystem_vendor" % path
        data_out, data_err = self.execute(cmd)
        if not data_err:
            vendor_subcode = ''.join(data_out).strip()[2:]
            return vendor_subcode

    def get_nic_model_code(self, path):
        if 'cat' in self.paths:
            cmd = "%s/cat %s/device" % (self.paths['cat'],path)
        else:
            cmd = "cat %s/device" % path
        data_out, data_err = self.execute(cmd)
        if not data_err:
            model_code = ''.join(data_out).strip()[2:]
            return model_code

    def get_nic_model_subcode(self, path):
        if 'cat' in self.paths:
            cmd = "%s/cat %s/subsystem_device" % (self.paths['cat'],path)
        else:
            cmd = "cat %s/subsystem_device" % path
        data_out, data_err = self.execute(cmd)
        if not data_err:
            sub_code = ''.join(data_out).strip()[2:]
            return sub_code

