Faces, Actions, Options, and Facades, Oh My!
This follows on from my previous post on Faces and starts to break down the components that make up the Faces system. The fundamental components here are:
- Facades – the ways you can interact with your Faces and Actions.
- Faces – these represent a coherent subsystem, or modelled object or entity.
- Actions – these represent things you can do to the modelled object or entity.
- Options – these modify the way that actions work
Facades: Ways of Using FacesFaces, and their Actions, provide a standard Ruby API over our models of the network, and the things you can command Puppet to do. That, alone, would provide a huge amount of value, but it isn't the end of the story. As part of Faces we have developed a Facade: every Face can be accessed, and every action invoked, from the command line. We map the arguments and options for the Face and Action down into command line options you can pass. We see the Facades as one of the greatest strengths of Puppet Faces. They provide a huge amount of functionality for free today, and we expect them to do a whole lot more tomorrow. Adding a Facade that integration with MCollective, or that provides a generic HTTP RPC mechanism, would add huge value without needing to change the individual Faces. The use of Facades also forces our Faces to support introspection: enough that you can write code that reasons about, and influences, the contained code. That also means that we can expect Faces to be able to effectively interact with each other using the same introspection mechanisms—code that manages code is easy, and routine, within Faces.
An Example of Face IntrospectionOne of the best examples of the power of Face introspection is the
puppet helpFace. This is just a regular Face that loads up other Faces and Actions, then uses introspection to fill out a documentation template with the Options, Actions, Faces, and other relevant details. The
helpFace is 124 lines long, but a lot of that is backwards compatibility support for our older model applications, or documentation on the Face itself. (Fun tip:
puppet help help helpwill tell you all about the
helpAction of the
helpFace. ;) Once we have dealt with all the legacy support, the actual meat of the function to get access to the face and action (less error handling) is only:
version ||= :current # a sensible default... face = Puppet::Face[facename, version] action = face.get_action(actionname) if actionnameOnce we have that we pass it off to the appropriate template for displaying global, Face, or Action help. The template uses some basic introspection to build up the help:
% action.options.map(&:get_option).each do |option| * - <%= option.name %> - <%= option.summary %> % endIn addition to the name and summary we can pull out details like a generated synopsis of the Action or Face, required arguments to each action, and other details required to invoke the system... Stay tuned for the next installment, "About Faces, until we go in the right direction."