Hi Tim

I had a similar question in 
https://groups.google.com/forum/?fromgroups#!topic/puppet-users/fhHYT3LkBoE 
but spent a while figuring out and testing what is possible.  Hopefully 
this will help you or someone work their way around a corner.

Puppet Environments

* Common modules, environment/node specific configs
* Environment specific modules and common or environment/node specific 
configs

It is possible to use both and failback/iterate over configs per 
$environment and per node.
And it is possible to have a shared/common module in (modules) that is 
specific to all environments and have the specific $environment or node 
configs being served via environments.  It is a little complicated but does 
work and allows for quite a bit of flexibility serving environments.

I find that I do not want to maintain all modules per environment in 
puppet, as that means maintaining $(( modules * number_of_environments )), 
but do as shown later :)

Some modules lend then themselves to a common module but environment 
specific configuration.  To achieve this some puppet magic is required, a 
few spells :)  I shall try and describe the concept and steps here.

So for example it is possible to achieve something like the following 
(caveat manifests/${environment} dirs are there if you are also using an 
include ${environment}/*.pp for node definitions):

|+-environments/
|  +-dev/
|  | +-configs/
|  | | |+-mysql_proxy/
|  | | |  +-${puppet_env}.mysql-proxy.erb
|  | | |  +-dev-server-1.mysql-proxy.erb
|  | | |+-mysql_server/
|  | |    +-$hostname.cnf
|  | |    +-mysql.conf
|  | +-modules/
|  | | |+-httpd/
|  | |    |+-manifests/
|  | |    |  +-init.pp
|  | |    |+-templates/
|  | |       +-httpd.conf.erb
|  | +-repo/
|  |   |+-*.rpm
|  +-prod/
|  | +-configs/
|  | | |+-mysql_proxy/
|  | | |  +-${puppet_env}.mysql-proxy.erb
|  | | |  +-prod-server-2.mysql-proxy.erb
|  | | |+-mysql_server/
|  | |    +-$hostname.cnf
|  | |    +-mysql.conf
|  | +-modules/
|  | | |+-httpd/
|  | |    |+-manifests/
|  | |    |  +-init.pp
|  | |    |+-templates/
|  | |       +-httpd.conf.erb
|  | +-repo/
|  |   |+-*.rpm
|+-manifests/
|  |+-dev/
|  |  +-dev-server-1.pp
|  |  +-dev-server-2.pp
|  |+-prod/
|  |  +-prod-server-1.pp
|  |  +-prod-server-2.pp
|  |+-extdata/
|  |  +-dev.csv
|  |  +-dev.csv
|  |+-dev.pp
|  |+-prod.pp
|  |+-site.pp
|+-modules/
   |+-mysql_proxy/
   |  |+-manifests/
   |  |  +-init.pp
   |  |+-files/
   |     +-mysql-proxy.erb
   |+-mysql_server/
      |+-manifests/
         +-init.pp

To achieve this you need to ensure environments are set in the puppet.conf
<SNIP>
[agent]
    environment = <%= environment %>
</SNIP>

Just for clarification I map $environment to $puppet_env (for some backward 
compatability issues as puppet environments has not always been avaiable).

<SNIP>
[agent]
    environment = <%= puppet_env %>
</SNIP>
,
In the node manifest:

<SNIP>
  $puppet_env = '$::environment'
</SNIP>

In the puppetmaster puppet.conf:

<SNIP>
[master]

  # Where the puppet manifests live
  templatedir = /opt/puppet/manifests
  modulepath  = $confdir/environments/$environment/modules:$confdir/modules
  manifest    = $confdir/manifests/unknown_environment.pp

[dev]
  manifest = $confdir/manifests/dev.pp
[prod]
  manifest = $confdir/manifests/prod.pp
</SNIP>

Environment specific manifests.  As you can see above, here if the node is 
a dev node, the manifest/dev.pp will be served and it does:

<SNIP>
import 'site.pp'
import 'dev/*.pp'
</SNIP>

site.pp being common dev and prod variables, etc.

Then in the puppetmaster filerserver.conf (example from a erb template), 
change the /opt/puppet path as appropriate.
For further clarification I use extdata and the extlookup function in erb 
templates and have dev.csv and prod.csv extdata files and there is a top 
scope variable of $puppet_repo = '/opt/puppet'
Here is a snippet that serves 
environments/${environment}/{configs,modules,repo} directories to the nodes.

fileserver.conf(.erb):

<SNIP>
[configs]
  path /opt/puppet/environments/<%= environment %>/configs
####
# Environment nodes
<% node_ips.each do |val| -%>
  allow <%= val %>
<% end -%>
<% if cloud_provider == "aws" %># aws allow private IP
  allow <%= ec2_local_ipv4 %><% end %>

[repo]
  path <%= puppet_repo %>/environments/<%= puppet_env %>/repo
####
# Environment nodes
<% node_ips.each do |val| -%>
  allow <%= val %>
<% end -%>
<% if cloud_provider == "aws" %># aws allow private IP
  allow <%= ec2_local_ipv4 %><% end %>
</SNIP>

A note regarding modules and environments, if you have environments 
configured and you have a module is the 
environments/${environment}/modules/module_a you cannot have 
modules/module_a.

Putting it all together....

mysql_proxy example init.pp:

<SNIP>
# mysql-proxy config
  file { '/etc/sysconfig/mysql-proxy':
    owner   => 'root',
    group   => 'root',
    mode    => '0644',
# Here we use an inline_template that calls the file() resource.  The 
template
# resource does not allow to use the "first file found" like the source 
resource
# does.  However the file () resource exits after it finds the first file
# declared and therefore passes the first template found :)
# Novel as per Wolf Nobel's method:
# http://www.mail-archive.com/puppet-users@googlegroups.com/msg27226.html
    content => inline_template(
      file( 
"${puppet_repo}/environments/${puppet_env}/configs/mysql_proxy/files/${hostname}.mysql-proxy.erb",
            
"${puppet_repo}/environments/${puppet_env}/configs/mysql_proxy/files/${puppet_env}.${cloud}.mysql-proxy.erb",
            
"${puppet_repo}/environments/${puppet_env}/configs/mysql_proxy/files/${puppet_env}.mysql-proxy.erb")),
    notify  => Service['mysql-proxy'],
  }
</SNIP>

The inline_template method allows for you to specify different LOCAL 
targets (not via fileserver), so this config would be equally valid and 
work (failover):

<SNIP>
    content => inline_template(
      file( 
"${puppet_repo}/environments/${puppet_env}/configs/mysql_proxy/files/${hostname}.mysql-proxy.erb",
            
"${puppet_repo}/environments/${puppet_env}/configs/mysql_proxy/files/${puppet_env}.${cloud}.mysql-proxy.erb",
            "${puppet_repo}/modules/mysql_proxy/files/mysql-proxy.erb")),
</SNIP>

As I said, a few puppet magic spells are required.  However this allows for 
very flexible environment management.

I use a git repo for puppet and in the puppet repo I have a dev and prod 
branch and automatically update the puppetmasters with git pull origin 
$enviornment, this ensure that the environments are TOTALLY segregated at 
an operational level and a mistaken dev change will not mistakenly be made 
to a prod resource.  Although this also means that there are 2 copies of 
modules, etc, but prod updates are "special" tasks and this allows for easy 
visual directory diffs and diffs, package/repo management per environment, 
etc, etc.

Locally I have:
git/dev/puppet
git/prod/puppet

My working dir is always dev and I always push with "git push origin 
$environment", habit.

Anyway hope some of this is useful.

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Users" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/puppet-users/-/sd-DFUDxYEAJ.
To post to this group, send email to puppet-users@googlegroups.com.
To unsubscribe from this group, send email to 
puppet-users+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/puppet-users?hl=en.

Reply via email to