Skip to content

Instantly share code, notes, and snippets.

@spynappels
Created January 10, 2018 14:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spynappels/41699b5bcc63a742084d5fb3d023c6dc to your computer and use it in GitHub Desktop.
Save spynappels/41699b5bcc63a742084d5fb3d023c6dc to your computer and use it in GitHub Desktop.
This is a very basic External Node Classifier script for Puppet Enterprise (or Puppet OpenSource with some changes) written in Python. It is mostly well commented, but I will add some additional points in a Github comment.
#!/usr/bin/python3
# An example Puppet External Node Classifier written in Python3
# This supposes a PE Installation, as I've used PE Classes for the Master config.
# ***NOTICE*** This is not supported by Puppet Support and will likely cause issues
# if you try to raise Support Tickets on it!!
import sys
import yaml
node_fqdn = sys.argv[1]
# Create empty classification dictionary
classification = dict()
classification['classes'] = {}
classification['parameters'] = {}
# Classes section
# Default Node Classes
# Always apply Puppet Agent and MCollective classes
classification['classes'].update({'puppet_enterprise::profile::agent':'','puppet_enterprise::profile::mcollective::agent':''})
# Add any other global classes below
# The testclass below is simply defined as the following, designed to echo back the
# node_role parameter defined in the Parameter section later in this script
# class testclass {
# notify{"The node role is ${::node_role}":}
# }
classification['classes'].update({'testclass':''})
# Add classes to groups of nodes using partial string matching on FQDN
if "pe-201722" in node_fqdn:
# Add classes to all nodes with the substring in the FQDN
classification['classes'].update({'ssh':''})
# Node specific classes
if node_fqdn == "pe-201722-master.puppetdebug.vlan":
# On Monolithic Master, ensure all Puppet Enterprise profiles are applied
classification['classes'].update({'puppet_enterprise::profile::master':''})
classification['classes'].update({'puppet_enterprise::profile::master::mcollective':''})
classification['classes'].update({'puppet_enterprise::profile::mcollective::peadmin':''})
classification['classes'].update({'pe_repo':''})
classification['classes'].update({'pe_repo::platform::ubuntu_1404_amd64':''})
classification['classes'].update({'puppet_enterprise::profile::puppetdb':''})
classification['classes'].update({'puppet_enterprise::profile::console':''})
classification['classes'].update({'puppet_enterprise::license':''})
classification['classes'].update({'puppet_enterprise::profile::amq::broker':''})
classification['classes'].update({'puppet_enterprise::profile::certificate_authority':''})
classification['classes'].update({'puppet_enterprise::profile::orchestrator':''})
# Add any other required classes for the Master node below
classification['classes'].update({'ntp':{'servers':['2.uk.pool.ntp.org','3.uk.pool.ntp.org']}})
if node_fqdn == "pe-201722-agent.puppetdebug.vlan":
# Add and configure NTP class
classification['classes'].update({'ntp':{'servers':['0.uk.pool.ntp.org','1.uk.pool.ntp.org']}})
# Parameters section
# This sets the node_role based on a section of the hostname
classification['parameters'].update({'node_role':node_fqdn.split(".")[0].split("-")[-1]})
# Environment section
# In this example the last but one section of the FQDN is checked to determine environment,
# similar results can be achieved by splitting on hyphens in a hostname if the environment
# is coded into the hostname like someapp1-test.domain.com
if node_fqdn.split(".")[-2] == "puppetdebug":
classification.update({'environment': 'production'})
else:
classification.update({'environment': node_fqdn.split(".")[-2]})
# Output classification back to puppetserver
print(yaml.dump(classification, default_flow_style=False))
@spynappels
Copy link
Author

This is based on the Puppet Documentation at https://puppet.com/docs/puppet/5.3/nodes_external.html

I had to add 2 keys to the common.yaml file in the Hieradata directory of the production environment:

puppet_enterprise::profile::master::classifier::node_terminus: 'exec'
puppet_enterprise::puppet_master_host: 'pe-201722-master.puppetdebug.vlan'

I also had to add the path to the script to the Master's puppet.conf.

This was developed on a PE2017.2.2 Environment, spun up using Vagrant on Ubuntu 14.04. It will also work on Puppet OpenSource, although obviously the classes that configure the various elements will have to be built, rather than using the puppet_enterprise classes and profiles.

I hope it is of use to someone, it certainly helped me understand ENCs better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment