You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ds...@apache.org on 2013/12/17 14:24:50 UTC

git commit: AMBARI-4084 Remove use of Facter on the Agent so that all the info can be grabbed using Python. (dsen)

Updated Branches:
  refs/heads/trunk 064ac7c1b -> f3afbc701


AMBARI-4084 Remove use of Facter on the Agent so that all the info can be grabbed using Python. (dsen)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/f3afbc70
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/f3afbc70
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/f3afbc70

Branch: refs/heads/trunk
Commit: f3afbc70128a2f0d0564a54419c6b72328136fe4
Parents: 064ac7c
Author: Dmitry Sen <ds...@hortonworks.com>
Authored: Tue Dec 17 15:21:17 2013 +0200
Committer: Dmitry Sen <ds...@hortonworks.com>
Committed: Tue Dec 17 15:21:17 2013 +0200

----------------------------------------------------------------------
 .../src/main/python/ambari_agent/Facter.py      | 367 +++++++++++++++++++
 .../src/main/python/ambari_agent/Hardware.py    | 132 +------
 .../src/main/python/ambari_agent/Register.py    |   2 +-
 .../test/python/ambari_agent/TestHardware.py    | 173 ++++-----
 4 files changed, 459 insertions(+), 215 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f3afbc70/ambari-agent/src/main/python/ambari_agent/Facter.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/Facter.py b/ambari-agent/src/main/python/ambari_agent/Facter.py
new file mode 100644
index 0000000..65fcfde
--- /dev/null
+++ b/ambari-agent/src/main/python/ambari_agent/Facter.py
@@ -0,0 +1,367 @@
+#!/usr/bin/env python2.6
+
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+'''
+
+import logging
+import os
+import getpass
+import platform
+import re
+import shlex
+import socket
+import multiprocessing
+import subprocess
+
+import time
+import uuid
+import hostname
+
+log = logging.getLogger()
+
+# selinux command
+GET_SE_LINUX_ST_CMD = "/usr/sbin/sestatus"
+GET_IFCONFIG_CMD = "ifconfig"
+GET_UPTIME_CMD = "cat /proc/uptime"
+GET_MEMINFO_CMD = "cat /proc/meminfo"
+
+DATA_IFCONFIG_OUTPUT = ""
+DATA_UPTIME_OUTPUT = ""
+DATA_MEMINFO_OUTPUT = ""
+
+
+class Facter():
+  def __init__(self):
+    global DATA_IFCONFIG_OUTPUT
+    DATA_IFCONFIG_OUTPUT = Facter.setDataIfConfigOutput()
+    global DATA_UPTIME_OUTPUT
+    DATA_UPTIME_OUTPUT = Facter.setDataUpTimeOutput()
+    global DATA_MEMINFO_OUTPUT
+    DATA_MEMINFO_OUTPUT = Facter.setMemInfoOutput()
+    pass
+
+  @staticmethod
+  def setDataIfConfigOutput():
+
+    try:
+      result = os.popen(GET_IFCONFIG_CMD).read()
+      return result
+    except OSError:
+      log.warn("Can't execute {0}".format(GET_IFCONFIG_CMD))
+    return ""
+
+  @staticmethod
+  def setDataUpTimeOutput():
+
+    try:
+      result = os.popen(GET_UPTIME_CMD).read()
+      return result
+    except OSError:
+      log.warn("Can't execute {0}".format(GET_UPTIME_CMD))
+    return ""
+
+  @staticmethod
+  def setMemInfoOutput():
+
+    try:
+      result = os.popen(GET_MEMINFO_CMD).read()
+      return result
+    except OSError:
+      log.warn("Can't execute {0}".format(GET_MEMINFO_CMD))
+    return ""
+
+  # Returns the currently running user id
+  def getId(self):
+    return getpass.getuser()
+
+  # Returns the OS name
+  def getKernel(self):
+    return platform.system()
+
+  # Returns the FQDN of the host
+  def getFqdn(self):
+    return socket.getfqdn()
+
+  # Returns the host's primary DNS domain name
+  def getDomain(self):
+    fqdn = self.getFqdn()
+    hostname = self.getHostname()
+    domain = fqdn.replace(hostname, "", 1)
+    domain = domain.replace(".", "", 1)
+    return domain
+
+  # Returns the short hostname
+  def getHostname(self):
+    return hostname.hostname()
+
+  # Returns the CPU hardware architecture
+  def getArchitecture(self):
+    result = platform.processor()
+    if result == '':
+      return 'OS NOT SUPPORTED'
+    else:
+      return result
+
+  # Returns the name of the OS
+  def getOperatingSystem(self):
+    dist = platform.linux_distribution()
+    operatingSystem = dist[0].lower()
+
+    if os.path.exists('/etc/oracle-release'):
+      return 'OracleLinux'
+    elif operatingSystem.startswith('suse linux enterprise server'):
+      return 'SLES'
+    elif operatingSystem.startswith('red hat enterprise linux server'):
+      return 'RedHat'
+    elif operatingSystem != '':
+      return operatingSystem
+    else:
+      return 'OS NOT SUPPORTED'
+
+  # Returns the OS vesion
+  def getOperatingSystemRelease(self):
+    dist = platform.linux_distribution()
+    if dist[1] != '':
+      return dist[1]
+    else:
+      return 'OS NOT SUPPORTED'
+
+  # Returns the OS TimeZone
+  def getTimeZone(self):
+    return time.tzname[time.daylight - 1]
+
+
+  # Returns the CPU count
+  def getProcessorcount(self):
+    return multiprocessing.cpu_count()
+
+  # Returns the Kernel release
+  def getKernelRelease(self):
+    return platform.release()
+
+
+  # Returns the Kernel release version
+  def getKernelVersion(self):
+    kernel_release = platform.release()
+    return kernel_release.split('-', 1)[0]
+
+  # Returns the major kernel release version
+  def getKernelMajVersion(self):
+    return '.'.join(self.getKernelVersion().split('.', 2)[0:2])
+
+  def getMacAddress(self):
+    mac = uuid.getnode()
+    if uuid.getnode() == mac:
+      mac = ':'.join('%02X' % ((mac >> 8 * i) & 0xff) for i in reversed(xrange(6)))
+    else:
+      mac = 'UNKNOWN'
+    return mac
+
+  # Returns the operating system family
+
+  def getOsFamily(self):
+    os_family = self.getOperatingSystem().lower()
+    if os_family in ['redhat', 'fedora', 'centos', 'oraclelinux', 'ascendos',
+                     'amazon', 'xenserver', 'oel', 'ovs', 'cloudlinux',
+                     'slc', 'scientific', 'psbm']:
+      os_family = 'RedHat'
+    elif os_family in ['ubuntu', 'debian']:
+      os_family = 'Debian'
+    elif os_family in ['sles', 'sled', 'opensuse', 'suse']:
+      os_family = 'Suse'
+    elif os_family == '':
+      os_family = 'OS NOT SUPPORTED'
+    else:
+      os_family = self.getOperatingSystem()
+    return os_family
+
+  def isSeLinux(self):
+
+    try:
+      retcode, out, err = run_os_command(GET_SE_LINUX_ST_CMD)
+      se_status = re.search('(enforcing|permissive|enabled)', out)
+      if se_status:
+        return True
+    except OSError:
+      log.warn("Could not run {0}: OK".format(GET_SE_LINUX_ST_CMD))
+    return False
+
+  # Function that returns list of values that matches
+  # Return empty str if no matches
+  def data_return_list(self, patern, data):
+    full_list = re.findall(patern, data)
+    result = ""
+    for i in full_list:
+      result = result + i + ","
+
+    result = re.sub(r',$', "", result)
+    return result
+
+  def data_return_first(self, patern, data):
+    full_list = re.findall(patern, data)
+    result = ""
+    if full_list:
+      result = full_list[0]
+
+    return result
+
+  #Convert kB to GB
+  def convertSizeKbToGb(self, size):
+    return "%0.2f GB" % round(float(size) / (1024.0 * 1024.0), 2)
+
+  # Return first ip adress
+  def getIpAddress(self):
+    result = self.data_return_first("(?: inet addr:)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", DATA_IFCONFIG_OUTPUT)
+    if result == '':
+      return 'OS NOT SUPPORTED'
+    else:
+      return result
+
+  # Return  netmask
+  def getNetmask(self):
+    result = self.data_return_first("(?: Mask:)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", DATA_IFCONFIG_OUTPUT)
+    if result == '':
+      return 'OS NOT SUPPORTED'
+    else:
+      return result
+
+  # Return interfaces
+  def getInterfaces(self):
+    result = self.data_return_list("(\w+)(?:.*Link encap:)", DATA_IFCONFIG_OUTPUT)
+    if result == '':
+      return 'OS NOT SUPPORTED'
+    else:
+      return result
+
+  # Return uptime seconds
+  def getUptimeSeconds(self):
+    try:
+      return int(self.data_return_first("\d+", DATA_UPTIME_OUTPUT))
+    except ValueError:
+      return 0
+
+
+  # Return uptime hours
+  def getUptimeHours(self):
+    return self.getUptimeSeconds() / (60 * 60)
+
+  # Return uptime days
+  def getUptimeDays(self):
+    return self.getUptimeSeconds() / (60 * 60 * 24)
+
+  # Return memoryfree
+  def getMemoryFree(self):
+    #:memoryfree_mb => "MemFree",
+    try:
+      return int(self.data_return_first("MemFree:.*?(\d+) .*", DATA_MEMINFO_OUTPUT))
+    except ValueError:
+      return 0
+
+  # Return memorytotal
+  def getMemoryTotal(self):
+    try:
+      return int(self.data_return_first("MemTotal:.*?(\d+) .*", DATA_MEMINFO_OUTPUT))
+    except ValueError:
+      return 0
+
+  # Return swapfree
+  def getSwapFree(self):
+    #:swapfree_mb   => "SwapFree"
+    try:
+      return int(self.data_return_first("SwapFree:.*?(\d+) .*", DATA_MEMINFO_OUTPUT))
+    except ValueError:
+      return 0
+
+  # Return swapsize
+  def getSwapSize(self):
+    #:swapsize_mb   => "SwapTotal",
+    try:
+      return int(self.data_return_first("SwapTotal:.*?(\d+) .*", DATA_MEMINFO_OUTPUT))
+    except ValueError:
+      return 0
+
+  # Return memorysize
+  def getMemorySize(self):
+    #:memorysize_mb => "MemTotal"
+    try:
+      return int(self.data_return_first("MemTotal:.*?(\d+) .*", DATA_MEMINFO_OUTPUT))
+    except ValueError:
+      return 0
+
+
+  def facterInfo(self):
+    facterInfo = {}
+    facterInfo['id'] = self.getId()
+    facterInfo['kernel'] = self.getKernel()
+    facterInfo['domain'] = self.getDomain()
+    facterInfo['fqdn'] = self.getFqdn()
+    facterInfo['hostname'] = self.getHostname()
+    facterInfo['macaddress'] = self.getMacAddress()
+    facterInfo['architecture'] = self.getArchitecture()
+    facterInfo['operatingsystem'] = self.getOperatingSystem()
+    facterInfo['operatingsystemrelease'] = self.getOperatingSystemRelease()
+    facterInfo['physicalprocessorcount'] = self.getProcessorcount()
+    facterInfo['processorcount'] = self.getProcessorcount()
+    facterInfo['timezone'] = self.getTimeZone()
+    facterInfo['hardwareisa'] = self.getArchitecture()
+    facterInfo['hardwaremodel'] = self.getArchitecture()
+    facterInfo['kernelrelease'] = self.getKernelRelease()
+    facterInfo['kernelversion'] = self.getKernelVersion()
+    facterInfo['osfamily'] = self.getOsFamily()
+    facterInfo['selinux'] = self.isSeLinux()
+    facterInfo['kernelmajversion'] = self.getKernelMajVersion()
+
+    facterInfo['ipaddress'] = self.getIpAddress()
+    facterInfo['netmask'] = self.getNetmask()
+    facterInfo['interfaces'] = self.getInterfaces()
+
+    facterInfo['uptime_seconds'] = str(self.getUptimeSeconds())
+    facterInfo['uptime_hours'] = str(self.getUptimeHours())
+    facterInfo['uptime_days'] = str(self.getUptimeDays())
+
+    facterInfo['memorysize'] = self.getMemorySize()
+    facterInfo['memoryfree'] = self.getMemoryFree()
+    facterInfo['swapsize'] = self.convertSizeKbToGb(self.getSwapSize())
+    facterInfo['swapfree'] = self.convertSizeKbToGb(self.getSwapFree())
+    facterInfo['memorytotal'] = self.getMemoryTotal()
+
+    return facterInfo
+
+def run_os_command(cmd):
+  if type(cmd) == str:
+    cmd = shlex.split(cmd)
+  process = subprocess.Popen(cmd,
+                             stdout=subprocess.PIPE,
+                             stdin=subprocess.PIPE,
+                             stderr=subprocess.PIPE
+  )
+  (stdoutdata, stderrdata) = process.communicate()
+  return process.returncode, stdoutdata, stderrdata
+
+
+def main(argv=None):
+  print Facter().facterInfo()
+
+
+if __name__ == '__main__':
+  main()
+
+
+
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/f3afbc70/ambari-agent/src/main/python/ambari_agent/Hardware.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/Hardware.py b/ambari-agent/src/main/python/ambari_agent/Hardware.py
index c62cb51..801fe3f 100644
--- a/ambari-agent/src/main/python/ambari_agent/Hardware.py
+++ b/ambari-agent/src/main/python/ambari_agent/Hardware.py
@@ -21,24 +21,18 @@ limitations under the License.
 import os.path
 import logging
 import subprocess
-import pprint
-import traceback
-import re
-
-import AmbariConfig
-
+from Facter import Facter
 
 logger = logging.getLogger()
 
 class Hardware:
   SSH_KEY_PATTERN = 'ssh.*key'
 
-  def __init__(self, config):
-    self.config = config
+  def __init__(self):
     self.hardware = {}
     osdisks = self.osdisks()
     self.hardware['mounts'] = osdisks
-    otherInfo = self.facterInfo()
+    otherInfo = Facter().facterInfo()
     self.hardware.update(otherInfo)
     pass
 
@@ -52,13 +46,13 @@ class Hardware:
     if (len(split)) == 7:
       device, type, size, used, available, percent, mountpoint = split
       mountinfo = {
-        'size' : size,
-        'used' : used,
-        'available' : available,
-        'percent' : percent,
-        'mountpoint' : mountpoint,
+        'size': size,
+        'used': used,
+        'available': available,
+        'percent': percent,
+        'mountpoint': mountpoint,
         'type': type,
-        'device' : device }
+        'device': device}
       return mountinfo
     else:
       return None
@@ -80,117 +74,11 @@ class Hardware:
     pass
     return mounts
 
-  def facterBin(self, facterHome):
-    facterBin = facterHome + "/bin/facter"
-    if (os.path.exists(facterBin)):
-      return facterBin
-    else:
-      return "facter"
-    pass
-  
-  def facterLib(self, facterHome):
-    return facterHome + "/lib/"
-    pass
-  
-  def configureEnviron(self, environ):
-    if not self.config.has_option("puppet", "ruby_home"):
-      return environ
-    ruby_home = self.config.get("puppet", "ruby_home")
-    if os.path.exists(ruby_home):
-      """Only update ruby home if the config is configured"""
-      path = os.environ["PATH"]
-      if not ruby_home in path:
-        environ["PATH"] = ruby_home + os.path.sep + "bin"  + ":"+environ["PATH"] 
-      environ["MY_RUBY_HOME"] = ruby_home
-    return environ
-    
-  def parseFacterOutput(self, facterOutput):
-    retDict = {}
-    compiled_pattern = re.compile(self.SSH_KEY_PATTERN)
-    allLines = facterOutput.splitlines()
-    for line in allLines:
-      keyValue = line.split("=>")
-      if (len(keyValue) == 2):
-        """Ignoring values that are just spaces or do not confirm to the 
-        format"""
-        strippedKey = keyValue[0].strip()
-        logger.info("Stripped key is " + strippedKey)
-        if strippedKey in ["memoryfree", "memorysize", "memorytotal"]:
-          value = keyValue[1].strip()
-          """Convert to KB"""
-          parts = value.split()
-          if len(parts) == 2:
-            mem_size = parts[1].upper()
-            if mem_size in ["GB", "G"]:
-              mem_in_kb = long(float(parts[0]) * 1024 * 1024)
-            elif mem_size in ["MB", "M"]:
-              mem_in_kb = long(float(parts[0]) * 1024)
-            elif mem_size in ["KB", "K"]:
-              mem_in_kb = long(float(parts[0]))
-            else:
-              mem_in_kb = long(float(parts[0]) / 1024)
-          else:
-            mem_in_kb = long(float(parts[0]) / 1024)
-          retDict[strippedKey] = mem_in_kb
-          pass
-        else:
-          if not compiled_pattern.match(strippedKey):
-            retDict[strippedKey] = keyValue[1].strip()
-          pass
-        pass
-      pass
-    """ Convert the needed types to the true values """
-    if 'physicalprocessorcount' in retDict.keys():
-      retDict['physicalprocessorcount'] = int(retDict['physicalprocessorcount'])
-      pass
-    if 'is_virtual' in retDict.keys():
-      retDict['is_virtual'] = ("true" == retDict['is_virtual'])
-      pass
-    
-    logger.info("Facter info : \n" + pprint.pformat(retDict))
-    return retDict  
-  
-  def facterInfo(self):
-    facterHome = self.config.get("puppet", "facter_home")
-    facterEnv = os.environ
-    logger.info("Using facter home as: " + facterHome)
-    facterInfo = {}
-    try:
-      if os.path.exists(facterHome):
-        rubyLib = ""
-        if os.environ.has_key("RUBYLIB"):
-          rubyLib = os.environ["RUBYLIB"]
-          logger.info("RUBYLIB from Env " + rubyLib)
-        if not (self.facterLib(facterHome) in rubyLib):
-          rubyLib = rubyLib + ":" + self.facterLib(facterHome)
-        
-        facterEnv["RUBYLIB"] = rubyLib
-        facterEnv = self.configureEnviron(facterEnv)
-        logger.info("Setting RUBYLIB as: " + rubyLib)
-        facter = subprocess.Popen([self.facterBin(facterHome)],
-                                  stdout=subprocess.PIPE,
-                                  stderr=subprocess.PIPE,
-                                  env=facterEnv)
-        stderr_out = facter.communicate()
-        if facter.returncode != 0:
-          logging.error("Error getting facter info: " + stderr_out[1])
-          pass
-        facterOutput = stderr_out[0]
-        infoDict = self.parseFacterOutput(facterOutput)
-        facterInfo = infoDict
-        pass
-      else:
-        logger.error("Facter home at " + facterHome + " does not exist")
-    except:
-      logger.info("Traceback " + traceback.format_exc())
-      pass
-    return facterInfo
-  
   def get(self):
     return self.hardware
 
 def main(argv=None):
-  hardware = Hardware(AmbariConfig.config)
+  hardware = Hardware()
   print hardware.get()
 
 if __name__ == '__main__':

http://git-wip-us.apache.org/repos/asf/ambari/blob/f3afbc70/ambari-agent/src/main/python/ambari_agent/Register.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/Register.py b/ambari-agent/src/main/python/ambari_agent/Register.py
index 2be489d..dbf0ef1 100644
--- a/ambari-agent/src/main/python/ambari_agent/Register.py
+++ b/ambari-agent/src/main/python/ambari_agent/Register.py
@@ -31,7 +31,7 @@ class Register:
   """ Registering with the server. Get the hardware profile and 
   declare success for now """
   def __init__(self, config):
-    self.hardware = Hardware(config)
+    self.hardware = Hardware()
     self.config = config
 
   def build(self, id='-1'):

http://git-wip-us.apache.org/repos/asf/ambari/blob/f3afbc70/ambari-agent/src/test/python/ambari_agent/TestHardware.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestHardware.py b/ambari-agent/src/test/python/ambari_agent/TestHardware.py
index 03c9afc..e4937ec 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestHardware.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestHardware.py
@@ -18,17 +18,14 @@ See the License for the specific language governing permissions and
 limitations under the License.
 '''
 
-import subprocess, os
-import tempfile
 from unittest import TestCase
 from ambari_agent.Hardware import Hardware
-from mock.mock import MagicMock, patch, ANY
-import mock.mock
-from AmbariConfig import AmbariConfig
+from mock.mock import patch
+from ambari_agent.Facter import Facter
 
 class TestHardware(TestCase):
   def test_build(self):
-    hardware = Hardware(AmbariConfig().getConfig())
+    hardware = Hardware()
     result = hardware.get()
     osdisks = hardware.osdisks()
     for dev_item in result['mounts']:
@@ -51,91 +48,6 @@ class TestHardware(TestCase):
 
     self.assertTrue(len(result['mounts']) == len(osdisks))
 
-
-  @patch.object(subprocess, "Popen")
-  @patch.object(Hardware, "facterLib")
-  @patch("os.path.exists")
-  def test_facterInfo(self, os_path_exists_mock, hardware_facterLib_mock, subprocess_popen_mock):
-    config = AmbariConfig().getConfig()
-    tmp_dir = tempfile.gettempdir()
-    config.set("puppet", "facter_home", tmp_dir)
-    hardware = Hardware(config)
-    facter = MagicMock()
-    facter.communicate.return_value = ["memoryfree => 1 GB\n memorysize => 25 MB\n memorytotal => 300 KB\n "
-                                        + "physicalprocessorcount => 25\n is_virtual => true\n", "no errors"]
-    facter.returncode = 0
-    os.environ['RUBYLIB'] = tmp_dir;
-    subprocess_popen_mock.return_value = facter
-    os_path_exists_mock.return_value = True
-    hardware_facterLib_mock.return_value = "bla bla bla"
-    facterInfo = hardware.facterInfo()
-
-    self.assertEquals(facterInfo['memoryfree'], 1048576L)
-    self.assertEquals(facterInfo['memorysize'], 25600L)
-    self.assertEquals(facterInfo['memorytotal'], 300L)
-    self.assertEquals(facterInfo['physicalprocessorcount'], 25)
-    self.assertTrue(facterInfo['is_virtual'])
-    self.assertEquals(subprocess_popen_mock.call_args[1]['env']['RUBYLIB'],
-                      tmp_dir + ":" + "bla bla bla")
-
-    facter.communicate.return_value = ["memoryfree => 1 G\n memorysize => 25 M\n memorytotal => 300 K\n "
-                                         + "someinfo => 12 Byte\n ssh_name_key => Aa06Fdd\n", "no errors"]
-    facterInfo = hardware.facterInfo()
-    facter.returncode = 1
-    self.assertEquals(facterInfo['memoryfree'], 1048576L)
-    self.assertEquals(facterInfo['memorysize'], 25600L)
-    self.assertEquals(facterInfo['memorytotal'], 300L)
-    self.assertEquals(facterInfo['someinfo'], '12 Byte')
-    self.assertFalse(facterInfo.has_key('ssh_name_key'))
-
-    facter.communicate.return_value = ["memoryfree => 1024 M B\n memorytotal => 1024 Byte" , "no errors"]
-
-    facterInfo = hardware.facterInfo()
-
-    self.assertEquals(facterInfo['memoryfree'], 1L)
-    self.assertEquals(facterInfo['memorytotal'], 1L)
-
-    os_path_exists_mock.return_value = False
-    facterInfo = hardware.facterInfo()
-
-    self.assertEquals(facterInfo, {})
-
-
-  @patch("os.path.exists")
-  def test_facterBin(self, ps_path_exists_mock):
-    hardware = Hardware(AmbariConfig().getConfig())
-    ps_path_exists_mock.return_value = False
-    result = hardware.facterBin("bla bla bla")
-    self.assertEquals(result, "facter")
-
-    ps_path_exists_mock.return_value = True
-    result = hardware.facterBin("bla bla bla")
-    self.assertEquals(result, "bla bla bla/bin/facter")
-
-
-  @patch("os.path.exists")
-  @patch.dict('os.environ', {"PATH": ""})
-  @patch.object(subprocess, "Popen")
-  @patch.object(Hardware, "facterInfo")
-  def test_configureEnviron(self, hrdware_facterinfo_mock, subproc_popen, os_path_exists_mock):
-    config = AmbariConfig().getConfig()
-    tmpdir = tempfile.gettempdir()
-    config.set("puppet", "ruby_home", tmpdir)
-    hardware = Hardware(config)
-    os_path_exists_mock.return_value = True
-    result = hardware.configureEnviron({'PATH': ""})
-
-    self.assertEquals(result['PATH'], tmpdir + "/bin:")
-    self.assertEquals(result['MY_RUBY_HOME'], tmpdir)
-    config.remove_option("puppet", "ruby_home")
-
-
-  def test_facterLib(self):
-    hardware = Hardware(AmbariConfig().getConfig())
-    facterLib = hardware.facterLib("/home")
-    self.assertEquals(facterLib, "/home/lib/")
-
-
   def test_extractMountInfo(self):
     outputLine = "device type size used available percent mountpoint"
     result = Hardware.extractMountInfo(outputLine)
@@ -163,6 +75,83 @@ class TestHardware(TestCase):
 
     self.assertEquals(result, None)
 
-
+  @patch.object(Facter, "getFqdn")
+  def test_fqdnDomainHostname(self, facter_getFqdn_mock):
+    facter_getFqdn_mock.return_value = "ambari.apache.org"
+    result = Facter().facterInfo()
+
+    self.assertEquals(result['hostname'], "ambari")
+    self.assertEquals(result['domain'], "apache.org")
+    self.assertEquals(result['fqdn'], (result['hostname'] + '.' + result['domain']))
+
+  @patch.object(Facter, "setDataUpTimeOutput")
+  def test_uptimeSecondsHoursDays(self, facter_setDataUpTimeOutput_mock):
+    # 3 days + 1 hour + 13 sec
+    facter_setDataUpTimeOutput_mock.return_value = "262813.00 123.45"
+    result = Facter().facterInfo()
+
+    self.assertEquals(result['uptime_seconds'], '262813')
+    self.assertEquals(result['uptime_hours'], '73')
+    self.assertEquals(result['uptime_days'], '3')
+
+  @patch.object(Facter, "setMemInfoOutput")
+  def test_facterMemInfoOutput(self, facter_setMemInfoOutput_mock):
+
+    facter_setMemInfoOutput_mock.return_value = '''
+MemTotal:        1832392 kB
+MemFree:          868648 kB
+HighTotal:             0 kB
+HighFree:              0 kB
+LowTotal:        1832392 kB
+LowFree:          868648 kB
+SwapTotal:       2139592 kB
+SwapFree:        1598676 kB
+    '''
+
+    result = Facter().facterInfo()
+
+    self.assertEquals(result['memorysize'], 1832392)
+    self.assertEquals(result['memorytotal'], 1832392)
+    self.assertEquals(result['memoryfree'], 868648)
+    self.assertEquals(result['swapsize'], '2.04 GB')
+    self.assertEquals(result['swapfree'], '1.52 GB')
+
+  @patch.object(Facter, "setDataIfConfigOutput")
+  def test_facterDataIfConfigOutput(self, facter_setDataIfConfigOutput_mock):
+
+    facter_setDataIfConfigOutput_mock.return_value = '''
+eth0      Link encap:Ethernet  HWaddr 08:00:27:C9:39:9E
+          inet addr:10.0.2.15  Bcast:10.0.2.255  Mask:255.255.255.0
+          inet6 addr: fe80::a00:27ff:fec9:399e/64 Scope:Link
+          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
+          RX packets:7575 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:3463 errors:0 dropped:0 overruns:0 carrier:0
+          collisions:0 txqueuelen:1000
+          RX bytes:9383574 (8.9 MiB)  TX bytes:231609 (226.1 KiB)
+
+eth1      Link encap:Ethernet  HWaddr 08:00:27:9A:9A:45
+          inet addr:192.168.64.101  Bcast:192.168.64.255  Mask:255.255.255.0
+          inet6 addr: fe80::a00:27ff:fe9a:9a45/64 Scope:Link
+          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
+          RX packets:180 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:89 errors:0 dropped:0 overruns:0 carrier:0
+          collisions:0 txqueuelen:1000
+          RX bytes:18404 (17.9 KiB)  TX bytes:17483 (17.0 KiB)
+
+lo        Link encap:Local Loopback
+          inet addr:127.0.0.1  Mask:255.0.0.0
+          inet6 addr: ::1/128 Scope:Host
+          UP LOOPBACK RUNNING  MTU:16436  Metric:1
+          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
+          collisions:0 txqueuelen:0
+          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)
+    '''
+
+    result = Facter().facterInfo()
+
+    self.assertEquals(result['ipaddress'], '10.0.2.15')
+    self.assertEquals(result['netmask'], '255.255.255.0')
+    self.assertEquals(result['interfaces'], 'eth0,eth1,lo')