Skip to content

Commit 410041b

Browse files
committed
Fix broken links and update community resources in bgtm.md
- Replace PDK references with voxbox (https://github.com/voxpupuli/container-voxbox) - Replace broken PDK liquid template link with direct URL - Fix all http:// → https:// for Forge, rspec-puppet, Vagrant, and Serverspec URLs - Fix section TOC anchors to match actual heading IDs - Change code fences from 'ruby' to 'puppet' for Puppet code examples; add 'ruby' hint to RSpec/Rakefile examples - Fix extra backtick on closing rspec code fence - Fix containment code block indentation - Remove Puppet 3.4 anchor pattern paragraph (not relevant for OpenVox 8) - Fix missing space in documenting section prose - Update community resources: replace Puppet Slack/IRC with Vox Pupuli Slack and #voxpupuli on Libera.Chat - Remove all {:.concept}/{:.section} kramdown markers unused by theme Signed-off-by: Michael Harp <mike@mikeharp.com>
1 parent e910cca commit 410041b

1 file changed

Lines changed: 34 additions & 61 deletions

File tree

docs/_openvox_8x/bgtm.md

Lines changed: 34 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,14 @@ 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
7+
[container-voxbox]: https://github.com/voxpupuli/container-voxbox
98

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

1211
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.
1312

1413
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).
1514

16-
{:.concept}
1715
## Giving your module purpose
1816

1917
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 +28,21 @@ To help plan your module appropriately, consider:
3028
3129
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.
3230

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`.
31+
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`.
3432

35-
{:.concept}
3633
## Structuring your module
3734

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

4037
This section covers:
4138

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).
39+
* [How to design your module's classes](#class-design).
40+
* [How to develop useful parameters](#parameters).
41+
* [How best to order your classes (rather than resources)](#ordering).
42+
* [How to leverage and utilize dependencies](#dependencies).
4643

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.
44+
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.
4845

49-
{:.concept}
5046
### Class design
5147

5248
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 +53,13 @@ In terms of class structure we recommend the following (more detail below):
5753

5854
![module class structure][structure]
5955

60-
{:.section}
6156
#### `module`
6257

6358
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`.
6459

6560
For instance, the main `ntp` class in the `ntp` module looks like this:
6661

67-
```ruby
62+
```puppet
6863
class ntp (
6964
Boolean $broadcastclient,
7065
Stdlib::Absolutepath $config,
@@ -81,14 +76,13 @@ class ntp (
8176
...
8277
```
8378

84-
{:.section}
8579
#### `module::install`
8680

8781
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.
8882

8983
The install class must be named `module::install`, as in the `ntp` module:
9084

91-
``` ruby
85+
```puppet
9286
class ntp::install {
9387
9488
if $ntp::package_manage {
@@ -101,14 +95,13 @@ class ntp::install {
10195
}
10296
```
10397

104-
{:.section}
10598
#### `module::config`
10699

107100
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.
108101

109102
For example, see the `module::config` class in the `ntp` module:
110103

111-
``` ruby
104+
```puppet
112105
class ntp::config {
113106
114107
#The servers-netconfig file overrides NTP config on SLES 12, interfering with our configuration.
@@ -143,14 +136,13 @@ class ntp::config {
143136
...
144137
```
145138

146-
{:.section}
147139
#### `module::service`
148140

149141
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.
150142

151143
For example:
152144

153-
``` ruby
145+
```puppet
154146
class ntp::service {
155147
156148
if ! ($ntp::service_ensure in [ 'running', 'stopped' ]) {
@@ -171,14 +163,12 @@ class ntp::service {
171163
}
172164
```
173165

174-
{:.concept}
175166
### Parameters
176167

177168
Parameters form the public API of your module.
178169

179170
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.
180171

181-
{:.section}
182172
#### Naming parameters
183173

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

188178
For example, in the `ntp` module
189179

190-
``` ruby
180+
```puppet
191181
class ntp::install {
192182
193183
if $ntp::package_manage {
@@ -204,7 +194,6 @@ If you have a parameter that toggles an entire function on and off, the naming c
204194

205195
Consistent naming across modules helps with the readability and usability of your code.
206196

207-
{:.section}
208197
#### Number of parameters
209198

210199
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 +202,15 @@ You must not hardcode data in your modules, and having more parameters is the be
213202

214203
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.
215204

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

218-
{:.concept}
219207
### Ordering
220208

221209
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.
222210

223211
For example:
224212

225-
``` ruby
213+
```puppet
226214
file { 'configuration':
227215
ensure => present,
228216
require => Class['module::install'],
@@ -231,7 +219,6 @@ For example:
231219

232220
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.
233221

234-
{:.section}
235222
#### Containment and anchoring
236223

237224
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 +227,67 @@ Classes do not _automatically_ contain the classes they declare. This is because
240227

241228
For example, the `ntp` module uses containment in the main `ntp` class:
242229

243-
```
230+
```puppet
244231
contain ntp::install
245-
contain ntp::config
246-
contain ntp::service
247-
Class['::ntp::install'] ->
248-
Class['::ntp::config'] ~>
249-
Class['::ntp::service']
232+
contain ntp::config
233+
contain ntp::service
234+
Class['::ntp::install'] ->
235+
Class['::ntp::config'] ~>
236+
Class['::ntp::service']
250237
```
251238

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}
255239
### Dependencies
256240

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

259243
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.)
260244

261-
{:.concept}
262245
## Testing your module
263246

264247
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.
265248

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.
249+
We recommend several testing frameworks available to help you write unit and acceptance tests. Some of these tools are available in [container-voxbox][container-voxbox], a container with a full Puppet development toolchain.
267250

268-
{:.section}
269251
### rspec-puppet
270252

271253
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.
272254

273-
```
255+
```ruby
274256
it { should contain_file('configuration') }
275-
````
257+
```
276258

277259
RSpec lets you provide facts, like `osfamily`, in order to test the module in various scenarios.
278260

279261
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.
280262

281-
To learn more, see [http://rspec-puppet.com/](http://rspec-puppet.com/).
263+
To learn more, see [https://rspec-puppet.com/](https://rspec-puppet.com/).
282264

283-
{:.section}
284265
### puppetlabs-spec-helper
285266

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

288269
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:
289270

290-
```
271+
```ruby
291272
require 'puppetlabs_spec_helper/rake_tasks'
292273
```
293274

294-
{:.section}
295275
### Beaker-rspec
296276

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

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.
279+
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.
300280

301-
{:.section}
302281
#### serverspec
303282

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:
283+
[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:
305284

306285
describe service('httpd') do
307286
it { should be_running }
308287
end
309288

310289
It then knows how to translate `be_running` into shell commands for different distributions.
311290

312-
{:.concept}
313291
## Versioning your module
314292

315293
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 +296,33 @@ After you've decided on the new version number, adjust the version number in the
318296

319297
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.
320298

321-
{:.concept}
322299
## Documenting your module
323300

324301
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.
325302

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.
303+
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.
327304

328-
{:.concept}
329305
## Releasing your module
330306

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

333309
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.
334310

335311
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).
336312

337-
{:.concept}
338313
## Community Resources
339314

340315
For beginning module authors, a variety of community resources are available.
341316

342317
[Module basics](./modules_fundamentals.html)
343318

344-
[Puppet Development Kit][pdk]
345-
346-
[Puppet Language Style Guide](./style_guide.html)
319+
[container-voxbox][container-voxbox]
347320

348-
[The Forge](http://forge.puppet.com)
321+
[OpenVox Language Style Guide](./style_guide.html)
349322

350-
The [puppet-users mailing list](https://groups.google.com/forum/#!forum/puppet-users)
323+
[The Forge](https://forge.puppet.com)
351324

352-
`#puppet` on IRC
325+
[Vox Pupuli on Slack](https://voxpupuli.org/slack/)
353326

354-
[Puppet Community on Slack](https://slack.puppet.com/)
327+
`#voxpupuli` on [Libera.Chat](https://libera.chat/)
355328

0 commit comments

Comments
 (0)