Skip to content

Commit 96de6c7

Browse files
authored
Merge pull request #67 from miharp/fix/bgtm-links-and-cleanup
Fix broken links and update community resources in bgtm.md
2 parents f270fff + 8cd982f commit 96de6c7

1 file changed

Lines changed: 43 additions & 68 deletions

File tree

docs/_openvox_8x/bgtm.md

Lines changed: 43 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,13 @@ title: Beginner's guide to writing modules
44
---
55

66
[structure]: ./images/bgtmclassstructure.png
7-
[anchor]: ./lang_containment.html#anchor-pattern-containment-for-compatibility-with-puppet--340
8-
[pdk]: {{pdk}}/pdk.html
97

108
Learn how to create fantastic modules by following module best practices [standards and architecture](./style_guide.html).
119

1210
Contributors to this guide have spent years creating Puppet modules, falling into every pitfall, trap, and mistake you could hope to make. This guide is intended to help you avoid our mistakes through an approachable introduction to module best practices.
1311

1412
Before you begin, you should be familiar with Puppet such that you have a basic understanding of the Puppet [language](./lang_summary.html), you know what constitutes a [class](./lang_classes.html), and you understand the basic module [structure](./modules_fundamentals.html).
1513

16-
{:.concept}
1714
## Giving your module purpose
1815

1916
Before you begin writing your module, you must define what it will do. Defining the range of your module's work helps you create concise modules that are easy to work with.
@@ -30,23 +27,21 @@ To help plan your module appropriately, consider:
3027
3128
It is standard practice for Puppet users to have 200 or more modules in an environment. Simple is better. Each module in your environment should contain related resources that enable it to accomplish a task. Create multiple modules for more complex needs. The practice of having many small, focused modules promotes code reuse and turns modules into building blocks.
3229

33-
As an example, let's take a look at the [`puppetlabs-puppetdb`](http://forge.puppet.com/puppetlabs/puppetdb) module. This module deals solely with the the setup, configuration, and management of PuppetDB. However, PuppetDB stores its data in a PostgreSQL database. Rather than having the module manage PostgreSQL, the author included the [`puppetlabs-postgresql`](http://forge.puppet.com/puppetlabs/postgresql) module as a dependency, leveraging the postgresql module's classes and resources to build out the right configuration for PuppetDB. Similarly, the `puppetdb-module` needs to manipulate the `puppet.conf` file in order to operate PuppetDB. Instead of having the `puppetdb-module` handle `puppet.conf` changes internally, the author used the [`puppetlabs-inifile`](http://forge.puppet.com/puppetlabs/inifile) module to enable `puppetlabs-puppetdb` to make only the required edits to `puppet.conf`.
30+
As an example, let's take a look at the [`puppetlabs-puppetdb`](https://forge.puppet.com/puppetlabs/puppetdb) module. This module deals solely with the the setup, configuration, and management of PuppetDB. However, PuppetDB stores its data in a PostgreSQL database. Rather than having the module manage PostgreSQL, the author included the [`puppetlabs-postgresql`](https://forge.puppet.com/puppetlabs/postgresql) module as a dependency, leveraging the postgresql module's classes and resources to build out the right configuration for PuppetDB. Similarly, the `puppetdb-module` needs to manipulate the `puppet.conf` file in order to operate PuppetDB. Instead of having the `puppetdb-module` handle `puppet.conf` changes internally, the author used the [`puppetlabs-inifile`](https://forge.puppet.com/puppetlabs/inifile) module to enable `puppetlabs-puppetdb` to make only the required edits to `puppet.conf`.
3431

35-
{:.concept}
3632
## Structuring your module
3733

3834
The ideal module manages a single piece of software from installation through setup, configuration, and service management.
3935

4036
This section covers:
4137

42-
* [2a. How to design your module's classes](#a-class-design).
43-
* [2b. How to develop useful parameters](#b-parameters).
44-
* [2c. How best to order your classes (rather than resources)](#c-ordering).
45-
* [2d. How to leverage and utilize dependencies](#d-dependencies).
38+
* [How to design your module's classes](#class-design).
39+
* [How to develop useful parameters](#parameters).
40+
* [How best to order your classes (rather than resources)](#ordering).
41+
* [How to leverage and utilize dependencies](#dependencies).
4642

47-
To demonstrate a real-world best practices standard module, we will walk through the structure of the [puppetlabs-ntp](http://forge.puppet.com/puppetlabs/ntp) module.
43+
To demonstrate a real-world best practices standard module, we will walk through the structure of the [puppetlabs-ntp](https://forge.puppet.com/puppetlabs/ntp) module.
4844

49-
{:.concept}
5045
### Class design
5146

5247
A good module is comprised of small, self-contained classes that each do only one thing. Classes within a module are similar to functions in programming, using parameters to perform related steps that create a coherent whole.
@@ -57,14 +52,13 @@ In terms of class structure we recommend the following (more detail below):
5752

5853
![module class structure][structure]
5954

60-
{:.section}
6155
#### `module`
6256

6357
The main class of any module must share the name of the module and be located in the `init.pp` file. The name and location of the main module class is extremely important, as it guides the [autoloader](./lang_namespaces.html#autoloader-behavior) behavior. The main class of a module is its interface point and ought to be the only parameterized class if possible. Limiting the parameterized classes to just the main class allows you to control usage of the entire module with the inclusion of a single class. This class should provide sensible defaults so that a user can get going with `include module`.
6458

6559
For instance, the main `ntp` class in the `ntp` module looks like this:
6660

67-
```ruby
61+
```puppet
6862
class ntp (
6963
Boolean $broadcastclient,
7064
Stdlib::Absolutepath $config,
@@ -81,14 +75,13 @@ class ntp (
8175
...
8276
```
8377

84-
{:.section}
8578
#### `module::install`
8679

8780
The install class must be located in the `install.pp` file. It should contain all of the resources related to getting the software that the module manages onto the node.
8881

8982
The install class must be named `module::install`, as in the `ntp` module:
9083

91-
``` ruby
84+
```puppet
9285
class ntp::install {
9386
9487
if $ntp::package_manage {
@@ -101,14 +94,13 @@ class ntp::install {
10194
}
10295
```
10396

104-
{:.section}
10597
#### `module::config`
10698

10799
The resources related to configuring the installed software should be placed in a config class. The config class must be named `module::config` and must be located in the `config.pp` file.
108100

109101
For example, see the `module::config` class in the `ntp` module:
110102

111-
``` ruby
103+
```puppet
112104
class ntp::config {
113105
114106
#The servers-netconfig file overrides NTP config on SLES 12, interfering with our configuration.
@@ -143,14 +135,13 @@ class ntp::config {
143135
...
144136
```
145137

146-
{:.section}
147138
#### `module::service`
148139

149140
The remaining service resources, and anything else related to the running state of the software, should be contained in the service class. The service class must be named `module::service` and must be located in the `service.pp` file.
150141

151142
For example:
152143

153-
``` ruby
144+
```puppet
154145
class ntp::service {
155146
156147
if ! ($ntp::service_ensure in [ 'running', 'stopped' ]) {
@@ -171,14 +162,12 @@ class ntp::service {
171162
}
172163
```
173164

174-
{:.concept}
175165
### Parameters
176166

177167
Parameters form the public API of your module.
178168

179169
They are the most important interface you expose, and you should take care to balance to the number and variety of parameters so that users can customize their interactions with the module. Below, we walk through best practices for naming and developing parameters.
180170

181-
{:.section}
182171
#### Naming parameters
183172

184173
Naming consistency is imperative for community comprehension and assists in troubleshooting and collaborating on module development.
@@ -187,7 +176,7 @@ Best practices recommend the pattern of `thing_property` for naming parameters.
187176

188177
For example, in the `ntp` module
189178

190-
``` ruby
179+
```puppet
191180
class ntp::install {
192181
193182
if $ntp::package_manage {
@@ -204,7 +193,6 @@ If you have a parameter that toggles an entire function on and off, the naming c
204193

205194
Consistent naming across modules helps with the readability and usability of your code.
206195

207-
{:.section}
208196
#### Number of parameters
209197

210198
To maximize the usability of your module, make it flexible by adding parameters. Parameters enable users to customize their use of your module.
@@ -213,16 +201,15 @@ You must not hardcode data in your modules, and having more parameters is the be
213201

214202
Avoid adding parameters that allow you to override templates. When your parameters allow template overrides, users can override your template with a custom template that contains additional hardcoded parameters. Hardcoded parameters in templates inhibits flexibility over time. It is far better to create more parameters and then modify the original template, or have a parameter which accepts an arbitrary chunk of text added to the template, than it is to override the template with a customized one.
215203

216-
For an example of a module that capitalizes on offering many parameters, please see [puppetlabs-apache](http://forge.puppet.com/puppetlabs/apache).
204+
For an example of a module that capitalizes on offering many parameters, please see [puppetlabs-apache](https://forge.puppet.com/puppetlabs/apache).
217205

218-
{:.concept}
219206
### Ordering
220207

221208
Best practice is to base all order-related dependencies (such as `require` and `before`) on classes rather than resources. Class-based ordering allows you to shield the implementation details of each class from the other classes.
222209

223210
For example:
224211

225-
``` ruby
212+
```puppet
226213
file { 'configuration':
227214
ensure => present,
228215
require => Class['module::install'],
@@ -231,7 +218,6 @@ For example:
231218

232219
Rather than making a `require` to several packages, the above ordering allows you to refactor and improve `module::install` without adjusting the manifests of other classes to match the changes.
233220

234-
{:.section}
235221
#### Containment and anchoring
236222

237223
To allow other modules to form ordering relationships with your module, ensure that your main classes explicitly _contain_ any subordinate classes they declare.
@@ -240,76 +226,73 @@ Classes do not _automatically_ contain the classes they declare. This is because
240226

241227
For example, the `ntp` module uses containment in the main `ntp` class:
242228

243-
```
229+
```puppet
244230
contain ntp::install
245-
contain ntp::config
246-
contain ntp::service
247-
Class['::ntp::install'] ->
248-
Class['::ntp::config'] ~>
249-
Class['::ntp::service']
231+
contain ntp::config
232+
contain ntp::service
233+
Class['::ntp::install'] ->
234+
Class['::ntp::config'] ~>
235+
Class['::ntp::service']
250236
```
251237

252-
Containment is supported in Puppet 3.4 and later. To support versions prior to Puppet 3.4 (or Puppet Enterprise 3.2), you must use the [anchor pattern][anchor] to hold those classes in place. Anchoring requires [puppetlabs-stdlib](http://forge.puppet.com/puppetlabs/stdlib).
253-
254-
{:.concept}
255238
### Dependencies
256239

257240
If your module's functionality depends on another module, then you must list these dependencies and include them directly.
258241

259242
This means you must `include x` in the main class to ensure the dependency is included in the catalog. You must also add the dependency to the module's [metadata.json](./style_guide.html#module-metadata) and `.fixtures.yml`. (`.fixtures.yml` is a file used exclusively by RSpec to pull in dependencies required to successfully run unit tests.)
260243

261-
{:.concept}
262244
## Testing your module
263245

264246
Ensure that the module works in a variety of conditions, and that the options and parameters of your module work together to an appropriate end result.
265247

266-
We recommend several testing frameworks available to help you write unit and acceptance tests. Some of these tools are already included in the Puppet Development Kit (PDK; see the [PDK][pdk] documentation for details.
248+
We recommend several testing frameworks available to help you write unit and acceptance tests. Some of these tools are already included in the [Puppet Development Kit (PDK)](https://www.puppet.com/docs/pdk/latest/pdk.html).
249+
250+
> **Note:** The open source version of PDK is no longer supported by Puppet. It may still be functional, but no further updates or bug fixes will be provided.
267251
268-
{:.section}
269252
### rspec-puppet
270253

271254
The `rspec-puppet` gem provides a unit-testing framework for Puppet. It extends RSpec to allow the testing framework to understand Puppet catalogs, the artifact it specializes in testing. You can write tests, as in the below example, to test that aspects of your module work as intended.
272255

273-
```
256+
```ruby
274257
it { should contain_file('configuration') }
275-
````
258+
```
276259

277-
RSpec lets you provide facts, like `osfamily`, in order to test the module in various scenarios.
260+
RSpec lets you provide facts, like `os['family']`, in order to test the module in various scenarios.
278261

279262
A typical use of RSpec is to iterate over a list of operating systems, asserting that the package and service should exist in the catalog for every operating system your module supports.
280263

281-
To learn more, see [http://rspec-puppet.com/](http://rspec-puppet.com/).
264+
To learn more, see the [rspec-puppet documentation](https://puppetlabs.github.io/rspec-puppet/).
282265

283-
{:.section}
284266
### puppetlabs-spec-helper
285267

286268
The [puppetlabs-spec-helper](https://github.com/puppetlabs/puppetlabs_spec_helper) gem automates some of the tasks required to test modules.
287269

270+
> **Note:** This gem is no longer needed for any Vox Pupuli modules.
271+
288272
This is especially useful in conjunction with `rspec-puppet`, as `puppetlabs-spec-helper` provides default Rake tasks that allow you to standardize testing across modules. It also provides some code to connect `rspec-puppet` with modules. Add it to the Gemfile of the project, and then add the following line to the Rakefile:
289273

290-
```
274+
```ruby
291275
require 'puppetlabs_spec_helper/rake_tasks'
292276
```
293277

294-
{:.section}
295278
### Beaker-rspec
296279

297280
[Beaker-rspec](https://github.com/puppetlabs/beaker-rspec) is an acceptance/integration testing framework.
298281

299-
It provisions one or more virtual machines on various hypervisors (such as [Vagrant](http://www.vagrantup.com/)) and then checks the result of applying your module in a realistic environment.
282+
It provisions one or more virtual machines on various hypervisors (such as [Vagrant](https://www.vagrantup.com/)) and then checks the result of applying your module in a realistic environment.
300283

301-
{:.section}
302284
#### serverspec
303285

304-
[Serverspec](http://serverspec.org/) provides additional testing constructs (such as `be_running` and `be_installed`) for beaker-rspec. It allows you to abstract away details of the underlying distribution when testing. It lets you write tests like:
286+
[Serverspec](https://serverspec.org/) provides additional testing constructs (such as `be_running` and `be_installed`) for beaker-rspec. It allows you to abstract away details of the underlying distribution when testing. It lets you write tests like:
305287

306-
describe service('httpd') do
307-
it { should be_running }
308-
end
288+
```ruby
289+
describe service('httpd') do
290+
it { should be_running }
291+
end
292+
```
309293

310294
It then knows how to translate `be_running` into shell commands for different distributions.
311295

312-
{:.concept}
313296
## Versioning your module
314297

315298
Modules, like any other piece of software, must be versioned and released when changes are made. Use semantic versioning, which sets out specific rules for when to increment major and minor versions.
@@ -318,38 +301,30 @@ After you've decided on the new version number, adjust the version number in the
318301

319302
This allows you to create a list of dependencies in the `metadata.json` file of your modules with specific versions of dependent modules, which ensures your module isn't used with an old dependency that won't work. Versioning also enables workflow management by allowing you to easily use different versions of modules in different environments.
320303

321-
{:.concept}
322304
## Documenting your module
323305

324306
We recommend that you document your module with a README explaining how your module works and a Reference section detailing information about your module's classes, defined types, functions, and resource types and providers.
325307

326-
For guidance, see our modules documentation [guide](./modules_documentation.html)and the [documentation](./style_guide.html#module-documentation) section of the Puppet Language Style Guide.
308+
For guidance, see our modules documentation [guide](./modules_documentation.html) and the [documentation](./style_guide.html#module-documentation) section of the OpenVox Language Style Guide.
327309

328-
{:.concept}
329310
## Releasing your module
330311

331-
We encourage you to publish your modules on the [Puppet Forge](http://forge.puppet.com).
312+
We encourage you to publish your modules on the [Puppet Forge](https://forge.puppet.com).
332313

333314
Sharing your modules allows other users to write improvements to the modules you make available and contribute them back to you, effectively giving you free improvements to your modules.
334315

335-
Additionally, publishing your modules to the Forge helps foster community among Puppet users, and allows other Puppet community members to download and use your module. If the Puppet community routinely releases and iterates on modules on the Forge, the quality of available modules increases dramatically and gives you access to more modules to download and modify for your own purposes. Details on how to publish modules to the Forge can be found [here](./modules_publishing.html).
316+
Additionally, publishing your modules to the Forge helps foster community among Puppet users, and allows other Puppet community members to download and use your module. If the Puppet community routinely releases and iterates on modules on the Forge, the quality of available modules increases dramatically and gives you access to more modules to download and modify for your own purposes. Details on how to publish modules to the Forge can be found in the [module publishing guide](./modules_publishing.html).
336317

337-
{:.concept}
338318
## Community Resources
339319

340320
For beginning module authors, a variety of community resources are available.
341321

342322
[Module basics](./modules_fundamentals.html)
343323

344-
[Puppet Development Kit][pdk]
345-
346-
[Puppet Language Style Guide](./style_guide.html)
347-
348-
[The Forge](http://forge.puppet.com)
349-
350-
The [puppet-users mailing list](https://groups.google.com/forum/#!forum/puppet-users)
324+
[OpenVox Language Style Guide](./style_guide.html)
351325

352-
`#puppet` on IRC
326+
[The Forge](https://forge.puppet.com)
353327

354-
[Puppet Community on Slack](https://slack.puppet.com/)
328+
[Vox Pupuli community channels](https://voxpupuli.org/connect/)
355329

330+
[puppetmodule.info](https://www.puppetmodule.info) — open source Puppet module documentation server, generating fresh docs for Puppet modules and popular Git repositories

0 commit comments

Comments
 (0)