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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
|
<chapter>
<title>Generators</title>
<para>
Generators are modules which are loaded by the Bcfg2 server,
based on directives in <filename>/etc/bcfg2.conf</filename>. They
provide concrete, fully-specified configuration entries for
clients. This chapter documents the function and usage of
generators bundled with Bcfg2 releases. It also describes the
interface used to communicate with generators; modeles
implementing this interface can provide configuration elements for
clients based on any representation or requirements that may
exist.
</para>
<section>
<title>Bundled Generators</title>
<para>This section describes the generators that come bundled with
Bcfg2. As a general rule, generators requiring more than one
configuration file will use a generator specific directory in the
configuration repository.
</para>
<section>
<title>Cfg</title>
<para>
The Cfg generator provides a configuration file repository
that uses literal file contents to provide client-tailored
configuration file entries. The Cfg generator chooses which
data to provide for a given client based on the aspect-based
metadata system used for high-level client configuration.
</para>
<para>
The Cfg repository is structured much like the filesystem
hierarchy being configured. Each configuration file being
served has a corresponding directory in the configuration
repository. These directories have the same relative path as
the absolute path of the configuration file on the target
system. For example, if Cfg was serving data for the
configuration file <filename>/etc/services</filename>, then
its directory would be in the relative path
<filename>./etc/services</filename> inside of the Cfg
repository.
</para>
<para>
Inside of this file-specific directory, three types of files
may exist. Base files are complete instances of configuration
file. Deltas are differences between a base file and the
target file contents. Base files and deltas are tagged with
metadata specifiers, which describe which groups of clients
the fragment pertains to. Configuration files are constructed
by finding the most specific base file and applying any more
specific deltas.
</para>
<para>
Specifiers are embedded in fragment filenames. For example, in
the fragment <filename>services.C99_webserver</filename>,
"C99_webserver" is the specifier. This specifier applies to
the class (C) webserver with a priority of 99. Other metadata
categories which can be used include bundle (B), profile (P),
hostname (H), attribute (A), and image (I). These are ordered
from least to most specific: image, profile, class, bundle,
and hostname. Global files are the least specific. Priorities
are used as to break ties.
</para>
<para>
Info files, named <filename>:info</filename> are used to
specify target configuration file metadata, such as owner,
group and permissions. If no <filename>:info</filename> is
provided, targets are installed with default
information. Default metadata is root ownership, root group
memberships, and 0644 file permissions.
</para>
<example>
<title>Cfg generator :info files</title>
<programlisting>
owner:root
group:root
perms:0755
</programlisting>
</example>
<example>
<title>Cfg file repository example</title>
<programlisting>
$ ls
:info passwd passwd.C99_chiba-login
passwd.H_bio-debian passwd.H_cvstest passwd.H_foxtrot
passwd.H_reboot passwd.H_rudy2 passwd.C99_netserv
passwd.B99_tacacs-server.cat passwd.H_adenine
</programlisting>
</example>
<para>
In the previous example, there exists files with each of the
characteristics mentioned above. All files ending in ".cat"
are deltas; ones with ".H_" are host specific files. There
exists a base file, a <filename>:info</filename> file, two
class-specified base files, and a bundle-specified base file.
</para>
</section>
<section>
<title>The Scoped XML File Group: Servicemgr</title>
<para>
The generator Servicemgr uses files formatted similarly to the
metadata files. It
works based on a single file, which contains definitions
ordered by increasing specificity.
</para>
<example>
<title><filename>services.xml</filename></title>
<programlisting>
<![CDATA[<Services>
<Class name='webserver'>
<Service status='on' name='httpd' port='80' protocol='tcp'>
<User address='0.0.0.0' mask='32'/>
</Service>
</Class>
<Host name='mailhost'>
<Service name='sendmail' status='on' protocol='tcp' port='80'>
<User address='0.0.0.0' mask='32'/>
</Service>
</Host>
<Host name='thai'>
<Service name='ssh' status='off'/>
</Host>
<Service name='ssh' status='on' protocol='tcp' port='22'/>
<Service name='ntp-server' status='on' />
</Services>]]>
</programlisting>
</example>
<para>
This set of service definitions is intrepreted in the
following way. Webservers run httpd, the host mailhost runs
sendmail, and all machines run ssh, and the ntp-server.
</para>
</section>
</section>
<section>
<title>The Generator API</title>
<para>
The Bcfg2 core has a well-formed API used to call
generators. This mechanism allows all stock generators to be
runtime selected; no stock generators are required. The
generator API has two main functions. The first is communication
to the Bcfg2 core: the list of entries a particular generator
can bind must be communicated to the core so that the proper
generator can be called. The second function is the actual
production of client-specific configuration element data; this
data is then included in client configurations.
</para>
<para>
The inventory function is provided by a python dictionary,
called __provides__ in each generator object. This dictionary
has a key for each type of configuration entry (ConfigFile,
Package, Directory, SymLink, Service), whose value is a
dictionary indexed by configuration element name. For example,
the data path to information about the service "sshd" could be
reached at __provides__['Service']['sshd']. The value of each of
these keys is a function that can be called to bind
client-specific values to a configuration entry. This function
is used in the next section.
</para>
<para>
The handler function located by the __provides__ dictionary is
called with a static API. The function prototype for each of
these handlers is:
</para>
<example>
<title>The Generator handler API</title>
<programlisting>
def Handler(self, entry, metadata):
generator logic here
</programlisting>
</example>
<para>
The data supplied upon handler invokation includes two
parts. The first is the entry. This is a ElementTree.Element
object, which already contains the configuration element type
(ie Service) and name. All other data is bound into this object
in this function. The range of data bound depends on the data
type. The other data provided to handlers is client metadata,
information about the current client, including hostname, image,
profile, classes and bundles. The metadata is typically used to
choose entry contents.
</para>
</section>
<section>
<title>Writing a Generator</title>
<para>
Writing a generator is a fairly straightforward task. At a high
level, generators are instantiated by the Bcfg2 core, and then
used to provide configuration entry contents. This means that
the two points where control passes into a generator from Bcfg2
are during initial object instantiation, and every time a
generator-provided configuration entry is bound.
</para>
<para>
Currently, generators must be written in python. They can
perform arbitrary operations, hence, a generator could be
written that executed logic in another language, but this
functionality is currently not implemented.
</para>
<example>
<title>Simple Generator</title>
<programlisting>
from socket import gethostbyname, gaierror
from syslog import syslog, LOG_ERR
from Bcfg2.Server.Generator import Generator, DirectoryBacked, SingleXMLFileBacked, GeneratorError
class Chiba(Generator):
'''the Chiba generator builds the following files:
-> /etc/network/interfaces'''
__name__ = 'Chiba'
__version__ = '$Id: Chiba.py 1.12 05/01/15 11:05:02-06:00 desai@topaz.mcs.anl.gov $'
__author__ = 'bcfg-dev@mcs.anl.gov'
__provides__ = {'ConfigFile':{}}
def __init__(self, core, datastore):
Generator.__init__(self, core, datastore)
self.repo = DirectoryBacked(self.data, self.core.fam)
self.__provides__['ConfigFile']['/etc/network/interfaces'] = self.build_interfaces
def build_interfaces(self, entry, metadata):
'''build network configs for clients'''
entry.attrib['owner'] = 'root'
entry.attrib['group'] = 'root'
entry.attrib['perms'] = '0644'
try:
myriaddr = gethostbyname("%s-myr" % metadata.hostname)
except gaierror:
syslog(LOG_ERR, "Failed to resolve %s-myr"% metadata.hostname)
raise GeneratorError, ("%s-myr" % metadata.hostname, 'lookup')
entry.text = self.repo.entries['interfaces-template'].data % myriaddr
</programlisting>
</example>
<para>
Generators must subclass the Bcfg2.Server.Generator.Generator
class. Generator constructors must take two arguments: an
instance of a Bcfg2.Core object, and a location for a
datastore. __name__, __version__, __author__, and __provides__
are used to describe what the generator is and how it
works. __provides__ describes a set of configuration entries
that can be provided by the generator, and a set of handlers
that can bind in the proper data. build_interfaces is an example
of a handler. It gets client metadata and an configuration entry
passed in, and binds data into entry as appropriate.
</para>
</section>
</chapter>
|