Our last blog post introduced how Puppet can be used to achieve Infrastructure-As-Code, and how to deploy Play applications following this practice. However, we didn’t address how the applications are actually copied to the host.
Apache Maven is a widely used build tool adopted by more and more companies to support their build process from compilation to deployment. Deploying, in the Maven world, means uploading the artifact to a Maven repository. Such Maven repositories are managed using Sonatype Nexus or JFrog Artifactory. However, this sort of deployment does not address the real provisioning of the application, i.e the deployment on the production servers.
This blog post presents a Puppet module to download Maven artifacts from a Nexus repository. This module closes the gap between the development team deploying their artifacts to a Maven repository, and the administration team responsible for installing and configuring the application.
Why use Puppet to download Maven artifacts ?
The first question you’re probably wondering is “why?”. At akquinet, Apache Maven and Nexus are cornerstones of our build processes. However, dealing with the live deployment still requires manual configuration, copies and so on. This process is error-prone and puts a lot of pressure on the development team. So, we started adopting Continuous Delivery and Infrastructure as Code to improve this last deployment step. But, all our applications and artifacts were stored in Nexus repositories, and the deployment to the production servers requires copying them onto a different type of server (generally via SSH/SCP) to be then deployed to the production servers. Even if these copies were automated using a continuous integration server (such as Jenkins), we’re duplicating the artifacts, making harder to trace the origin of each file. So, it makes a lot of sense to avoid this second server and to retrieve the artifacts directly from Nexus.
The puppet-nexus module is a Puppet extension downloading Maven artifacts from Nexus. Why Nexus? Because it relies on the REST API of Nexus. This Puppet extension supports authentication and repository selection. Actually, we have developed a Bash script to do the job. This script can be used outside of the Puppet module and is just wrapped inside Puppet. But we needed a solution integrated with Puppet and our deployment tool, and which simplified usage of the script.
The Puppet Nexus Module
The Puppet Nexus module defines two entities: The Nexus class and the artifact resource.
The Nexus class is configured with the base url of your Nexus installation and the credentials of the user:
class {'nexus':
url => "http://edge.spree.de/nexus",
username => "nexus",
password => "********"
}
Once done, you can declare nexus::artifacts as follows:
nexus::artifact {'commons-io':
gav => "commons-io:commons-io:2.1",
repository => "public",
output => "/tmp/commons-io-2.1.jar"
}
The artifact is identified using the GAV coordinates (groupId:artifactId:version). The module supports SNAPSHOT versions (downloading the latest snapshot). The classifier and packaging attributes allow you to select the right file:
nexus::artifact {'chameleon web distribution':
gav => "org.ow2.chameleon:distribution-web:0.3.0-SNAPSHOT",
classifier => 'distribution',
packaging => 'zip',
repository => "public-snapshots",
output => "/tmp/distribution-web-0.3.0-SNAPSHOT.zip"
The repository attribute indicates the repository to use, generally a group (i.e. a group of proxies and hosted repositories) such as the public, public-snapshots, central. Check your nexus installation to know which repository you should use.
The output attribute indicates the location of the downloaded artifact. It must be an absolute path (following the Puppet convention).
The ensure parameter can be set to:
- present : does not update the file if already there
- absent : deletes the file if there
- update : updates the file (default)
# Checks that the file is present, downloads it if needed
nexus::artifact {'ipojo-2':
gav => "org.apache.felix:org.apache.felix.ipojo:1.8.0",
repository => "public",
output => "/tmp/ipojo-1.8.jar",
ensure => present
}
# Delete the file
nexus::artifact {'ipojo-1':
gav => "org.apache.felix:org.apache.felix.ipojo:1.8.0",
repository => "public",
output => "/tmp/ipojo-1.8.jar",
ensure => absent
}
# Update the file
nexus::artifact {'ipojo-3':
gav => "org.apache.felix:org.apache.felix.ipojo:1.8.0",
repository => "public",
output => "/tmp/ipojo-1.8.jar",
ensure => update
}
Getting and using the module
To use the presented module, clone the git repository. Once done, configure the modulepath of Puppet in the Puppet configuration file (/etc/puppet/puppet.conf). Once the module is installed correctly, you can download any Maven artifacts from the repositories hosted on your Nexus instance as presented above.
The common pattern is to download an archive containing your application (EAR, ZIP, WAR) and to unzip it (if needed) to the right location such as in the deploy folder of your application server.
Conclusion
This blog post has presented a Puppet Module closing the gap between Maven deployment and the production installation. The Nexus Puppet Module allows you to download Maven artifacts on your production servers. Artifacts are still organized and managed by Nexus. They are downloaded when the application is installed using Puppet.

The Nexus plugin is exactly what I was looking for. Thank you.
Our Maven build assembles tar.gz files and store them in Nexus.
Can you recommend a way for Puppet to deploy those?
Puppetlab recommends packaging RPM instead, but we want to stick with tarballs.
Hi,
In our case we’re using ZIP files. We just unzip them to a specific location using an ‘exec’ executing ‘unzip’. You can simply do the same for tar.gz files.
Is there a Puppet Artifactory module?
Not as far as I know. This module is specific to Nexus because it relies on the REST API provided by Nexus.
Just what I need – thanks. I had issues with the script when used with our Nexus installation, though: having both -L and –location-trusted on the curl line resulted in me jsut getting some text about the redirect URL instead of the artifact. Removing –location-trusted got it working, however..
Great idea.
I’m not sure why, but puppet always tells me that the class nexus couldn’t be found.
In which file i need to create the instance of nexus like
class {‘nexus’:
url => “http://edge.spree.de/nexus”,
username => “nexus”,
password => “********”
}
in init.pp (/etc/puppet/modules/puppet-nexus/manifests/)
or in e.g. site.pp (/etc/puppet/manifests/)?
My modulepath is set to /etc/puppet/modules/
I’m working with SLES 11.2 and puppet 2.6.12
Thanks from Munich
The nexus class must be configured within your site.pp file. But the nexus module must be in /etc/puppet/modules (or whatever is your modules directory).
I love your blog.. very nice colors & theme. Did you make this
website yourself or did you hire someone to do it for
you? Plz answer back as I’m looking to create my own blog and would like to find out where u got this from. appreciate it