1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
|
.. -*- mode: rst -*-
.. vim: ft=rst
.. _development-plugins:
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:
.. toctree::
:maxdepth: 1
cfg
packages
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.
.. automodule:: Bcfg2.Server.Plugin
:no-members:
Server Plugin Types
-------------------
A plugin must implement at least one of the interfaces described
below. Each interface is available as a class in
:mod:`Bcfg2.Server.Plugin`. In most cases, a plugin must also
inherit from :class:`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
^^^^^^
.. autoclass:: Bcfg2.Server.Plugin.base.Plugin
:members: name, __author__, experimental, deprecated, conflicts,
sort_order, __rmi__, init_repo, shutdown
:inherited-members:
:show-inheritance:
With the exceptions of
:class:`Bcfg2.Server.Plugin.interfaces.Statistics` and
:class:`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
.. automodule:: Bcfg2.Server.Plugin.interfaces
Exposing XML-RPC Functions
--------------------------
Plugins can expose XML-RPC functions that can then be called with
:ref:`bcfg2-admin xcmd <server-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 :ref:`server-plugins-generators-packages`
plugin:
.. code-block:: python
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
-------------------
.. versionadded:: 1.3.0
In Bcfg2 1.3.0, some limited :ref:`server-caching` was introduced. If
you are writing a :class:`Bcfg2.Server.Plugin.interfaces.Connector`
plugin that implements
:func:`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:
* :attr:`Bcfg2.Server.Core.metadata_cache_mode`: A string description
of the caching mode. See :ref:`server-caching` for a description of
each mode.
* :attr:`Bcfg2.Server.Core.metadata_cache`: A dict-like
:class:`Bcfg2.Server.Cache.Cache` object that stores the cached
data.
:class:`Bcfg2.Server.Plugin.base.Plugin` objects have access to the
:class:`Bcfg2.Server.Core` object as ``self.core``. In general,
you'll be interested in the :func:`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:
* :func:`Bcfg2.Server.Plugins.Probes.ReceiveData` takes a copy of the
groups that have been assigned to a client by
:ref:`server-plugins-probes`, and if that data changes when new probe
data is received, it invalidates the cache for that client.
* :func:`Bcfg2.Server.Plugins.GroupPatterns.Index` expires the entire
cache whenever a FAM event is received for the
:ref:`server-plugins-grouping-grouppatterns` config file.
* :func:`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
:ref:`server-plugins-connectors-puppetenc` plugin is incompatible
with aggressive caching.
Tracking Execution Time
-----------------------
.. versionadded:: 1.3.0
Statistics can and should track execution time statistics using
:mod:`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
:func:`Bcfg2.Server.Plugin.helpers.track_statistics` decorator to
decorate functions that you would like to track execution times for:
.. code-block:: python
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 :func:`time.time` to manually
determine the execution time of a given event and calling
:func:`Bcfg2.Server.Statistics.Statistics.add_value` with an appropriate
statistic name.
Bcfg2.Server.Statistics
^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: Bcfg2.Server.Statistics
Plugin Helper Classes
---------------------
.. automodule:: Bcfg2.Server.Plugin.helpers
:inherited-members:
.. Debuggable is in base to avoid circular imports, but it's a helper
.. and should be listed here in the docs
.. autoclass:: Bcfg2.Server.Plugin.base.Debuggable
:inherited-members:
Plugin Exceptions
-----------------
.. automodule:: Bcfg2.Server.Plugin.exceptions
See Also
--------
* :ref:`development-compat`
* :ref:`development-utils`
|