What's best practice when combining Roles, Profiles, Containment and Ordering?
I'm attempting to build some custom application modules using the profiles, roles combined with hiera workflow described by Gary Larizza. I'm using Puppet 3.7 open source variant on centos6 nodes but intend to deploy as an enterprise customer once my configuration is in a good enough shape. The problem I'm having is with understanding containment and puppet ordering in this context.
The applications I have are for the most part individual applications and can be used interchangeably in different roles. However several of those applications have dependencies on others under certain use cases.
One use case would be:
- install configure and start app1
- install and configure more stuff
However in a different use case I need to do the following:
- install configure and start app1
- install configure and start app2
- restart app1's service
- install and configure more stuff
I've attempted to implement this as my code example illustrates. Problem is, I can't do that as it creates a dependency loop between app1 and app2. I'm trying to achieve this in a single puppet run as further apps may or may not be dependent on the previous apps being up. I'm trying not do require inside the main app1,app2 modules but abstract them as single services.
I suppose my question(s) here is, am I doing this right? How should I be doing this? Is it even possible to refresh a service twice in a run whilst maintaining order?
roles/manifests/appserver.pp
class role::appserver {
contain profile::app1
contain profile::app2
Class['::app1'] -> Class['::app2'] -> Service['app1']
}
profiles/manifest/app1.pp
class profile::app1 {
class { '::app1': var => 'value' }
contain app1::
}
profiles/manifest/app2.pp
class profile::app2 {
class { '::app2': var => 'value' }
contain app2::
}
modules/app1/manifests/init.pp
class app1 ( $var = app1::params::var ) inherits app1::params {
contain ::app1::install, ::app1::config, ::app1::service
Class['::app1::install'] -> Class['::app1::config'] -> Class['::app1::service']
}
class app1::install inherits app1 {
package { 'app1': ensure => installed }
}
class app1::config inherits app1 {
file { 'app1.conf': ensure => file }
}
class app1::service inherits app1 {
service{ 'app1': ensure => running }
}
modules/app2/manifests/init.pp
class app2 ( $var = app2::params::var ) inherits app2::params {
contain ::app2::install, ::app2::config, ::app2::service
Class['::app2::install'] -> Class['::app2::config'] -> Class['::app2::service']
}
class app2::install inherits app2 {
package {'app2': ensure => installed }
}
class app2::config inherits app2 {
file {'app2.conf': ensure => file }
}
class app2::service inherits app2 {
service{'app2': ensure => running }
}
In your 2nd use case, does app2's installation/startup depend on app1 running? Also, does installing/starting app2 then modify a file that app1 depends on and must be reloaded before the subsequent installations can take place?
App2 depends on app1 being installed, but not necessarily started. Subsequent modules apps do depend on app1 and app2 being started. For now what I've done to work around the dependency loop is simply write a custom exec to bounce app1's service once app2 is up. Not ideal
I think the answer from @cbarbour will be key to your solution. You can make app2's profile class depend on app1's profile class, then make other classes depend on those app services starting up.