Search code examples
apachecapistranopuppet

Provisioning server with Puppet, deploying with Capistrano


I'm having issues with provisioning a server via Puppet that is compatible with a Capistrano deployment. I'm using puppetlabs/apache to setup my virtualhosts, and it is (rightfully) checking that the docroot exists (and creating it if it doesn't, ignoring potential nested directory issues). However, the true docroot will be /var/www/vhosts/${::fqdn}/current/public, and Capistrano will be creating the appropriate symlink (from current to releases/{releasestamp}) when deploying, and is not happy when that directory path is setup by Puppet in advance (due to current being an actual directory, instead of a symlink, and not being empty).

I've thought about adding something like:

file { "/var/www/vhosts/${::fqdn}/current":
  ensure => 'link',
  target => '/tmp/initial'
}

and setting up a blank file at /tmp/initial/public/index.html, so that Capistrano will be able to point current to the appropriate release when deploying. However, this means that whenever someone re-runs the provision (to apply any configuration changes, for example), the symlink will be relocated to the junk directory (if it even exists at that point).

Any suggestions? I've considered splitting the provision into an application provision and server provision, and having Capistrano execute the application provision when deploying, but I'd really prefer to keep this concise.


Solution

  • You should just use Puppet to create the application directory, and let Capistano take care of creating the releases and shared directories using the cap deploy:setup task, and laying down the current symlink when deploying a new version with cap deploy.

    In more concrete terms, I recommend having this in your Puppet config:

    file { "/var/www/vhosts/${::fqdn}":
      ensure => 'directory'
    }
    

    Then, as a one-time setup step, run this task to instruct Capistrano to create the releases and shared directories within the /var/www/vhosts/${::fqdn} directory Puppet should have created for you:

    cap deploy:setup
    

    And thereafter, simply run cap deploy to deploy your app, which will create or update the current symlink for you.

    (Note that you can pass the -n option to cap to preview the exact commands Capistrano will run, For instance, cap -n deploy:setup will show the mkdir commands it runs.)

    Updated

    Puppet's standard Apache module seems to require that docroot exist, which it does using the following:

    # This ensures that the docroot exists
    # But enables it to be specified across multiple vhost resources
    if ! defined(File[$docroot]) {
      file { $docroot:
        ensure => directory,
        owner  => $docroot_owner,
        group  => $docroot_group,
      }
    }
    

    But you may be able to disable that using the following:

    file { "/var/www/vhosts/${::fqdn}/current/public":
      ensure => directory,
      replace => false,  # don't replace the directory once Capistrano makes it a symlink
    }
    

    Just defining the resource yourself may prevent the if ! defined(File[$docroot]) part of the apache::vhost module from running.