@ -42,272 +42,539 @@ try:
except ImportError:
except ImportError:
import simplejson as json
import simplejson as json
_I386RE = re.compile(r'i[3456]86')
class Facts(object):
SIOCGIFCONF = 0x8912
"""
SIOCGIFHWADDR = 0x8927
This class should only attempt to populate those facts that
MEMORY_FACTS = ['MemTotal', 'SwapTotal', 'MemFree', 'SwapFree']
are mostly generic to all systems. This includes platform facts,
# DMI bits
service facts (eg. ssh keys or selinux), and distribution facts.
DMI_DICT = { 'form_factor': '/sys/devices/virtual/dmi/id/chassis_type',
Anything that requires extensive code or may have more than one
'product_name': '/sys/devices/virtual/dmi/id/product_name',
possible implementation to establish facts for a given topic should
'product_serial': '/sys/devices/virtual/dmi/id/product_serial',
subclass Facts.
'product_uuid': '/sys/devices/virtual/dmi/id/product_uuid',
"""
'product_version': '/sys/devices/virtual/dmi/id/product_version',
'system_vendor': '/sys/devices/virtual/dmi/id/sys_vendor',
_I386RE = re.compile(r'i[3456]86')
'bios_date': '/sys/devices/virtual/dmi/id/bios_date',
# For the most part, we assume that platform.dist() will tell the truth.
'bios_version': '/sys/devices/virtual/dmi/id/bios_version' }
# This is the fallback to handle unknowns or exceptions
# From smolt and DMI spec
OSDIST_DICT = { '/etc/redhat-release': 'RedHat',
FORM_FACTOR = [ "Unknown", "Other", "Unknown", "Desktop",
'/etc/vmware-release': 'VMwareESX' }
"Low Profile Desktop", "Pizza Box", "Mini Tower", "Tower",
SELINUX_MODE_DICT = { 1: 'enforcing', 0: 'permissive', -1: 'disabled' }
"Portable", "Laptop", "Notebook", "Hand Held", "Docking Station",
"All In One", "Sub Notebook", "Space-saving", "Lunch Box",
def __init__(self, facts):
"Main Server Chassis", "Expansion Chassis", "Sub Chassis",
self.facts = facts
"Bus Expansion Chassis", "Peripheral Chassis", "RAID Chassis",
"Rack Mount Chassis", "Sealed-case PC", "Multi-system",
def populate(self):
"CompactPCI", "AdvancedTCA" ]
self.get_platform_facts()
# For the most part, we assume that platform.dist() will tell the truth.
self.get_distribution_facts()
# This is the fallback to handle unknowns or exceptions
self.get_public_ssh_host_keys()
OSDIST_DICT = { '/etc/redhat-release': 'RedHat',
self.get_selinux_facts()
'/etc/vmware-release': 'VMwareESX' }
SELINUX_MODE_DICT = { 1: 'enforcing', 0: 'permissive', -1: 'disabled' }
# Platform
# patform.system() can be Linux, Darwin, Java, or Windows
def get_file_content(path):
def get_platform_facts(self):
if os.path.exists(path) and os.access(path, os.R_OK):
self.facts['system'] = platform.system()
data = open(path).read().strip()
self.facts['kernel'] = platform.release()
if len(data) == 0:
self.facts['machine'] = platform.machine()
data = None
self.facts['python_version'] = platform.python_version()
else:
self.facts['fqdn'] = socket.getfqdn()
data = None
self.facts['hostname'] = self.facts['fqdn'].split('.')[0]
return data
if self.facts['machine'] == 'x86_64':
self.facts['architecture'] = self.facts['machine']
# platform.dist() is deprecated in 2.6
elif Facts._I386RE.search(self.facts['machine']):
# in 2.6 and newer, you should use platform.linux_distribution()
self.facts['architecture'] = 'i386'
def get_distribution_facts(facts):
else:
dist = platform.dist()
self.facts['archtecture'] = self.facts['machine']
facts['distribution'] = dist[0].capitalize() or 'NA'
if self.facts['system'] == 'Linux':
facts['distribution_version'] = dist[1] or 'NA'
self.get_distribution_facts()
facts['distribution_release'] = dist[2] or 'NA'
# Try to handle the exceptions now ...
# platform.dist() is deprecated in 2.6
for (path, name) in OSDIST_DICT.items():
# in 2.6 and newer, you should use platform.linux_distribution()
if os.path.exists(path):
def get_distribution_facts(self):
if facts['distribution'] == 'Fedora':
dist = platform.dist()
pass
self.facts['distribution'] = dist[0].capitalize() or 'NA'
elif name == 'RedHat':
self.facts['distribution_version'] = dist[1] or 'NA'
data = get_file_content(path)
self.facts['distribution_release'] = dist[2] or 'NA'
if 'Red Hat' in data:
# Try to handle the exceptions now ...
facts['distribution'] = name
for (path, name) in Facts.OSDIST_DICT.items():
if os.path.exists(path):
if self.facts['distribution'] == 'Fedora':
pass
elif name == 'RedHat':
data = get_file_content(path)
if 'Red Hat' in data:
self.facts['distribution'] = name
else:
self.facts['distribution'] = data.split()[0]
else:
else:
facts['distribution'] = data.split()[0]
self.facts['distribution'] = name
else:
facts['distribution'] = name
def get_public_ssh_host_keys(self):
dsa = get_file_content('/etc/ssh/ssh_host_dsa_key.pub')
# Platform
rsa = get_file_content('/etc/ssh/ssh_host_rsa_key.pub')
# patform.system() can be Linux, Darwin, Java, or Windows
if dsa is None:
def get_platform_facts(facts):
dsa = 'NA'
facts['system'] = platform.system()
else:
facts['kernel'] = platform.release()
self.facts['ssh_host_key_dsa_public'] = dsa.split()[1]
facts['machine'] = platform.machine()
if rsa is None:
facts['python_version'] = platform.python_version()
rsa = 'NA'
if facts['machine'] == 'x86_64':
else:
facts['architecture'] = facts['machine']
self.facts['ssh_host_key_rsa_public'] = rsa.split()[1]
elif _I386RE.search(facts['machine']):
facts['architecture'] = 'i386'
def get_selinux_facts(self):
else:
if not HAVE_SELINUX:
facts['archtecture'] = facts['machine']
self.facts['selinux'] = False
if facts['system'] == 'Linux':
return
get_distribution_facts(facts)
self.facts['selinux'] = {}
if not selinux.is_selinux_enabled():
def get_memory_facts(facts):
self.facts['selinux']['status'] = 'disabled'
if not os.access("/proc/meminfo", os.R_OK):
else:
return facts
self.facts['selinux']['status'] = 'enabled'
for line in open("/proc/meminfo").readlines():
self.facts['selinux']['policyvers'] = selinux.security_policyvers()
data = line.split(":", 1)
(rc, configmode) = selinux.selinux_getenforcemode()
key = data[0]
if rc == 0 and Facts.SELINUX_MODE_DICT.has_key(configmode):
if key in MEMORY_FACTS:
self.facts['selinux']['config_mode'] = Facts.SELINUX_MODE_DICT[configmode]
val = data[1].strip().split(' ')[0]
mode = selinux.security_getenforce()
facts["%s_mb" % key.lower()] = long(val) / 1024
if Facts.SELINUX_MODE_DICT.has_key(mode):
self.facts['selinux']['mode'] = Facts.SELINUX_MODE_DICT[mode]
def get_cpu_facts(facts):
(rc, policytype) = selinux.selinux_getpolicytype()
i = 0
if rc == 0:
physid = 0
self.facts['selinux']['type'] = policytype
sockets = {}
if not os.access("/proc/cpuinfo", os.R_OK):
class Hardware(Facts):
return facts
"""
for line in open("/proc/cpuinfo").readlines():
This is a generic Hardware subclass of Facts. This should be further
data = line.split(":", 1)
subclassed to implement per platform. If you subclass this, it
key = data[0].strip()
should define:
if key == 'model name':
- memfree_mb
if 'processor' not in facts:
- memtotal_mb
facts['processor'] = []
- swapfree_mb
facts['processor'].append(data[1].strip())
- swaptotal_mb
i += 1
- processor (a list)
elif key == 'physical id':
- processor_cores
physid = data[1].strip()
- processor_count
if physid not in sockets:
sockets[physid] = 1
All subclasses MUST define platform.
elif key == 'cpu cores':
"""
sockets[physid] = int(data[1].strip())
platform = 'Generic'
if len(sockets) > 0:
facts['processor_count'] = len(sockets)
def __new__(cls, facts, *arguments, **keyword):
facts['processor_cores'] = reduce(lambda x, y: x + y, sockets.values())
subclass = cls
else:
for sc in Hardware.__subclasses__():
facts['processor_count'] = i
if sc.platform == platform.system():
facts['processor_cores'] = 'NA'
subclass = sc
return super(cls, subclass).__new__(subclass, *arguments, **keyword)
def get_hardware_facts(facts):
get_memory_facts(facts)
def __init__(self, facts):
get_cpu_facts(facts)
Facts.__init__(self, facts)
for (key,path) in DMI_DICT.items():
self.facts['memfree_mb'] = 'NA'
data = get_file_content(path)
self.facts['memtotal_mb'] = 'NA'
if data is not None:
self.facts['swapfree_mb'] = 'NA'
if key == 'form_factor':
self.facts['swaptotal_mb'] = 'NA'
facts['form_factor'] = FORM_FACTOR[int(data)]
self.facts['processor'] = ['NA']
else:
self.facts['processor_cores'] = 'NA'
facts[key] = data
self.facts['processor_count'] = 'NA'
def populate(self):
pass
class LinuxHardware(Hardware):
"""
Linux-specific subclass of Hardware. Defines memory and CPU facts:
- memfree_mb
- memtotal_mb
- swapfree_mb
- swaptotal_mb
- processor (a list)
- processor_cores
- processor_count
In addition, it also defines number of DMI facts.
"""
platform = 'Linux'
MEMORY_FACTS = ['MemTotal', 'SwapTotal', 'MemFree', 'SwapFree']
# DMI bits
DMI_DICT = { 'form_factor': '/sys/devices/virtual/dmi/id/chassis_type',
'product_name': '/sys/devices/virtual/dmi/id/product_name',
'product_serial': '/sys/devices/virtual/dmi/id/product_serial',
'product_uuid': '/sys/devices/virtual/dmi/id/product_uuid',
'product_version': '/sys/devices/virtual/dmi/id/product_version',
'system_vendor': '/sys/devices/virtual/dmi/id/sys_vendor',
'bios_date': '/sys/devices/virtual/dmi/id/bios_date',
'bios_version': '/sys/devices/virtual/dmi/id/bios_version' }
# From smolt and DMI spec
FORM_FACTOR = [ "Unknown", "Other", "Unknown", "Desktop",
"Low Profile Desktop", "Pizza Box", "Mini Tower", "Tower",
"Portable", "Laptop", "Notebook", "Hand Held", "Docking Station",
"All In One", "Sub Notebook", "Space-saving", "Lunch Box",
"Main Server Chassis", "Expansion Chassis", "Sub Chassis",
"Bus Expansion Chassis", "Peripheral Chassis", "RAID Chassis",
"Rack Mount Chassis", "Sealed-case PC", "Multi-system",
"CompactPCI", "AdvancedTCA" ]
def __init__(self, facts):
Hardware.__init__(self, facts)
def populate(self):
self.get_cpu_facts()
self.get_memory_facts()
self.get_dmi_facts()
def get_memory_facts(self):
if not os.access("/proc/meminfo", os.R_OK):
return
for line in open("/proc/meminfo").readlines():
data = line.split(":", 1)
key = data[0]
if key in LinuxHardware.MEMORY_FACTS:
val = data[1].strip().split(' ')[0]
self.facts["%s_mb" % key.lower()] = long(val) / 1024
def get_cpu_facts(self):
i = 0
physid = 0
sockets = {}
if not os.access("/proc/cpuinfo", os.R_OK):
return
self.facts['processor'] = []
for line in open("/proc/cpuinfo").readlines():
data = line.split(":", 1)
key = data[0].strip()
if key == 'model name':
if 'processor' not in self.facts:
self.facts['processor'] = []
self.facts['processor'].append(data[1].strip())
i += 1
elif key == 'physical id':
physid = data[1].strip()
if physid not in sockets:
sockets[physid] = 1
elif key == 'cpu cores':
sockets[physid] = int(data[1].strip())
if len(sockets) > 0:
self.facts['processor_count'] = len(sockets)
self.facts['processor_cores'] = reduce(lambda x, y: x + y, sockets.values())
else:
else:
facts[key] = 'NA'
self.facts['processor_count'] = i
self.facts['processor_cores'] = 'NA'
def get_linux_virtual_facts(facts):
if os.path.exists("/proc/xen"):
def get_dmi_facts(self):
facts['virtualization_type'] = 'xen'
for (key,path) in LinuxHardware.DMI_DICT.items():
facts['virtualization_role'] = 'guest'
data = get_file_content(path)
if os.path.exists("/proc/xen/capabilities"):
if data is not None:
facts['virtualization_role'] = 'host'
if key == 'form_factor':
if os.path.exists("/proc/modules"):
self.facts['form_factor'] = LinuxHardware.FORM_FACTOR[int(data)]
modules = []
else:
for line in open("/proc/modules").readlines():
self.facts[key] = data
data = line.split(" ", 1)
else:
modules.append(data[0])
self.facts[key] = 'NA'
if 'kvm' in modules:
facts['virtualization_type'] = 'kvm'
class SunOSHardware(Hardware):
facts['virtualization_role'] = 'host'
"""
elif 'vboxdrv' in modules:
In addition to the generic memory and cpu facts, this also sets
facts['virtualization_type'] = 'virtualbox'
swap_reserved_mb and swap_allocated_mb that is available from *swap -s*.
facts['virtualization_role'] = 'host'
"""
elif 'vboxguest' in modules:
platform = 'SunOS'
facts['virtualization_type'] = 'virtualbox'
facts['virtualization_role'] = 'guest'
def __init__(self, facts):
if 'QEMU' in facts['processor'][0]:
Hardware.__init__(self, facts)
facts['virtualization_type'] = 'kvm'
facts['virtualization_role'] = 'guest'
def populate(self):
if facts['distribution'] == 'VMwareESX':
self.get_cpu_facts()
facts['virtualization_type'] = 'VMware'
self.get_memory_facts()
facts['virtualization_role'] = 'host'
# You can spawn a dmidecode process and parse that or infer from devices
def get_cpu_facts(self):
for dev_model in glob.glob('/sys/block/?da/device/vendor'):
cmd = subprocess.Popen("/usr/sbin/psrinfo -v", shell=True,
info = open(dev_model).read()
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if 'VMware' in info:
out, err = cmd.communicate()
facts['virtualization_type'] = 'VMware'
self.facts['processor'] = []
facts['virtualization_role'] = 'guest'
for line in out.split('\n'):
elif 'Virtual HD' in info or 'Virtual CD' in info:
if 'processor operates' in line:
facts['virtualization_type'] = 'VirtualPC'
if 'processor' not in self.facts:
facts['virtualization_role'] = 'guest'
self.facts['processor'] = []
self.facts['processor'].append(line.strip())
def get_virtual_facts(facts):
self.facts['processor_cores'] = 'NA'
facts['virtualization_type'] = 'None'
self.facts['processor_count'] = len(self.facts['processor'])
facts['virtualization_role'] = 'None'
if facts['system'] == 'Linux':
def get_memory_facts(self):
facts = get_linux_virtual_facts(facts)
cmd = subprocess.Popen("/usr/sbin/prtconf", shell=False,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# get list of interfaces that are up
out, err = cmd.communicate()
def get_interfaces(facts):
for line in out.split('\n'):
if facts['system'] == 'SunOS':
if 'Memory size' in line:
return []
self.facts['memtotal_mb'] = line.split()[2]
length = 4096
cmd = subprocess.Popen("/usr/sbin/swap -s", shell=True,
offset = 32
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
step = 32
out, err = cmd.communicate()
if platform.architecture()[0] == '64bit':
allocated = long(out.split()[1][:-1])
offset = 16
reserved = long(out.split()[5][:-1])
step = 40
used = long(out.split()[8][:-1])
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
free = long(out.split()[10][:-1])
names = array.array('B', '\0' * length)
self.facts['swapfree_mb'] = free / 1024
bytelen = struct.unpack('iL', fcntl.ioctl(
self.facts['swaptotal_mb'] = (free + used) / 1024
s.fileno(), SIOCGIFCONF, struct.pack(
self.facts['swap_allocated_mb'] = allocated / 1024
'iL', length, names.buffer_info()[0])
self.facts['swap_reserved_mb'] = reserved / 1024
))[0]
return [names.tostring()[i:i+offset].split('\0', 1)[0]
class FreeBSDHardware(Hardware):
for i in range(0, bytelen, step)]
"""
FreeBSD-specific subclass of Hardware. Defines memory and CPU facts:
def get_iface_hwaddr(iface):
- memfree_mb
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- memtotal_mb
info = fcntl.ioctl(s.fileno(), SIOCGIFHWADDR,
- swapfree_mb
struct.pack('256s', iface[:15]))
- swaptotal_mb
return ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1]
- processor (a list)
- processor_cores
def get_network_facts(facts):
- processor_count
facts['fqdn'] = socket.getfqdn()
"""
facts['hostname'] = facts['fqdn'].split('.')[0]
platform = 'FreeBSD'
facts['interfaces'] = get_interfaces(facts)
DMESG_BOOT = '/var/run/dmesg.boot'
for iface in facts['interfaces']:
facts[iface] = { 'macaddress': get_iface_hwaddr(iface) }
def __init__(self, facts):
# This is lame, but there doesn't appear to be a good way
Hardware.__init__(self, facts)
# to get all addresses for both IPv4 and IPv6.
cmd = subprocess.Popen("/sbin/ifconfig %s" % iface, shell=True,
def populate(self):
self.get_cpu_facts()
self.get_memory_facts()
def get_cpu_facts(self):
self.facts['processor'] = []
cmd = subprocess.Popen("/sbin/sysctl -n hw.ncpu", shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = cmd.communicate()
self.facts['processor_count'] = out.strip()
for line in open(FreeBSDHardware.DMESG_BOOT).readlines():
if 'CPU:' in line:
cpu = re.sub(r'CPU:\s+', r"", line)
self.facts['processor'].append(cpu.strip())
if 'Logical CPUs per core' in line:
self.facts['processor_cores'] = line.split()[4]
def get_memory_facts(self):
cmd = subprocess.Popen("/sbin/sysctl vm.stats", shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = cmd.communicate()
out, err = cmd.communicate()
for line in out.split('\n'):
for line in out.split('\n'):
data = line.split()
data = line.split()
if 'inet addr' in line:
if 'vm.stats.vm.v_page_size' in line:
if 'ipv4' not in facts[iface]:
pagesize = long(data[1])
facts[iface]['ipv4'] = {}
if 'vm.stats.vm.v_page_count' in line:
facts[iface]['ipv4'] = { 'address': data[1].split(':')[1],
pagecount = long(data[1])
'netmask': data[-1].split(':')[1] }
if 'vm.stats.vm.v_free_count' in line:
ip = struct.unpack("!L", socket.inet_aton(facts[iface]['ipv4']['address']))[0]
freecount = long(data[1])
mask = struct.unpack("!L", socket.inet_aton(facts[iface]['ipv4']['netmask']))[0]
self.facts['memtotal_mb'] = pagesize * pagecount / 1024 / 1024
facts[iface]['ipv4']['network'] = socket.inet_ntoa(struct.pack("!L", ip & mask))
self.facts['memfree_mb'] = pagesize * freecount / 1024 / 1024
if 'inet6 addr' in line:
# Get swapinfo. swapinfo output looks like:
(ip, prefix) = data[2].split('/')
# Device 1M-blocks Used Avail Capacity
scope = data[3].split(':')[1].lower()
# /dev/ada0p3 314368 0 314368 0%
if 'ipv6' not in facts[iface]:
#
facts[iface]['ipv6'] = []
cmd = subprocess.Popen("/usr/sbin/swapinfo -m", shell=True,
facts[iface]['ipv6'].append( { 'address': ip,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
'prefix': prefix,
out, err = cmd.communicate()
'scope': scope } )
lines = out.split('\n')
return facts
if len(lines[-1]) == 0:
lines.pop()
def get_public_ssh_host_keys(facts):
data = lines[-1].split()
dsa = get_file_content('/etc/ssh/ssh_host_dsa_key.pub')
self.facts['swaptotal_mb'] = data[1]
rsa = get_file_content('/etc/ssh/ssh_host_rsa_key.pub')
self.facts['swapfree_mb'] = data[3]
if dsa is None:
dsa = 'NA'
class Network(Facts):
else:
"""
facts['ssh_host_key_dsa_public'] = dsa.split()[1]
This is a generic Network subclass of Facts. This should be further
if rsa is None:
subclassed to implement per platform. If you subclass this,
rsa = 'NA'
you must define:
else:
- interfaces (a list of interface names)
facts['ssh_host_key_rsa_public'] = rsa.split()[1]
- interface_<name> dictionary of ipv4, ipv6, and mac address information.
def get_selinux_facts(facts):
All subclasses MUST define platform.
if not HAVE_SELINUX:
"""
facts['selinux'] = False
platform = 'Generic'
return
facts['selinux'] = {}
def __new__(cls, facts, *arguments, **keyword):
if not selinux.is_selinux_enabled():
subclass = cls
facts['selinux']['status'] = 'disabled'
for sc in Network.__subclasses__():
else:
if sc.platform == platform.system():
facts['selinux']['status'] = 'enabled'
subclass = sc
facts['selinux']['policyvers'] = selinux.security_policyvers()
return super(cls, subclass).__new__(subclass, *arguments, **keyword)
(rc, configmode) = selinux.selinux_getenforcemode()
if rc == 0 and SELINUX_MODE_DICT.has_key(configmode):
def __init__(self, facts):
facts['selinux']['config_mode'] = SELINUX_MODE_DICT[configmode]
Facts.__init__(self, facts)
mode = selinux.security_getenforce()
self.facts['interfaces'] = ['NA']
if SELINUX_MODE_DICT.has_key(mode):
facts['selinux']['mode'] = SELINUX_MODE_DICT[mode]
def populate(self):
(rc, policytype) = selinux.selinux_getpolicytype()
pass
if rc == 0:
facts['selinux']['type'] = policytype
class LinuxNetwork(Network):
"""
def get_service_facts(facts):
This is a Linux-specific subclass of Network. It defines
get_public_ssh_host_keys(facts)
- interfaces (a list of interface names)
get_selinux_facts(facts)
- interface_<name> dictionary of ipv4, ipv6, and mac address information.
"""
platform = 'Linux'
SIOCGIFCONF = 0x8912
SIOCGIFHWADDR = 0x8927
def __init__(self, facts):
Network.__init__(self, facts)
def populate(self):
self.get_network_facts()
# get list of interfaces that are up
def get_interfaces(self):
length = 4096
offset = 32
step = 32
if platform.architecture()[0] == '64bit':
offset = 16
step = 40
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
names = array.array('B', '\0' * length)
bytelen = struct.unpack('iL', fcntl.ioctl(
s.fileno(), LinuxNetwork.SIOCGIFCONF, struct.pack(
'iL', length, names.buffer_info()[0])
))[0]
return [names.tostring()[i:i+offset].split('\0', 1)[0]
for i in range(0, bytelen, step)]
def get_iface_hwaddr(self, iface):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
info = fcntl.ioctl(s.fileno(), LinuxNetwork.SIOCGIFHWADDR,
struct.pack('256s', iface[:15]))
return ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1]
def get_network_facts(self):
self.facts['interfaces'] = self.get_interfaces()
for iface in self.facts['interfaces']:
self.facts[iface] = { 'macaddress': self.get_iface_hwaddr(iface) }
# This is lame, but there doesn't appear to be a good way
# to get all addresses for both IPv4 and IPv6.
cmd = subprocess.Popen("/sbin/ifconfig %s" % iface, shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = cmd.communicate()
for line in out.split('\n'):
is_ipv4 = False
data = line.split()
if 'inet addr' in line:
if 'ipv4' not in self.facts[iface]:
self.facts[iface]['ipv4'] = {}
is_ipv4 = True
self.facts[iface]['ipv4'] = { 'address': data[1].split(':')[1],
'netmask': data[-1].split(':')[1] }
# Slightly different output in net-tools-1.60-134.20120127git
# Looks like
# inet 192.168.1.2 netmask 255.255.255.0 broadcast 192.168.1.255
elif 'inet ' in line:
is_ipv4 = True
if 'ipv4' not in self.facts[iface]:
self.facts[iface]['ipv4'] = {}
self.facts[iface]['ipv4'] = { 'address': data[1],
'netmask': data[3] }
if is_ipv4:
ip = struct.unpack("!L", socket.inet_aton(self.facts[iface]['ipv4']['address']))[0]
mask = struct.unpack("!L", socket.inet_aton(self.facts[iface]['ipv4']['netmask']))[0]
self.facts[iface]['ipv4']['network'] = socket.inet_ntoa(struct.pack("!L", ip & mask))
if 'inet6 addr' in line:
(ip, prefix) = data[2].split('/')
scope = data[3].split(':')[1].lower()
if 'ipv6' not in self.facts[iface]:
self.facts[iface]['ipv6'] = []
self.facts[iface]['ipv6'].append( { 'address': ip,
'prefix': prefix,
'scope': scope } )
# Slightly different output in net-tools-1.60-134.20120127git
# Looks like
# inet6 fe80::21b:21ff:fe6e:5baa prefixlen 64 scopeid 0x20<link>
elif 'inet6 ' in line:
if 'ipv6' not in self.facts[iface]:
self.facts[iface]['ipv6'] = []
scope = data[5].split('<')[1][:-1]
self.facts[iface]['ipv6'].append( { 'address': data[1],
'prefix': data[3],
'scope': scope } )
class Virtual(Facts):
"""
This is a generic Virtual subclass of Facts. This should be further
subclassed to implement per platform. If you subclass this,
you should define:
- virtualization_type
- virtualization_role
All subclasses MUST define platform.
"""
def __new__(cls, facts, *arguments, **keyword):
subclass = cls
for sc in Virtual.__subclasses__():
if sc.platform == platform.system():
subclass = sc
return super(cls, subclass).__new__(subclass, *arguments, **keyword)
def __init__(self, facts):
Facts.__init__(self, facts)
self.facts['virtualization_type'] = 'NA'
self.facts['virtualization_role'] = 'NA'
def populate(self):
pass
class LinuxVirtual(Virtual):
"""
This is a Linux-specific subclass of Virtual. It defines
- virtualization_type
- virtualization_role
"""
platform = 'Linux'
def __init__(self, facts):
Virtual.__init__(self, facts)
self.facts = facts
def populate(self):
if os.path.exists("/proc/xen"):
self.facts['virtualization_type'] = 'xen'
self.facts['virtualization_role'] = 'guest'
if os.path.exists("/proc/xen/capabilities"):
self.facts['virtualization_role'] = 'host'
if os.path.exists("/proc/modules"):
modules = []
for line in open("/proc/modules").readlines():
data = line.split(" ", 1)
modules.append(data[0])
if 'kvm' in modules:
self.facts['virtualization_type'] = 'kvm'
self.facts['virtualization_role'] = 'host'
elif 'vboxdrv' in modules:
self.facts['virtualization_type'] = 'virtualbox'
self.facts['virtualization_role'] = 'host'
elif 'vboxguest' in modules:
self.facts['virtualization_type'] = 'virtualbox'
self.facts['virtualization_role'] = 'guest'
if 'QEMU' in self.facts['processor'][0]:
self.facts['virtualization_type'] = 'kvm'
self.facts['virtualization_role'] = 'guest'
if self.facts['distribution'] == 'VMwareESX':
self.facts['virtualization_type'] = 'VMware'
self.facts['virtualization_role'] = 'host'
# You can spawn a dmidecode process and parse that or infer from devices
for dev_model in glob.glob('/sys/block/?da/device/vendor'):
info = open(dev_model).read()
if 'VMware' in info:
self.facts['virtualization_type'] = 'VMware'
self.facts['virtualization_role'] = 'guest'
elif 'Virtual HD' in info or 'Virtual CD' in info:
self.facts['virtualization_type'] = 'VirtualPC'
self.facts['virtualization_role'] = 'guest'
def ansible_facts():
def ansible_facts():
facts = {}
facts = {}
get_platform_facts(facts)
f = Facts(facts)
get_hardware_facts(facts)
f.populate()
get_virtual_facts(facts)
f = Hardware(f.facts)
get_network_facts(facts)
f.populate()
get_service_facts(facts)
f = Network(f.facts)
return facts
f.populate()
f = Virtual(f.facts)
f.populate()
return f.facts
# ===========================================
# ===========================================