sampledoc

Bcfg2 Plugin development

While the Bcfg2 server provides a good interface for representing general system configurations, its plugin interface offers the ability to implement configuration interfaces and representation tailored to problems encountered by a particular site. This chapter describes what plugins are good for, what they can do, and how to implement them.

Several plugins themselves have pluggable backends, and for narrow cases you may want to develop a backend for an existing plugin rather than an entirely new plugin. See the following pages for more information:

Bcfg2 Plugins

Bcfg2 plugins are loadable python modules that the Bcfg2 server loads at initialization time. These plugins can contribute to the functions already offered by the Bcfg2 server or can extend its functionality. In general, plugins will provide some portion of the configuration for clients, with a data representation that is tuned for a set of common tasks. Much of the core functionality of Bcfg2 is implemented by several plugins, however, they are not special in any way; new plugins could easily supplant one or all of them.

Server Plugin Types

A plugin must implement at least one of the interfaces described below. Each interface is available as a class in Bcfg2.Server.Plugin. In most cases, a plugin must also inherit from Bcfg2.Server.Plugin.base.Plugin, which is the base Plugin object (described below). Some of the interfaces listed below are themselves Plugin objects, so your custom plugin would only need to inherit from the plugin type.

Plugin

With the exceptions of Bcfg2.Server.Plugin.interfaces.Statistics and Bcfg2.Server.Plugin.interfaces.ThreadedStatistics, the plugin interfaces listed below do not inherit from Plugin; they simply provide interfaces that a given plugin may or must implement.

Interfaces

class Bcfg2.Server.Plugin.interfaces

Exposing XML-RPC Functions

Plugins can expose XML-RPC functions that can then be called with bcfg2-admin xcmd. Note that there is absolutely no access control beyond the initial authentication, so take care to not expose any data or behavior via XML-RPC that you would not want all of your clients to be able to see or use.

To expose a function, simply add its name to the __rmi__ class attribute. (RMI stands for “Remote Method Invocation.”) Consider this example from the Packages plugin:

class Packages(Bcfg2.Server.Plugin.Plugin,
               Bcfg2.Server.Plugin.StructureValidator,
               Bcfg2.Server.Plugin.Generator,
               Bcfg2.Server.Plugin.Connector,
               Bcfg2.Server.Plugin.ClientRunHooks):
    name = 'Packages'
    conflicts = ['Pkgmgr']
    __rmi__ = Bcfg2.Server.Plugin.Plugin.__rmi__ + ['Refresh', 'Reload']

def Refresh(self):
    self._load_config(force_update=True)
    return True

def Reload(self):
    self._load_config()
    return True

This exposes two functions, Refresh and Reload, in addition to any default methods that are already exposed. To call one of these functions, you could run:

bcfg2-admin xcmd Packages.Refresh

Invalidating Caches

New in version 1.3.0.

In Bcfg2 1.3.0, some limited Server-side Caching was introduced. If you are writing a Bcfg2.Server.Plugin.interfaces.Connector plugin that implements Bcfg2.Server.Plugin.interfaces.Connector.get_additional_groups(), then you need to be able to invalidate the server metadata cache in order to be compatible with the cautious or aggressive caching modes.

The two attributes you need to know about are:

  • Bcfg2.Server.Core.metadata_cache_mode: A string description of the caching mode. See Server-side Caching for a description of each mode.
  • Bcfg2.Server.Core.metadata_cache: A dict-like Bcfg2.Server.Cache.Cache object that stores the cached data.

Bcfg2.Server.Plugin.base.Plugin objects have access to the Bcfg2.Server.Core object as self.core. In general, you’ll be interested in the Bcfg2.Server.Cache.Cache.expire() method; if called with no arguments, it expires all cached data; if called with one string argument, it expires cached data for the named client.

It’s important, therefore, that your Connector plugin can either track when changes are made to the group membership it reports, and expire cached data appropriately when in cautious or aggressive mode; or prudently flag an incompatibility with those two modes.

For examples, see:

  • Bcfg2.Server.Plugins.Probes.ReceiveData() takes a copy of the groups that have been assigned to a client by Probes, and if that data changes when new probe data is received, it invalidates the cache for that client.
  • Bcfg2.Server.Plugins.GroupPatterns.Index() expires the entire cache whenever a FAM event is received for the GroupPatterns config file.
  • Bcfg2.Server.Plugins.PuppetENC.end_client_run() expires the entire cache at the end of every client run and produces a message at the warning level that the PuppetENC plugin is incompatible with aggressive caching.

Tracking Execution Time

New in version 1.3.0.

Statistics can and should track execution time statistics using Bcfg2.Server.Statistics. This module tracks execution time for the server core and for plugins, and exposes that data via bcfg2-admin perf. This data can be invaluable for locating bottlenecks or other performance issues.

The simplest way to track statistics is to use the Bcfg2.Server.Plugin.helpers.track_statistics() decorator to decorate functions that you would like to track execution times for:

from Bcfg2.Server.Plugin import track_statistics

@track_statistics()
def do_something(self, ...):
    ...

This will track the execution time of do_something.

More granular usage is possible by using time.time() to manually determine the execution time of a given event and calling Bcfg2.Server.Statistics.Statistics.add_value() with an appropriate statistic name.

Bcfg2.Server.Statistics

Module for tracking execution time statistics from the Bcfg2 server core. This data is exposed by Bcfg2.Server.Core.BaseCore.get_statistics().

class Bcfg2.Server.Statistics.Statistic(name, initial_value)[source]

Bases: object

A single named statistic, tracking minimum, maximum, and average execution time, and number of invocations.

Parameters:
  • name (string) – The name of this statistic
  • initial_value (int or float) – The initial value to be added to this statistic
add_value(value)[source]

Add a value to the statistic, recalculating the various metrics.

Parameters:value (int or float) – The value to add to this statistic
get_value()[source]

Get a tuple of all the stats tracked on this named item. The tuple is in the format:

(<name>, (min, max, average, number of values))

This makes it very easy to cast to a dict in Statistics.display().

Returns:tuple
class Bcfg2.Server.Statistics.Statistics[source]

Bases: object

A collection of named Statistic objects.

add_value(name, value)[source]

Add a value to the named Statistic. This just proxies to Statistic.add_value() or the Statistic constructor as appropriate.

Parameters:
  • name (string) – The name of the Statistic to add the value to
  • value (int or float) – The value to add to the Statistic
display()[source]

Return a dict of all Statistic object values. Keys are the statistic names, and values are tuples of the statistic metrics as returned by Statistic.get_value().

Bcfg2.Server.Statistics.stats

A module-level Statistics objects used to track all execution time metrics for the server.

class Bcfg2.Server.Statistics.track_statistics(name=None)[source]

Bases: object

Decorator that tracks execution time for the given method with Bcfg2.Server.Statistics for reporting via bcfg2-admin perf

Parameters:name (string) – The name under which statistics for this function will be tracked. By default, the name will be the name of the function concatenated with the name of the class the function is a member of.

Plugin Helper Classes

Plugin Exceptions