Downloading artifacts from a Maven repository with Ansible

AnsibleLogoAn example of downloading artifacts from a Maven repository using Ansible, including a prebuilt Docker image.

Prerequisites

Install JDK and Maven using existing Ansible modules

ansible-galaxy install geerlingguy.java
ansible-galaxy install https://github.com/silpion/ansible-maven.git
- hosts: localhost

 roles:
 - { role: ansible-maven }
 - { role: geerlingguy.java }

 vars:
 java_packages:
 - java-1.7.0-openjdk

Example

From mvn.yml, download any number of Maven artifacts optionally from different repositories

- hosts: localhost

 vars:
 mvn_artifacts:
 - id: org.apache.maven:maven-core:2.2.1:jar:sources
 dest: /tmp/test.jar
 # params: -U # update snapshots
 # repos:
 # - http://repo1.maven.apache.org/maven2
 
 tasks:
 - name: copy maven artifacts
 command: mvn {{ item.params | default('') }} org.apache.maven.plugins:maven-dependency-plugin:get -Dartifact={{ item.id }} -Ddest={{ item.dest }} -Dtransitive=false -Pansible-maven -DremoteRepositories={{ item.repos | default(['http://repo1.maven.apache.org/maven2']) | join(",") }}
 with_items: mvn_artifacts

Docker

An image with Ansible, JDK and Maven preinstalled is available at csanchez/ansible-maven.

Continuous Delivery with Maven, Puppet and Tomcat – Video from ApacheCon NA 2013

Apachecon NA 2013A little bit late but finally the video from my session at ApacheCon Portland is available. That was the first version of the talk that I just gave at Agile testing Days which unfortunately was not recorded.

Description
Continuous Integration, with Apache Continuum or Jenkins, can be extended to fully manage deployments and production environments, running in Tomcat for instance, in a full Continuous Delivery cycle using infrastructure-as-code tools like Puppet, allowing to manage multiple servers and their configurations.

Abstract
Puppet is an infrastructure-as-code tool that allows easy and automated provisioning of servers, defining the packages, configuration, services,… in code. Enabling DevOps culture, tools like Puppet help drive Agile development all the way to operations and systems administration, and along with continuous integration tools like Apache Continuum or Jenkins, it is a key piece to accomplish repeatability and continuous delivery, automating the operations side during development, QA or production, and enabling testing of systems configuration.

Traditionally a field for system administrators, Puppet can empower developers, allowing both to collaborate coding the infrastructure needed for their developments, whether it runs in hardware, virtual machines or cloud. Developers and sysadmins can define what JDK version must be installed, application server, version, configuration files, war and jar files,… and easily make changes that propagate across all nodes.

Using Vagrant, a command line automation layer for VirtualBox, they can also spin off virtual machines in their local box, easily from scratch with the same configuration as production servers, do development or testing and tear them down afterwards.

We will show how to install and manage Puppet nodes with JDK, multiple Tomcat instances with installed web applications, database, configuration files and all the supporting services. Including getting up and running with Vagrant and VirtualBox for quickstart and Puppet experiments, as well as setting up automated testing of the Puppet code.

Binary Repository Management refcard on DZone

DZone logoBinary Repository Management refcard on DZone The people at DZone were kind enough to ask me to write a refcard on Binary Repository Management a few months ago, and it’s now available for download.

I wrote about benefits and best practices when using a repository and compare the three tools in the space: Apache Archiva, Sonatype Nexus and JFrog Artifactory.

Puppet Module of the Week: maestrodev/maven – Maven repository artifact downloads

This is a guest post I wrote in the Puppetlabs blog for their Module of the Week program about the MaestroDev/maven module we created.

Module of the Week: maestrodev/maven – Maven repository artifact downloads

Purpose Manage Apache Maven installation and download artifacts from Maven repositories
Module maestrodev/maven
Puppet Version 2.7+
Platforms RHEL5, RHEL6

The maven module allows Puppet users to install and configure Apache Maven, the build and project management tool, as well as easily use dependencies from Maven repositories.

If you use Maven repositories to store the artifacts resulting from your development process, whether you use Maven, Ivy, Gradle or any other tool capable of pushing builds to Maven repositories, this module defines a new maven type that will let you deploy those artifacts into any Puppet managed server. For instance, you can deploy WAR files directly from your Maven repository by just using their groupId, artifactId and version, bridging development and provisioning without any extra steps or packaging like RPMs or debs.

The maven type allows you to easily provision servers during development by using SNAPSHOT versions—using the latest build for provisioning. Together with a CI tool, this enables you to always keep your development servers up to date.

In this first version, this module supports

  • Installing Apache Maven
  • Configuring Maven settings.xml for repository configuration
  • Configuring Maven environment variables
  • Downloading artifacts from Maven repositories

Installing the module

Complexity Easy
Installation Time 2 minutes

Installing the Maven module is as simple as using the Puppet module tool, available in Puppet 2.7.14+ and Puppet Enterprise 2.5+, and also available as a RubyGem:

$ puppet module install maestrodev-maven
Preparing to install into /etc/puppet/modules ...
Downloading from http://forge.puppetlabs.com ...
Installing -- do not interrupt ...
/etc/puppet/modules
└─┬ maestrodev-maven (v0.0.1)
  └── maestrodev-wget (v0.0.1)

Alternatively, you can install the Maven module manually:

$ cd /etc/puppet/modules/

$ wget http://forge.puppetlabs.com/system/releases/m/maestrodev/maestrodev-maven-0.0.1.tar.gz

$ tar zxvf maestrodev-maven-0.0.1.tar.gz && rm maestrodev-maven-0.0.1.tar.gz
$ mv maestrodev-maven-0.0.1 maven
$ wget http://forge.puppetlabs.com/system/releases/m/maestrodev/maestrodev-wget-0.0.1.tar.gz
$ tar zxvf maestrodev-wget-0.0.1.tar.gz && rm maestrodev-wget-0.0.1.tar.gz
$ mv maestrodev-wget-0.0.1 wget

Resource Overview

CLASSES

maven class

This class installs Apache Maven with a default version of 2.2.1

maven::maven class

Installs Apache Maven, allowing you to specify the version of Maven you wish to install

DEFINITIONS

maven::environment

The definition allows us to configure Apache Maven environment variables on a per-user basis.

maven::settings

Configures $HOME/.m2/settings.xml per user with repositories, mirrors, credentials and properties.

TYPES

maven

This new type lets us download files from remote Maven repositories. Maven must be previously installed.

Testing the module

The module includes some Puppet rspec tests that use the puppetlabs_spec_helper, so it’s simple to implement, and all the fixtures will be automatically downloaded and tests run.

There is a Gemfile included to install all the dependent gems, so after running

$ bundle install

The tests can be executed with

$ bundle exec rake spec

Configuring the module

Complexity Easy
Installation Time 5 minutes

To install Maven there are two options, a simple one to install the default version (2.2.1):

include maven

or a slightly more complex option that customizes the version:

class { "maven::maven":
  version => "3.0.4"
}

Maven will be downloaded by default from the main Apache archive location. It can be configured to be downloaded from a different repository, like one in the local network, by using this repository syntax used throughout the module.

$repo = {
  id       => "myrepo",
  username => "myuser",
  password => "mypassword",
  url      => "http://repo.acme.com",
  mirrorof => "external:*" # if you want to use the repo as a mirror, see maven::settings below
}

class { "maven::maven":
  version => "3.0.4",
  repo    => $repo
}

Once you have Maven installed you can configure the Maven settings.xml for different users, override the mirrors, servers, localRepository, active properties and default repository. It is particularly useful to force Maven to use a repository in the internal network for faster downloads. These settings are used by both command line Maven and the maven puppet type.

We are using hashes to be able to reuse repository definitions, without copy and paste, like the $repo definition above.

# Create a settings.xml with the repo credentials
maven::settings { 'maven' :
  mirrors             => [$central], # mirrors entry in settings.xml, uses id, url, mirrorof from the hash passed
  servers             => [$central], # servers entry in settings.xml, uses id, username, password from the hash passed
  user                => 'maven',
  default_repo_config => {
    url       => $repo['url],
    snapshots => {
      enabled      => 'true',
      updatePolicy => 'always'
    },
    releases  => {
      enabled      => 'true',
      updatePolicy => 'always'
    }
  }
  properties          => {
    myproperty => 'myvalue'
  },
  local_repo          => '/home/maven/.m2/repository'
}

We can override the central repository with mirrors, whichb add repositories to the mirrors settings. The servers parameter configures each settings.xml server entry for user and password credentials.

With default_repo_config, we can add a repository that will be enabled for all Maven executions, including the aven puppet type. That would be necessary in order to check a remote repository for snapshots, as there is no snapshot repository defined by default in Maven.

The properties parameter is a hash with keys and values for the properties section of the settings, while local_repo overrides Maven default local repository location.

Another Maven file that can be configured to alter the Maven environment variables is $HOME/.mavenrc with the maven::environment class. The .mavenrc is sourced by the Apache Maven script for each run.

maven::environment { 'env-maven-user' :
  user                 => 'maven',
  maven_opts           => '-XX:MaxPermSize=256m',
  maven_path_additions => '/usr/local/bin'
}

Probably the module’s most useful functionality is the ability to download artifacts from Maven repositories. This requires having Maven correctly installed and configured, which can be done with the previous classes and definitions, and uses the Maven dependency:get plugin behind the scenes. The title of the maven resource is used as the file destination, and the user to run maven as can be set with the user parameter.

maven { "/tmp/maven-core-2.2.1.jar":
  id    => "org.apache.maven:maven-core:2.2.1:jar",
  repos => ["central::default::http://repo.maven.apache.org/maven2","http://mirrors.ibiblio.org/pub/mirrors/maven2"],
  user  => "maven",
}

With the optional parameter repos, we can define what repositories to download the dependencies from if not using the default Maven central. The parameter is in the form expected by the Maven dependency plugin, that is id::[layout]::url or just url, separated by a comma.

Or, a little more verbose:

maven { "/tmp/maven-core-2.2.1-sources.jar":
  groupid    => "org.apache.maven",
  artifactid => "maven-core",
  version    => "2.2.1",
  classifier => "sources",
  packaging  => "jar",
  user       => "maven",
}

Example usage

With some simple declarations we can install Maven in a node, downloading the Apache Maven binaries from apache.org and uncompressing them under /usr/local, and then download any file from the central Maven repo. An example is maven-core-2.2.1.jar, which is located in the repository under org.apache.maven groupId and maven-core artifactId.

# Install Maven
class { "maven::maven": } ->

maven { "/tmp/maven-core-2.2.1.jar":
  id => "org.apache.maven:maven-core:2.2.1:jar",
}

The usage of the shorter form groupId:artifactId:version:packaging allows us to be more concise, but we could do the same using the groupid, artifactid, version, packaging parameters of the maven type. Note that we are using the chain arrow (->) to explicitly install Maven before using it to download the jar file.

You should have a /tmp/maven-core-2.2.1.jar file with contents matching those of http://repo.maven.apache.org/maven2/org/apache/maven/maven-core/2.2.1/maven-core-2.2.1.jar.

Conclusion

If you use Apache Maven this module comes in handy for installing and configuring it on any machine in a consistent and repeatable way. This module also consumes the output artifacts from the development process in later stages of product delivery without extra steps or re-packaging.

Please let us know if you have any issues with the module. We are looking for new ways to improve the module, such as removing the need for wget to be installed. We look forward to your feedback!

Learn More:

Puppet for Java developers talk at JavaZone Oslo 2012

I am in Oslo right now speaking at JavaZone about Puppet for Java developers covering some of the basics but then getting into using Vagrant, Puppet and Puppet modules, to manage maven dependencies, postgresql, tomcat, and apache as examples.

The sample code showcases how to effectively use Puppet and modules, with unit testing and testing with Vagrant.

Update: The video is now up. Run a bit short on time and didn’t have as much time as I wanted for the demo but hopefully the sample code is useful to understand the tools involved.

Puppet is an infrastructure-as-code tool that allows easy and automated provisioning of servers, defining the packages, configuration, services,… in code. Enabling DevOps culture, tools like Puppet help drive Agile development all the way to operations and systems administration, and along with continuous integration tools like Jenkins, it is a key piece to accomplish repeatability and continuous delivery, automating the operations side during development, QA or production, and enabling testing of systems configuration.
Traditionally a field for system administrators, Puppet can empower developers, allowing both to collaborate coding the infrastructure needed for their developments, whether it runs in hardware, virtual machines or cloud. Developers and sysadmins can define what JDK version must be installed, application server, version, configuration files, war and jar files,… and easily make changes that propagate across all nodes.
Using Vagrant, a command line automation layer for VirtualBox, they can also spin off virtual machines in their local box, easily from scratch with the same configuration as production servers, do development or testing and tear them down afterwards.
We’ll show how to install and manage Puppet nodes with JDK, multiple application server instances with installed web applications, database, configuration files and all the supporting services. Including getting up and running with Vagrant and VirtualBox for quickstart and Puppet experiments, as well as setting up automated testing of the Puppet code.

Infrastructure as Code

DevOps is not about the tools

That’s true, in the same way that agile is not about the tools either, it’s a set of ideas, concepts, best practices,…

Nice, but… how can I successfully implement it?

Tools can enable change in behavior and eventually change culture [Patrick Debois]

Printer in 1568

The same way the Guttemberg printer was a tool that enabled a cultural change, or that Agile development wouldn’t be possible without Continuous Integration servers, DevOps relies on some tools to implement its principles.

Unfortunately, the same way everyone thinks of themselves as being intelligent enough, and every tool out there is magically cloud enabled, now every tool claims to be DevOps.

However, there is agreement that tools that allow us to deal with infrastructure as code are key on implementing DevOps concepts.

It’s all been invented already, now it’s standardized with tools like Chef or Puppet. Before, you could write your own scripts to automate server installation, configuration,… but everyone would do it their very own way.

Now there’s some common language used by Puppet or by Chef, that allows to share and reuse configuration as modules or recipes.

Infrastructure as Code, a key concept

The concept that infrastructure should be treated as code is really powerful. Server configuration, packages installed, relationships with other servers,… should be modeled with code to be automated and have a predictable outcome, removing manual steps prone to errors. Doesn’t sound bad, does it?

But new solutions bring new challenges, and when infrastructure is code we face the same problems faced by developers.

  • What version of the infrastructure are we using in production?
  • how can we ensure that when an issue is found it gets fixed and redeployed?
  • how can we test the infrastructure as we develop it?

That’s why when dealing with infrastructure as code we should follow development best practices.

For instance we can (and should!)

  • tag, branch and release the code that define our servers.
  • have a lifecycle that covers different stages through the infrastructure code, ie. dev, QA, production.
  • continuously test our infrastructure as we make changes.

Is DevOps killing the Operations team?

To make error is human. To propagate error to all server in automatic way is DevOpsHearing everywhere about DevOps and how it is all about automation, and how manual steps should be removed from Operations. Starting to worry about your OPs job?

On one hand, yes, you should worry.

My job is to make other people’s jobs unnecessary.

While I was working on Maven the goal was to automate and standardize all the build steps so there’s no more need to have a magician build master that is the only one that knows how to build the software. All Maven projects are built in the same way and there’s no need to do any manual step. That ended the build master job in many companies as they knew it. Those that were interested enough moved on to do more useful tasks, like setting up continuous integration servers, integrating new quality assurance tools, adding metrics,…

So, on the other hand, no, you shouldn’t worry as long as you want to explore new areas, because there’s still plenty to improve. Stop doing tedious manual tasks and focus on what’s really important.

You should just worry about the NOOPS guys 😉

FOSDEM

The slides from my From Dev to DevOps talk at FOSDEM 2012 Brussels are up in Slideshare. The material is also in the Lanyrd page.

The conference was huge, I’ve heard that over 4000 people showed up this year, for this free (as in both software and beer) event, organized on several tracks. Not bad considering that the temperature was between -15 and -6C (5 and 23 Fahrenheit) and got a lot of snow.

I spoke on the main auditorium with capacity for 1400 people, there was plenty of space. Unfortunately (for me, but great for the other speakers and the organization) some other devrooms got filled quickly, and couldn’t get into the Configuration and Systems Management Devroom, which should have been really good as nobody left as I was waiting outside between talks 😦

A lot of care by the organization, including a note with a 24/7 phone number in case I got “lost/confused/arrested” (which makes me think it must have happened before), and a full commitment to promote belgian beer 😉

And thanks to the people that attended my talk and engaged through twitter, got great feedback and hints for improvements on the future of development and infrastructure automation!

Grand Place 360 panorama

From Dev to DevOps slides from ApacheCON NA Vancouver 2011

ApacheCON NA 2011The slides from my From Dev to DevOps talk at ApacheCON NA 2011 Vancouver. Thanks to all the attendees for coming!

The audio recording seems that it’s going to be uploaded to FeatherCast.

UPDATE: the Lanyrd official page is up too

The code for the Maven-Puppet module is avalable in GitHub, and I’ll write some posts about it in the coming weeks.

The DevOps movement aims to improve communication between developers and operations teams to solve critical issues such as fear of change and risky deployments. But the same way that Agile development would likely fail without continuous integration tools, the DevOps principles need tools to make them real, and provide the automation required to actually be implemented. Most of the so called DevOps tools focus on the operations side, and there should be more than that, the automation must cover the full process, Dev to QA to Ops and be as automated and agile as possible. Tools in each part of the workflow have evolved in their own silos, and with the support of their own target teams. But a true DevOps mentality requires a seamless process from the start of development to the end in production deployments and maintenance, and for a process to be successful there must be tools that take the burden out of humans.

Apache Maven has arguably been the most successful tool for development, project standardization and automation introduced in the last years. On the operations side we have open source tools like Puppet or Chef that are becoming increasingly popular to automate infrastructure maintenance and server provisioning.

In this presentation we will introduce an end-to-end development-to-production process that will take advantage of Maven and Puppet, each of them at their strong points, and open source tools to automate the handover between them, automating continuous build and deployment, continuous delivery, from source code to any number of application servers managed with Puppet, running either in physical hardware or the cloud, handling new continuous integration builds and releases automatically through several stages and environments such as development, QA, and production.

Vancouver harbour panorama