summaryrefslogtreecommitdiffstats
path: root/doc/generators.xml
blob: 053c754e34a5fa25d62302d8d6b46f61a2ed08a4 (plain)
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>