Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use facter's --json #10

Open
daenney opened this issue May 8, 2015 · 4 comments
Open

Use facter's --json #10

daenney opened this issue May 8, 2015 · 4 comments

Comments

@daenney
Copy link

daenney commented May 8, 2015

Facter can output JSON if you give it the --json argument on the command line. All it takes is:

json.loads(subprocess.check_output(['facter', '--json']))

You can easily turn it into a named tuple too:

>>> y = json.loads(subprocess.check_output(['facter', '--json']), object_hook=lambda d: namedtuple('Factset', d.keys())(*d.values()))

>>> dir(y)
['__add__', '__class__', '__contains__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__getstate__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '_asdict', '_fields', '_make', '_replace', 'architecture', 'count', 'domain', 'facterversion', 'fqdn', 'gid', 'hardwareisa', 'hardwaremodel', 'hostname', 'id', 'index', 'interfaces', 'ipaddress', 'ipaddress6', 'ipaddress6_en0', 'ipaddress_en0', 'ipaddress_lo0', 'is_virtual', 'kernel', 'kernelmajversion', 'kernelrelease', 'kernelversion', 'macaddress', 'macaddress_awdl0', 'macaddress_bridge0', 'macaddress_en0', 'macaddress_en1', 'macaddress_en2', 'macaddress_p2p0', 'macosx_buildversion', 'macosx_productname', 'macosx_productversion', 'macosx_productversion_major', 'macosx_productversion_minor', 'memoryfree', 'memoryfree_mb', 'memorysize', 'memorysize_mb', 'mtu_awdl0', 'mtu_bridge0', 'mtu_en0', 'mtu_en1', 'mtu_en2', 'mtu_gif0', 'mtu_lo0', 'mtu_p2p0', 'mtu_stf0', 'netmask', 'netmask_en0', 'netmask_lo0', 'network_en0', 'network_lo0', 'operatingsystem', 'operatingsystemmajrelease', 'operatingsystemrelease', 'os', 'osfamily', 'path', 'processorcount', 'processors', 'productname', 'ps', 'puppetversion', 'rubyplatform', 'rubysitedir', 'rubyversion', 'sp_boot_mode', 'sp_boot_rom_version', 'sp_boot_volume', 'sp_cpu_type', 'sp_current_processor_speed', 'sp_kernel_version', 'sp_l2_cache_core', 'sp_l3_cache', 'sp_local_host_name', 'sp_machine_model', 'sp_machine_name', 'sp_number_processors', 'sp_os_version', 'sp_packages', 'sp_physical_memory', 'sp_platform_uuid', 'sp_secure_vm', 'sp_serial_number', 'sp_smc_version_system', 'sp_uptime', 'sp_user_name', 'swapencrypted', 'swapfree', 'swapfree_mb', 'swapsize', 'swapsize_mb', 'system_uptime', 'timezone', 'uptime', 'uptime_days', 'uptime_hours', 'uptime_seconds', 'virtual']

>>> y.memorysize
u'16.00 GB'

This will go haywire if a Fact has a - in a key name as that won't fly in Python but that's easily rectified.

The namedtuple has two advantages:

  • attribute style lookups, so .memorysize
  • it's immutable, no one can go in and mess with the values of the facts
@knorby
Copy link
Owner

knorby commented May 8, 2015

@daenney oh, cool. That's definitely new, as I wouldn't have written the library if it was available when I did (I'm not an active puppet user currently). Do you happened to know what version that was added in?

I don't really think of this case as a good one for namedtuples, as puppet-defined facts are not predefined. I do like the idea of defining properties for common values, and perhaps some better handling for certain types (e.g. size values). I'm not sure I see the value in guaranteeing immutability.

@daenney
Copy link
Author

daenney commented May 8, 2015

The value in immutability is that people can't mess with the values of the Facts after the fact. Facts represent the current state of your system as determined by Facter. If people can go in and mess with that data they aren't really of any value to make any kind of decision with. But yes, I ran into a multitude of issues with the tuples because the keys aren't guaranteed to be able to convert to things that are suitable as attribute names for Python.

As far as --json goes, it has been around since Facter 1.6, so summer 2011.

@knorby
Copy link
Owner

knorby commented May 8, 2015

I looked through facter commit history, and it looks like past versions didn't include the option when the json gem wasn't installed (likely how I missed it), and I'm uncertain exactly how that's changed aside from it always being displayed. I will continue to want fallback handling, which is some of the point to this library in the first place.

I don't think there is a point to the sort of immutability you are describing in python, because it doesn't really buy you anything. Preventing unintended modifications is one thing, which this library already does, but there isn't a point really in guarding against bad actors, as there is almost always a workaround, including with namedtuples.

@mohsenBanan
Copy link

import json
import subprocess

import collections

y = json.loads(subprocess.check_output(['facter', '--json']), object_hook=lambda d: collections.namedtuple('Factset', d.keys(), rename=True)(*d.values()))

print(y.networking.primary)

This works for me and rename=True makes use of namedtuple reliable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants