blob: 7e92c1b68f644e7ae64323c77922cfced9cf1ea7 [file] [log] [blame]
#!/usr/bin/env ambari-python-wrap
'''
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 hostname
import re
import shlex
import socket
import multiprocessing
import subprocess
from ambari_commons.shell import shellRunner
import time
import uuid
import json
import glob
from AmbariConfig import AmbariConfig
from ambari_commons import OSCheck, OSConst
from ambari_commons.os_family_impl import OsFamilyImpl
log = logging.getLogger()
def run_os_command(cmd):
shell = (type(cmd) == str)
process = subprocess.Popen(cmd,
shell=shell,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE
)
(stdoutdata, stderrdata) = process.communicate()
return process.returncode, stdoutdata, stderrdata
class Facter(object):
def __init__(self, config):
"""
Initialize the configs, which can be provided if using multiple Agents per host.
:param config: Agent configs. None if will use the default location.
"""
self.config = config if config is not None else self.resolve_ambari_config()
def resolve_ambari_config(self):
"""
Resolve the default Ambari Agent configs.
:return: The default configs.
"""
try:
config = AmbariConfig()
if os.path.exists(AmbariConfig.getConfigFile()):
config.read(AmbariConfig.getConfigFile())
else:
raise Exception("No config found, use default")
except Exception, err:
log.warn(err)
return config
# Return first ip adress
def getIpAddress(self):
return socket.gethostbyname(self.getFqdn().lower())
# Returns the currently running user id
def getId(self):
return getpass.getuser()
# Returns the OS name
def getKernel(self):
return platform.system()
# 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 self.getFqdn().split('.', 1)[0]
# Returns the CPU hardware architecture
def getArchitecture(self):
result = platform.processor()
if not result:
retcode, out, err = run_os_command("lscpu | grep Architecture: | awk '{ print $2 }'")
out = out.strip()
if out:
return out
return 'unknown cpu arch'
else:
return result
# Returns the full name of the OS
def getOperatingSystem(self):
return OSCheck.get_os_type()
# Returns the OS version
def getOperatingSystemRelease(self):
return OSCheck.get_os_version()
# 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):
return OSCheck.get_os_family()
# Return uptime hours
def getUptimeHours(self):
return self.getUptimeSeconds() / (60 * 60)
# Return uptime days
def getUptimeDays(self):
return self.getUptimeSeconds() / (60 * 60 * 24)
def getSystemResourceIfExists(self, systemResources, key, default):
if key in systemResources:
return systemResources[key]
else:
return default
def replaceFacterInfoWithSystemResources(self, systemResources, facterInfo):
"""
Replace facter info with fake system resource data (if there are any).
"""
for key in facterInfo:
facterInfo[key] = self.getSystemResourceIfExists(systemResources, key, facterInfo[key])
return facterInfo
def getSystemResourceOverrides(self):
"""
Read all json files from 'system_resource_overrides' directory, and later these values are used as
fake system data for hosts. In case of the key-value pairs cannot be loaded use default behaviour.
"""
systemResources = {}
if self.config.has_option('agent', 'system_resource_overrides'):
systemResourceDir = self.config.get('agent', 'system_resource_overrides', '').strip()
if systemResourceDir:
if os.path.isdir(systemResourceDir) and os.path.exists(systemResourceDir):
try:
for filename in glob.glob('%s/*.json' % systemResourceDir):
with open(filename) as fp:
data = json.loads(fp.read())
for (key, value) in data.items():
systemResources[key] = data[key]
except:
log.warn(
"Cannot read values from json files in %s. it won't be used for gathering system resources." % systemResourceDir)
else:
log.info(
"Directory: '%s' does not exist - it won't be used for gathering system resources." % systemResourceDir)
else:
log.info("'system_resource_dir' is not set - it won't be used for gathering system resources.")
return systemResources
def getFqdn(self):
raise NotImplementedError()
def getNetmask(self):
raise NotImplementedError()
def getInterfaces(self):
raise NotImplementedError()
def getUptimeSeconds(self):
raise NotImplementedError()
def getMemorySize(self):
raise NotImplementedError()
def getMemoryFree(self):
raise NotImplementedError()
def getMemoryTotal(self):
raise NotImplementedError()
def facterInfo(self):
return {
'id': self.getId(),
'kernel': self.getKernel(),
'domain': self.getDomain(),
'fqdn': self.getFqdn(),
'hostname': self.getHostname(),
'macaddress': self.getMacAddress(),
'architecture': self.getArchitecture(),
'operatingsystem': self.getOperatingSystem(),
'operatingsystemrelease': self.getOperatingSystemRelease(),
'physicalprocessorcount': self.getProcessorcount(),
'processorcount': self.getProcessorcount(),
'timezone': self.getTimeZone(),
'hardwareisa': self.getArchitecture(),
'hardwaremodel': self.getArchitecture(),
'kernelrelease': self.getKernelRelease(),
'kernelversion': self.getKernelVersion(),
'osfamily': self.getOsFamily(),
'kernelmajversion': self.getKernelMajVersion(),
'ipaddress': self.getIpAddress(),
'netmask': self.getNetmask(),
'interfaces': self.getInterfaces(),
'uptime_seconds': str(self.getUptimeSeconds()),
'uptime_hours': str(self.getUptimeHours()),
'uptime_days': str(self.getUptimeDays()),
'memorysize': self.getMemorySize(),
'memoryfree': self.getMemoryFree(),
'memorytotal': self.getMemoryTotal()
}
#Convert kB to GB
@staticmethod
def convertSizeKbToGb(size):
return "%0.2f GB" % round(float(size) / (1024.0 * 1024.0), 2)
#Convert MB to GB
@staticmethod
def convertSizeMbToGb(size):
return "%0.2f GB" % round(float(size) / (1024.0), 2)
@OsFamilyImpl(os_family=OSConst.WINSRV_FAMILY)
class FacterWindows(Facter):
GET_SYSTEM_INFO_CMD = "systeminfo"
GET_MEMORY_CMD = '$mem =(Get-WMIObject Win32_OperatingSystem -ComputerName "LocalHost" ); echo "$($mem.FreePhysicalMemory) $($mem.TotalVisibleMemorySize)"'
GET_PAGE_FILE_INFO = '$pgo=(Get-WmiObject Win32_PageFileUsage); echo "$($pgo.AllocatedBaseSize) $($pgo.AllocatedBaseSize-$pgo.CurrentUsage)"'
GET_UPTIME_CMD = 'echo $([int]((get-date)-[system.management.managementdatetimeconverter]::todatetime((get-wmiobject -class win32_operatingsystem).Lastbootuptime)).TotalSeconds)'
# Returns the FQDN of the host
def getFqdn(self):
return socket.getfqdn().lower()
# Return netmask
def getNetmask(self):
#TODO return correct netmask
return 'OS NOT SUPPORTED'
# Return interfaces
def getInterfaces(self):
#TODO return correct interfaces
return 'OS NOT SUPPORTED'
# Return uptime seconds
def getUptimeSeconds(self):
try:
runner = shellRunner()
result = runner.runPowershell(script_block=FacterWindows.GET_UPTIME_CMD).output.replace('\n', '').replace('\r',
'')
return int(result)
except:
log.warn("Can not get SwapFree")
return 0
# Return memoryfree
def getMemoryFree(self):
try:
runner = shellRunner()
result = runner.runPowershell(script_block=FacterWindows.GET_MEMORY_CMD).output.split(" ")[0].replace('\n',
'').replace(
'\r', '')
return result
except:
log.warn("Can not get MemoryFree")
return 0
# Return memorytotal
def getMemoryTotal(self):
try:
runner = shellRunner()
result = runner.runPowershell(script_block=FacterWindows.GET_MEMORY_CMD).output.split(" ")[-1].replace('\n',
'').replace(
'\r', '')
return result
except:
log.warn("Can not get MemoryTotal")
return 0
# Return swapfree
def getSwapFree(self):
try:
runner = shellRunner()
result = runner.runPowershell(script_block=FacterWindows.GET_PAGE_FILE_INFO).output.split(" ")[-1].replace('\n',
'').replace(
'\r', '')
return result
except:
log.warn("Can not get SwapFree")
return 0
# Return swapsize
def getSwapSize(self):
try:
runner = shellRunner()
result = runner.runPowershell(script_block=FacterWindows.GET_PAGE_FILE_INFO).output.split(" ")[0].replace('\n',
'').replace(
'\r', '')
return result
except:
log.warn("Can not get SwapFree")
return 0
# Return memorysize
def getMemorySize(self):
try:
runner = shellRunner()
result = runner.runPowershell(script_block=FacterWindows.GET_MEMORY_CMD).output.split(" ")[-1].replace('\n',
'').replace(
'\r', '')
return result
except:
log.warn("Can not get MemorySize")
return 0
def facterInfo(self):
facterInfo = super(FacterWindows, self).facterInfo()
systemResourceOverrides = self.getSystemResourceOverrides()
facterInfo = self.replaceFacterInfoWithSystemResources(systemResourceOverrides, facterInfo)
facterInfo['swapsize'] = Facter.convertSizeMbToGb(
self.getSystemResourceIfExists(systemResourceOverrides, 'swapsize', self.getSwapSize()))
facterInfo['swapfree'] = Facter.convertSizeMbToGb(
self.getSystemResourceIfExists(systemResourceOverrides, 'swapfree', self.getSwapFree()))
return facterInfo
@OsFamilyImpl(os_family=OsFamilyImpl.DEFAULT)
class FacterLinux(Facter):
# selinux command
GET_SE_LINUX_ST_CMD = "/usr/sbin/sestatus"
GET_IFCONFIG_SHORT_CMD = "ifconfig -s"
GET_IP_LINK_CMD = "ip link"
GET_UPTIME_CMD = "cat /proc/uptime"
GET_MEMINFO_CMD = "cat /proc/meminfo"
def __init__(self, config):
super(FacterLinux,self).__init__(config)
self.DATA_IFCONFIG_SHORT_OUTPUT = FacterLinux.setDataIfConfigShortOutput()
self.DATA_IP_LINK_OUTPUT = FacterLinux.setDataIpLinkOutput()
self.DATA_UPTIME_OUTPUT = FacterLinux.setDataUpTimeOutput()
self.DATA_MEMINFO_OUTPUT = FacterLinux.setMemInfoOutput()
# Returns the output of `ifconfig -s` command
@staticmethod
def setDataIfConfigShortOutput():
try:
result = os.popen(FacterLinux.GET_IFCONFIG_SHORT_CMD).read()
return result
except OSError:
log.warn("Can't execute {0}".format(FacterLinux.GET_IFCONFIG_SHORT_CMD))
return ""
# Returns the output of `ip link` command
@staticmethod
def setDataIpLinkOutput():
try:
result = os.popen(FacterLinux.GET_IP_LINK_CMD).read()
return result
except OSError:
log.warn("Can't execute {0}".format(FacterLinux.GET_IP_LINK_CMD))
return ""
@staticmethod
def setDataUpTimeOutput():
try:
result = os.popen(FacterLinux.GET_UPTIME_CMD).read()
return result
except OSError:
log.warn("Can't execute {0}".format(FacterLinux.GET_UPTIME_CMD))
return ""
@staticmethod
def setMemInfoOutput():
try:
result = os.popen(FacterLinux.GET_MEMINFO_CMD).read()
return result
except OSError:
log.warn("Can't execute {0}".format(FacterLinux.GET_MEMINFO_CMD))
return ""
# Returns the FQDN of the host
def getFqdn(self):
return hostname.hostname(self.config)
def isSeLinux(self):
try:
retcode, out, err = run_os_command(FacterLinux.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(FacterLinux.GET_SE_LINUX_ST_CMD))
return False
def return_first_words_from_list(self, list):
result = ""
for i in list:
if i.strip():
result = result + i.split()[0].strip() + ","
result = re.sub(r',$', "", result)
return result
def return_ifnames_from_ip_link(self, ip_link_output):
list = []
prog = re.compile("^\d")
for line in ip_link_output.splitlines():
if prog.match(line):
list.append(line.split()[1].rstrip(":"))
return ",".join(list)
def data_return_first(self, patern, data):
full_list = re.findall(patern, data)
result = ""
if full_list:
result = full_list[0]
return result
# Return netmask
def getNetmask(self):
import fcntl
import struct
primary_ip = self.getIpAddress().strip()
for ifname in self.getInterfaces().split(","):
if ifname.strip():
ip_address_by_ifname = self.get_ip_address_by_ifname(ifname)
if ip_address_by_ifname is not None:
if primary_ip == ip_address_by_ifname.strip():
return socket.inet_ntoa(fcntl.ioctl(socket.socket(socket.AF_INET, socket.SOCK_DGRAM), 35099, struct.pack('256s', ifname))[20:24])
return None
# Return IP by interface name
def get_ip_address_by_ifname(self, ifname):
import fcntl
import struct
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip_address_by_ifname = None
try:
ip_address_by_ifname = socket.inet_ntoa(fcntl.ioctl(
s.fileno(),
0x8915, # SIOCGIFADDR
struct.pack('256s', ifname[:15])
)[20:24])
except Exception, err:
log.warn("Can't get the IP address for {0}".format(ifname))
return ip_address_by_ifname
# Return interfaces
def getInterfaces(self):
result = self.return_first_words_from_list(self.DATA_IFCONFIG_SHORT_OUTPUT.splitlines()[1:])
# If the host has `ifconfig` command, then return that result.
if result != '':
return result
# If the host has `ip` command, then return that result.
result = self.return_ifnames_from_ip_link(self.DATA_IP_LINK_OUTPUT)
if result != '':
return result
# If the host has neither `ifocnfig` command nor `ip` command, then return "OS NOT SUPPORTED"
log.warn("Can't get a network interfaces list from {0}".format(self.DATA_IFCONFIG_SHORT_OUTPUT))
return 'OS NOT SUPPORTED'
# Return uptime seconds
def getUptimeSeconds(self):
try:
return int(self.data_return_first("\d+", self.DATA_UPTIME_OUTPUT))
except ValueError:
log.warn("Can't get an uptime value from {0}".format(self.DATA_UPTIME_OUTPUT))
return 0
# Return memoryfree
def getMemoryFree(self):
#:memoryfree_mb => "MemFree",
try:
return int(self.data_return_first("MemFree:.*?(\d+) .*", self.DATA_MEMINFO_OUTPUT))
except ValueError:
log.warn("Can't get free memory size from {0}".format(self.DATA_MEMINFO_OUTPUT))
return 0
# Return memorytotal
def getMemoryTotal(self):
try:
return int(self.data_return_first("MemTotal:.*?(\d+) .*", self.DATA_MEMINFO_OUTPUT))
except ValueError:
log.warn("Can't get total memory size from {0}".format(self.DATA_MEMINFO_OUTPUT))
return 0
# Return swapfree
def getSwapFree(self):
#:swapfree_mb => "SwapFree"
try:
return int(self.data_return_first("SwapFree:.*?(\d+) .*", self.DATA_MEMINFO_OUTPUT))
except ValueError:
log.warn("Can't get free swap memory size from {0}".format(self.DATA_MEMINFO_OUTPUT))
return 0
# Return swapsize
def getSwapSize(self):
#:swapsize_mb => "SwapTotal",
try:
return int(self.data_return_first("SwapTotal:.*?(\d+) .*", self.DATA_MEMINFO_OUTPUT))
except ValueError:
log.warn("Can't get total swap memory size from {0}".format(self.DATA_MEMINFO_OUTPUT))
return 0
# Return memorysize
def getMemorySize(self):
#:memorysize_mb => "MemTotal"
try:
return int(self.data_return_first("MemTotal:.*?(\d+) .*", self.DATA_MEMINFO_OUTPUT))
except ValueError:
log.warn("Can't get memory size from {0}".format(self.DATA_MEMINFO_OUTPUT))
return 0
def facterInfo(self):
facterInfo = super(FacterLinux, self).facterInfo()
systemResourceOverrides = self.getSystemResourceOverrides()
facterInfo = self.replaceFacterInfoWithSystemResources(systemResourceOverrides, facterInfo)
facterInfo['selinux'] = self.isSeLinux()
facterInfo['swapsize'] = Facter.convertSizeKbToGb(
self.getSystemResourceIfExists(systemResourceOverrides, 'swapsize', self.getSwapSize()))
facterInfo['swapfree'] = Facter.convertSizeKbToGb(
self.getSystemResourceIfExists(systemResourceOverrides, 'swapfree', self.getSwapFree()))
return facterInfo
def main(argv=None):
config = None
print Facter(config).facterInfo()
if __name__ == '__main__':
main()