# Puppet Standards

### Classification and Class Assignment

Classes should be assigned to nodes via Hiera. Within any Hiera YAML file, you
can assign classes / modules with the `classes` key:

    # hiera/twitch_role/production/my_service.yaml
    ---
    classes:
      - "my_class"

### Software Repositories

When installing packages from outside sources, always package the software and
upload it to our internal software mirrors. This prevents installation failure
when connectivity to the outside sources is lost, and improves the performance
of Puppet runs in general.

#### Parameters, Defaults, and Hiera

Any configurable setting in your module should conform to the following flow:

  * A default value is set in `params.pp`
  * If the default value needs to be overriden (by any consumer), use the class
    params pattern in `init.pp`. Any setting which is defined as a class
    parameter (and has a default value set in `params.pp`) can be modified as
    needed in Hiera.
  * Use Hiera to override defaults where necessary.

#### Component-Specific Manifests

When creating a module for a service, use individual manifests for each
component of the service. For example, given a service which consists of an
application server, an HAProxy load balancer, and a MySQL database, you might
have a module layout like this:

    my_module
    └── manifests
        ├── init.pp
        ├── params.pp
        ├── app.pp
        ├── haproxy.pp
        └── mysql.pp

#### Avoid `exec` Statements

The `exec` statement allows you to execute an arbitrary shell command via
Puppet. However, this resource type should generally not be used. Instead, use
the resource type which best fits your use case. When installing things, use
`package` resources. When running things, use `service` resources.

#### Explicit Dependencies

When an individual resource in your module depends on an indiviual resource in
another module, that dependency should be explicitly specified on the resource
which has the dependency.

Q: When depending on a component of `twitch_core` from an external module (e.g.
   a wrapper module for a service), should `twitch_core` be required, or its
   specific component?

### Inter-module Contracts

This section describes the ways in which modules should refer to or interact
with other modules.

From the upstream documentation:

```When declaring classes in publicly available modules, you should use
include, contain, or require rather than class resource declaration.
This avoids duplicate class declarations and vendor lock-in.```

#### Import

`import` statements are deprecated and should not be used.

#### Include

`include` statements are equivalent to instantiating a class with the default
arguments. Remember that classes in Puppet are singletons, and attempting to
instantiate the same class or module twice will result in a runtime error.

Inclusions can happen in one of three places only:

* In Hiera, under the `classes` array key

* In wrapper modules, where open source modules are being instantiated
  * When this approach is used, the wrapper module itself should be included
    via Hiera

* In first-party modules, where subclasses are being instantiated from
  `init.pp`.

https://docs.puppetlabs.com/puppet/latest/reference/lang_classes.html#using-include

#### Contain

#### Require

`require` statements declare a class or module, and then marks it as a
dependency of the surrounding container.

Modules should specify their dependencies with `require` instead of `include`.

https://docs.puppetlabs.com/puppet/latest/reference/lang_classes.html#using-require

#### Puppet Tests

Puppet modules can include their own tests in the `tests/` directory. See the
following documentation for more info:

https://docs.puppetlabs.com/guides/tests_smoke.html#writing-tests

https://docs.puppetlabs.com/guides/module_guides/bgtm.html#step-three-module-testing

#### Jenkins Tests (RSpec, ServerSpec, Test-Kitchen)

These tests are executed by Jenkins against a live instance of your service.
