Chapter 3. Git and Environments

When working in a large organization, changes can break things. Every developer will need a sandbox to test their code. A single developer may have to work on two or three issues independently, throughout the day, but they may not apply the working code to any node. It would be great if you could work on a module and verify it in a development environment or even on a single node, before pushing it to the rest of your fleet. Environments allow you to carve up your fleet into as many development environments, as needed. Environments allow nodes to work from different versions of your code. Keeping track of the different versions with Git allows for some streamlined workflows. Other versioning systems can be used, but the bulk of integration in Puppet is done with Git.

Environments

When every node requests an object from the Puppet master, they inform the Puppet master of their environment. Depending on how the master is configured, the environment can change the set of modules, the contents of Hiera, or the site manifest (site.pp). The environment is set on the agent in their puppet.conf file or on the command line using the puppet agent –environment command.

In addition, environment may also be set from the ENC node terminus. In Puppet 4, setting the environment from the ENC overrides the setting in puppet.conf. If no environment is set, then production, which is the default environment, is applied.

In previous versions of Puppet, environments could be configured using section names in puppet.conf ([production] for example). In version 4 the only valid sections in puppet.conf are: main, master, agent, and user. Directory environments are now the only supported mechanism to configure environments. To configure directory environments, specify the environmentpath option in puppet.conf. The default environmentpath is /etc/puppetlabs/code/environments. The production environment is created by Puppet automatically. To create a development environment, create the development directory in /etc/puppetlabs/code/environments, as shown here:

[thomas@stand environments]$ sudo mkdir -p development/manifests development/modules

Now, to use the development environment, copy the base module from production to development, as shown here:

[thomas@stand environments]$ sudo cp -a production/modules/base development/modules

Note

In the remainder of this chapter, we will not use the ENC script we configured in Chapter 2, Organizing Your Nodes and Data. Modify /etc/puppetlabs/puppet/puppet.conf on stand, and comment out the two ENC-related settings which we configured in Chapter 2, Organizing Your Nodes and Data. My examples will be run on a standalone puppetserver machine named stand.

Next, modify the class definition in /etc/puppetlabs/code/environments/development/modules/base/manifests/init.pp, as follows:

class base {
  $welcome = hiera('welcome','Unwelcome')
  file {'/etc/motd':
    mode    => '0644',
    owner   => '0',
    group   => '0',
    content => inline_template("<%= @environment %>
<%= @welcome %>
Managed Node: <%= @hostname %>
Managed by Puppet version <%= @puppetversion %>
"),
  }
}

Now, run the puppet agent command on client and verify whether the production module is being used, as shown here:

[thomas@client ~]$ sudo puppet agent -t
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for client.example.com
Info: Applying configuration version '1442861899'
Notice: /Stage[main]/Base/File[/etc/motd]/ensure: defined content as '{md5}56289627b792b8ea3065b44c03b848a4'
Notice: Applied catalog in 0.84 seconds
[thomas@client ~]$ cat /etc/motd
Welcome to Example.com
Managed Node: client
Managed by Puppet version 4.2.1

Now, run the puppet agent command again with the environment option set to development, as shown here:

[thomas@stand ~]$ sudo puppet agent -t --environment=development
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for stand.example.com
Info: Applying configuration version '1442862701'
Notice: /Stage[main]/Base/File[/etc/motd]/content: 
--- /etc/motd   2015-09-21 14:58:23.648809785 -0400
+++ /tmp/puppet-file20150921-3787-1aus09m       2015-09-21 15:11:41.753703780 -0400
@@ -1,3 +1,4 @@
-Welcome to Example.com
+development
+Unwelcome
 Managed Node: stand
 Managed by Puppet version 4.2.1

Info: Computing checksum on file /etc/motd
Info: /Stage[main]/Base/File[/etc/motd]: Filebucketed /etc/motd to puppet with sum 56289627b792b8ea3065b44c03b848a4
Notice: /Stage[main]/Base/File[/etc/motd]/content: content changed '{md5}56289627b792b8ea3065b44c03b848a4' to '{md5}dd682631bcd240a08669c2c87a7e328d'
Notice: Applied catalog in 0.05 seconds
[thomas@stand ~]$ cat /etc/motd
development
Unwelcome
Managed Node: stand
Managed by Puppet version 4.2.1

This will perform a one-time compilation in the development environment. In the next Puppet run, when the environment is not explicitly set, this will default to production again. To permanently move the node to the development environment, edit /etc/puppetlabs/puppet/puppet.conf and set the environment, as shown here:

[agent]
    environment = development

Environments and Hiera

Hiera's main configuration file can also use environment, as a variable. This leads us to two options: a single hierarchy with the environment as a hierarchy item and multiple hierarchies where the path to the hieradata directory comes from the environment setting. To have separate hieradata trees, you can use environment in the datadir setting for the backend, or to have parts of the hierarchy tied to your environment, put %{::environment} in the hierarchy.

Multiple hierarchies

To have a separate data tree, we will first copy the existing hieradata directory into the production and development directories, using the following commands:

Stand# cd /etc/puppetlabs/code/environments
stand# cp -a production/hieradata development

Now, edit /etc/puppetlabs/puppet/hiera.yaml and change :datadir, as follows:

:yaml:
  :datadir: '/etc/puppetlabs/code/environments/%{::environment}/hieradata'

Now, edit the welcome message in the client.yaml file of the production hieradata tree (/etc/puppetlabs/code/environments/production/hieradata/hosts/client.yaml), as shown here:

---
welcome: 'Production Node: watch your step.'

Also, edit the development hieradata tree (/etc/puppetlabs/code/environments/development/hieradata/hosts/client.yaml) to reflect the different environments, as shown here:

---
welcome: "Development Node: it can't rain all the time."

Now, run Puppet on client to see the /etc/motd file change according to the environment. First, we will run the agent without setting an environment so that the default setting of production is applied, as shown here:

[root@client ~]# puppet agent -t

Notice: /Stage[main]/Base/File[/etc/motd]/ensure: defined content as '{md5}8147bf5dbb04eba29d5efb7e0fa28ce2'
Notice: Applied catalog in 0.83 seconds
[root@client ~]# cat /etc/motd
Production Node: watch your step.
Managed Node: client
Managed by Puppet version 4.2.2

Tip

If you have already set the environment value to development by adding environment=development in puppet.conf, remove that setting.

Then, we run the agent with environment set to development to see the change, as shown here:

[root@client ~]# puppet agent -t --environment=development

Notice: /Stage[main]/Base/File[/etc/motd]/content: 
--- /etc/motd   2015-09-30 21:35:59.523156901 -0700
+++ /tmp/puppet-file20150930-3185-1vyeusl       2015-09-30 21:45:18.444186406 -0700
@@ -1,3 +1,3 @@
-Production Node: watch your step.
+Development Node: it can't rain all the time.
 Managed Node: client
 Managed by Puppet version 4.2.2

Info: Computing checksum on file /etc/motd
Info: /Stage[main]/Base/File[/etc/motd]: Filebucketed /etc/motd to puppet with sum 8147bf5dbb04eba29d5efb7e0fa28ce2
Notice: /Stage[main]/Base/File[/etc/motd]/content: content changed '{md5}8147bf5dbb04eba29d5efb7e0fa28ce2' to '{md5}dc504aeaeb934ad078db900a97360964'
Notice: Applied catalog in 0.04 seconds

Configuring Hiera in this fashion will let you keep completely distinct hieradata trees, for each environment. You can, however, configure Hiera to look for environment-specific information in a single tree.

Single hierarchy for all environments

To have one hierarchy for all environments, edit hiera.yaml as follows:

---
:hierarchy:
  - "environments/%{environment}"
  - "hosts/%{hostname}"
  - "roles/%{role}"
  - "%{kernel}/%{os.family}/%{os.release.major}"
  - "is_virtual/%{is_virtual}"
  - common
:backends:
  - yaml
:yaml:
  :datadir: '/etc/puppetlabs/code/hieradata'

Next, create an environments directory in /etc/puppetlabs/code/hieradata and create the following two YAML files: one for production (/etc/puppetlabs/code/hieradata/environments/production.yaml) and another for development (/etc/puppetlabs/code/hieradata/environments/development.yaml). The following will be the welcome message for the production file:

---
welcome: 'Single tree production welcome'

The following will be the welcome message for the development file:

---
welcome: 'Development in Single Tree'

Restart httpd on stand and run Puppet on node1 again to see the new motd for production, as shown here:

[root@client ~]# puppet agent -t

Notice: /Stage[main]/Base/File[/etc/motd]/content: 
--- /etc/motd   2015-09-30 21:45:18.465186407 -0700
+++ /tmp/puppet-file20150930-3221-bh9ik5        2015-09-30 21:53:43.283213056 -0700
@@ -1,3 +1,3 @@
-Development Node: it can't rain all the time.
+Single tree production welcome

Notice: Applied catalog in 0.67 seconds

Having the production and development environments may be sufficient for a small operation (a manageable amount of nodes, typically less than a thousand), but in an enterprise, you will need many more such environments to help admins avoid stumbling upon one another.

Previous versions of Puppet required special configuration to work with arbitrary environment names; this is no longer the case. The current state of environments is directory environments; any subdirectory within the environmentpath configuration variable is a valid environment. To create new environments, you need to only create the directory within the environmentpath directory. By default, the environmentpath variable is set to /etc/puppetlabs/code/environments. The code directory is meant to be a catchall location for your code. This change was made to help us separate code from configuration data.

Directory environments

Our configuration for Hiera did not specify production or development environments in hiera.yaml. We used the environment value to fill in a path on the filesystem. The directory environments in Puppet function the same way. Directory environments are the preferred method for configuring environments. When using directory environments, it is important to always account for the production environment, since it is the default setting for any node, when environment is not explicitly set.

Puppet determines where to look for directory environments, based on the environmentpath configuration variable. In Puppet 4, the default environmentpath is /etc/puppetlabs/code. Within each environment, an environment.conf file can be used to specify modulepath, manifest, config_version and environment_timeout per environment. When Puppet compiles a catalog, it will run the script specified by config_version and use the output as the config version of the catalog. This provides a mechanism to determine which code was used to compile a specific catalog.

Versions 3.7 and above of Puppet also support a parser setting, which determines which parser (current or future) is used to compile the catalog in each environment. In version 4 and above, the future parser is the only available parser. Using the parser setting, it is possible to test your code against the future parser before upgrading from Puppet 3.x to 4. The usage scenario for the parser option will be to upgrade your development environments to the future parser and fix any problems you encounter along the way. You will then promote your code up to production and enable the future parser in production.

Using the manifest option in environment.conf, it is possible to have a per environment site manifests. If your enterprise requires a site manifest to be consistent between environments, you can set disable_per_environment_manifest = true in puppet.conf to use the same site manifest for all environments.

If an environment does not specify a manifest in environment.conf, the manifest specified in default_manifest is used. A good use of this setting is to specify a default manifest and not specify one within your environment.conf files. You can then test a new site manifest in an environment by adding it to the environment.conf within that environment.

The modulepath within environment.conf may have relative paths and absolute paths. To illustrate, consider the environment named mastering. In the mastering directory within environmentpath (/etc/puppetlabs/code/environments), the environment.conf file has modulepath set to modules:public:/etc/puppetlabs/code/modules. When searching for modules in the mastering environment, Puppet will search the following locations:

  • /etc/puppetlabs/code/environments/mastering/modules
  • /etc/puppetlabs/code/environments/mastering/public
  • /etc/puppetlabs/code/modules

Another useful setting in puppet.conf is basemodulepath. You may configure basemodulepath to a set of directories containing your enterprise wide modules or modules that are shared across multiple environments. The $basemodulepath variable is available within environment.conf. A typical usage scenario is to have modulepath within environment.conf configured with $basemodulepath, defined first in the list of directories, as shown here:

modulepath=$basemodulepath:modules:site:/etc/puppetlabs/code/modules

A great use of directory environments is to create test environments where you can experiment with modifications to your site manifest without affecting other environments. (provided you haven't used the disable_per_environment_manifest setting). As an example, we'll create a sandbox environment and modify the manifest within that environment.

Create the sandbox directory and environment.conf with the following contents:

manifest=/etc/puppetlabs/code/test

Now, create the site manifest at /etc/puppetlabs/code/test/site.pp with the following code:

node default {
  notify {"Trouble in the Henhouse": }
}

Now when you do an agent run on the client node against the sandbox environment, the site manifest in /etc/puppetlabs/code/test will be used, as shown here:

[root@client ~]# puppet agent -t --environment sandbox
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for client.local
Info: Applying configuration version '1443285153'
Notice: Trouble in the Henhouse
Notice: /Stage[main]/Main/Node[default]/Notify[Trouble in the Henhouse]/message: defined 'message' as 'Trouble in the Henhouse'
Notice: Applied catalog in 0.02 seconds

This type of playing around with environments is great for a single developer, but when you are working in a large team, you'll need some version control and automation to convert this to a workable solution. With a large team, it is important that admins do not interfere with each other when making changes to the /etc/puppetlabs/code directory. In the next section, we'll use Git to automatically create environments and share environments between developers.

For further reading on environments, refer to the Puppet Labs website at http://docs.puppetlabs.com/guides/environment.html.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset