Solita CD Tools¶
This is a collection of Continuous Delivery tools and documentation built by Solita. It is released under the MIT license.
Tutorials¶
Jenkins Configuration Management¶
This tutorial will show you how to manage the configuration of a Jenkins installation with Ansible and Jenkins Job DSL. At the end of the tutorial, you’ll have your Jenkins installation’s configuration under version control and you’ll be able to test changes to the configuration locally in a virtual machine before applying them to your CI server.
First we’ll create a configuration for a Jenkins installation that runs on your computer in a virtual machine. Then we’ll apply the same configuration to a Linux server, either updating the configuration of an existing Jenkins installation or creating a new installation.
This tutorial covers the basics of Vagrant, Ansible and Jenkins Job DSL. If you’re proficient with all these tools, you can probably skip this tutorial and jump straight to the reference documentation of the solita.jenkins Ansible role.
Prerequisites¶
Before continuing with this tutorial, you need to have the following software installed:
We’ll be using Git via its command-line interface, but don’t worry if you don’t have experience with it – the instructions should be clear enough. (If they are not, please create an issue!)
Setting up the Virtual Machine¶
One of the biggest benefits of configuration management is that we can test our changes on a test server before applying them to a production server. Virtual machines work especially well as test servers because if we make a mistake and get a server into a funny state, we can simply destroy it and recreate it in a known state.
We’ll manage our virtual machines with a tool called Vagrant, which allows us to describe what kind of machines we want with a simple text-based configuration file. Vagrant supports many different virtualization tools, but we’ll be using VirtualBox, which should have been installed along with Vagrant.
First we’ll create a directory that will hold both our Jenkins configuration and the Vagrant configuration of the virtual machine that we use for testing. As a starting point, we’ll use a Ubuntu-based Vagrant configuration that pre-installs Ansible, which we’ll need later in this tutorial. We need to clone it with Git, so open up a terminal (on Linux and OS X) or Git Bash (on Windows).
Note
The shell starts in your home directory (/home/yourname
, /Users/yourname
, or C:\Users\yourname
). If you want to place your Jenkins configuration somewhere else, change the directory with cd
:
# Linux and OS X
cd /where/you/want/the/conf
# Windows. Git Bash doesn't like the backslashes in Windows-style paths, so
# we need to put the path in single quotes.
cd 'C:\where\you\want\the\conf'
Clone the Vagrant configuration that we’ll use as our starting point:
git clone https://github.com/solita/vagrant-ansible.git jenkins
Note
The configuration we just cloned initializes the virtual machine with the IP address 192.168.50.76
. If you want to use some other address, find 192.168.50.76
in the file called Vagrantfile
and replace it with another value before you run vagrant up
.
Now enter the cloned repository, which contains our Vagrant configuration, and start the virtual machine with vagrant up
:
cd jenkins
vagrant up
With this command, Vagrant downloads a disk image of an empty Ubuntu server, boots a virtual machine, and sets it up according to its configuration file (the Vagrantfile
). This will take several minutes, so now is good time to go grab a coffee (or a non-caffeinated beverage, if it’s getting late and you don’t want to mess up your night’s sleep).
If all goes well, the command’s output should look something like this:
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'ubuntu/trusty64'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'ubuntu/trusty64' is up to date...
==> default: Setting the name of the VM: jenkins_default_1450333475157_82556
==> default: Clearing any previously set forwarded ports...
...
blah blah blah
...
==> default: Collecting pycrypto>=2.6 (from ansible==2.0.0)
==> default: Collecting ecdsa>=0.11 (from paramiko->ansible==2.0.0)
==> default: Using cached ecdsa-0.13-py2.py3-none-any.whl
==> default: Collecting MarkupSafe (from jinja2->ansible==2.0.0)
==> default: Installing collected packages: ecdsa, pycrypto, paramiko, MarkupSafe, jinja2, PyYAML, ansible
==> default: Running setup.py install for ansible
==> default: Successfully installed MarkupSafe-0.23 PyYAML-3.11 ansible-2.0.0 ecdsa-0.13 jinja2-2.8 paramiko-1.16.0 pycrypto-2.6.1
Now that the virtual machine is up and running, we can connect to it with SSH:
vagrant ssh
If everything’s working, you should be greeted with the following output:
Welcome to Ubuntu 14.04.3 LTS (GNU/Linux 3.13.0-71-generic x86_64)
* Documentation: https://help.ubuntu.com/
System information as of Thu Dec 17 06:24:57 UTC 2015
System load: 0.76 Processes: 80
Usage of /: 3.4% of 39.34GB Users logged in: 0
Memory usage: 25% IP address for eth0: 10.0.2.15
Swap usage: 0%
Graph this data and manage this system at:
https://landscape.canonical.com/
Get cloud support with Ubuntu Advantage Cloud Guest:
http://www.ubuntu.com/business/services/cloud
0 packages can be updated.
0 updates are security updates.
(ansible-1.9-env)vagrant@vagrant-ubuntu-trusty-64:/ansible$
You’re now in a shell on the virtual machine and any commands you type here are executed on the virtual machine, not on your own. To get back to the shell on your own machine, use the exit
command in the virtual machine’s shell:
(ansible-1.9-env)vagrant@vagrant-ubuntu-trusty-64:/ansible$ exit
logout
Connection to 127.0.0.1 closed.
Vagrant Survival Guide¶
You can always get back to the virtual machine’s shell by following the same steps we just used:
- Enter the Jenkins configuration directory:
cd /path/to/jenkins
- Start the virtual machine if it has been stopped:
vagrant up
- Open a shell on the virtual machine:
vagrant ssh
If you don’t need the virtual machine and want to free the memory and CPU resources it’s using, you can stop it with vagrant halt
.
To free the disk space allocated to the virtual machine, you can destroy it with vagrant destroy
. Note that the virtual machine is not stored in the same directory as its Vagrantfile
, so just removing the jenkins
directory won’t destroy the virtual hard disk.
Finally, for advanced management and debugging, start Oracle VM VirtualBox, the VirtualBox management interface, from your operating system’s menu. There you can see VirtualBox’s logs or shut down and destroy a virtual machine even if you’ve lost Vagrant’s bookkeeping files and can’t manage the machine with Vagrant.
For more information, see the documentation for Vagrant and VirtualBox.
Installing Jenkins with Ansible¶
We want our Jenkins installations to be as reproducible as possible, so our goal is to configure nothing by hand. Instead, we describe the configuration that a server should have and let Ansible make the required changes. These descriptions are written in the YAML format in files called playbooks.
Let’s create a playbook that tells Ansible that the Vagrant-managed virtual machine should have Jenkins installed. Create a new file called jenkins.yml
in the jenkins
directory with the following contents:
1 2 3 4 | ---
- hosts: vagrant
roles:
- solita.jenkins
|
We won’t go into details of Ansible playbooks – for that, see Ansible’s documentation – but here’s a big-picture view of what each line in the file contains:
- Begin a new YAML document.
- Configure the server called “vagrant” (that’s our virtual machine).
- Apply some roles – reusable pieces of Ansible configuration – to the server.
- The only role we need is solita.jenkins.
Note
YAML is very fussy about indentation, so make sure that you indent each line exactly as shown. You should also change your editor to only add spaces and never tabs.
Installing and Updating Roles¶
We use the role solita.jenkins, so we need to tell Ansible where it can be found. Create a file called requirements.yml
in the jenkins
directory:
---
- src: https://github.com/solita/ansible-role-solita.jenkins.git
name: solita.jenkins
Because Ansible does not officially support Windows, we’ll be running it in our virtual machine, so connect to it with vagrant ssh
. There you can use update-roles.sh
to install the role:
c:\> vagrant ssh
$ ./update-roles.sh
Under the hood the script uses Ansible galaxy to install role with dependencies.
Note
If you get a message saying [ERROR]: Unable to open requirements.yml
, you may have created the file in the wrong directory. Make sure you have a file called requirements.yml
in the jenkins
directory, next to the Vagrantfile
.
If you get message saying -bash: ./update-roles.sh: Permission denied
the script has lost execution right somehow. Call chmod +x update-roles.sh
to add the permission to execute the script.
Running the Playbook¶
Now that we have installed our playbook’s dependencies (the solita.jenkins role), you can run the playbook:
ansible-playbook -i environments/vagrant/inventory jenkins.yml
This will take some time as Ansible has to download some large packages (Java and Jenkins). Unfortunately there’s no way to monitor a task’s progress in Ansible, so you just have to trust that it’s not stuck, even if it’s taking a long time.
Once the playbook run is complete, Jenkins should be installed, running, and listening on the virtual machine’s port 8080. The virtual machine’s IP address is 192.168.50.76
, so you can access the Jenkins installation with a web browser at http://192.168.50.76:8080/.

Configuring Jenkins¶
The Jenkins installation we just created (in Installing Jenkins with Ansible) is now in its default settings. To change the settings, we set variables in the playbook.
By default the Jenkins installation is unsecured and anonymous users can act as administrators. Let’s secure the installation and add a password-protected user account.
We can see in the documentation of the solita.jenkins role that we need to set the variables solita_jenkins_security_realm
and solita_jenkins_users
. We can do that by changing the playbook jenkins.yml
like this (the lines 3 to 6 are new):
1 2 3 4 5 6 7 8 | ---
- hosts: vagrant
vars:
solita_jenkins_security_realm: jenkins
solita_jenkins_users:
- some_user
roles:
- solita.jenkins
|
To apply the changes to the Jenkins installation, run the playbook just as before:
ansible-playbook -i environments/vagrant/inventory jenkins.yml
If you now try to access Jenkins, you will be redirected to a login screen:

To log in as some_user
, we have to know the user’s password. When solita.jenkins creates a new user, it writes the user’s default password into a file called solita_jenkins_default_password
next to the Ansible inventory file (the file we passed to ansible-playbook
with the -i
option). You can print the file’s contents with cat
on the virtual machine:
cat environments/vagrant/solita_jenkins_default_password/some_user
Alternatively, since the virtual machine’s /ansible
directory is synchronized with the jenkins
directory on your machine, you can just open the file with a text editor.
Open the file and read the password, and you should be able to use it to log in as some_user
.
Further configuration¶
solita.jenkins can do much more than just add users. See its documentation for all of the configuration options.
Ansible Roles¶
solita.jenkins¶
A Jenkins installation completely configured with Ansible. This role builds on top of geerlingguy.jenkins, adding the following features:
- User management
- Job and view configuration with Job DSL
This role is tested on Ubuntu 14.04 LTS (Trusty Thar), but it should work on all operating systems supported by the upstream role.
Example¶
With this role and the Job DSL plugin, your entire Jenkins configuration can be stored in text files that look something like this:
# playbook.yml
---
- hosts: jenkins-server
vars:
solita_jenkins_plugins:
- timestamper
- git
solita_jenkins_security_realm: jenkins
solita_jenkins_users:
- alice
- bob
solita_jenkins_absent_users:
- eve
roles:
- solita.jenkins
// jobs/Main.groovy
job('DSL-Tutorial-1-Test') {
scm {
git('git://github.com/jgritman/aws-sdk-test.git')
}
triggers {
scm('*/15 * * * *')
}
steps {
maven('-e clean test')
}
}
Installation¶
You can install this role and its dependencies with ansible-galaxy. First add the following lines to your requirements.yml
:
# requirements.yml
---
- src: https://github.com/solita/ansible-role-solita.jenkins.git
version: v1.3.2
name: solita.jenkins
Then run ansible-galaxy
to install the role:
ansible-galaxy install -p path/to/your/roles -r requirements.yml
Plugins¶
To add plugins to your Jenkins installation, list their plugin IDs in the variable solita_jenkins_plugins
. You can find a plugin’s ID on its wiki page.
Note
This role depends on the Job DSL plugin and always installs it.
To limit role application to plugins, use the tag solita_jenkins_plugins
.
Examples¶
Install the timestamper
and git
plugins:
# playbook.yml
---
- hosts: jenkins-server
vars:
solita_jenkins_plugins:
- timestamper
- git
roles:
- solita.jenkins
Security¶
A security realm means the method that Jenkins uses to authenticate users. To enable or disable authentication for your Jenkins installation, set the variable solita_jenkins_security_realm
to one of the following values:
none
- Disables security.
jenkins
- The default setting. Enables security, authentication against Jenkins’ own user database, and matrix-based authorization.
User Management¶
To add and remove users, add their usernames to the lists solita_jenkins_users
and solita_jenkins_absent_users
, respectively.
Note
User management is only available when solita_jenkins_security_realm
is set to 'jenkins'
.
Note
Currently only administrator users are supported.
When a new user is created, the user’s default password will be read from the file solita_jenkins_default_password/<username>
in the inventory directory. If the file does not exist, a file containing a random password is created. For example, if your inventory file is environments/vagrant/inventory
and you add the user alice
, you can find their default password in the file environments/vagrant/solita_jenkins_default_password/alice
.
Note
If you don’t have an inventory file (e.g. if you create the servers using the Ansible cloudformation module), solita.jenkins
will try to write the generated passwords into /etc/ansible/solita_jenkins_default_password/
and fail. In this case you can set the variable solita_jenkins_password_dir
to the directory where you want to place the passwords.
To limit role application to security settings and user management, use the tag solita_jenkins_security
.
Examples¶
Enable security, add users alice
and bob
, and remove user eve
:
# playbook.yml
---
- hosts: jenkins-server
vars:
solita_jenkins_security_realm: jenkins
solita_jenkins_users:
- alice
- bob
solita_jenkins_absent_users:
- eve
roles:
- solita.jenkins
Disable security:
# playbook.yml
---
- hosts: jenkins-server
vars:
solita_jenkins_security_realm: none
roles:
- solita.jenkins
Only update security settings and users:
ansible-playbook playbook.yml --tags solita_jenkins_security
Place the generated passwords in /tmp/default-passwords
:
ansible-playbook playbook.yml -e solita_jenkins_password_dir=/tmp/default-passwords
Credentials¶
The Jenkins credentials plugin allows you to store credentials in Jenkins. This role allows you to add, change and remove those credentials.
Managing Credentials¶
You should never store credentials in your regular playbooks or inventories. Instead use Ansible Vault to create an encrypted file for them:
# Create a new encrypted file:
ansible-vault create group_vars/all/credentials
# Edit an existing encrypted file:
ansible-vault edit group_vars/all/credentials
To add or modify credentials, add them to solita_jenkins_credentials
, which is a map from credential ID to the credential itself. To remove credentials, list their IDs in solita_jenkins_absent_credentials
.
Examples¶
Add a username/password credential with the ID alice
, and an SSH key with
the id bob
:
# Encrypted var file
---
solita_jenkins_credentials:
alice:
username: alice
password: swordfish
description: Alice's password # Optional
bob:
username: bob # Optional
private_key: |
-----BEGIN RSA PRIVATE KEY-----
MIIJKgIBAAKCAgEAr959S9hp6tUFqrVzxs31+vYZWyKHia9SBWtmRthDlO/uMnr/
VoEnRVqUmjlJcgSMhIl7d5Daqkc8sxMjzipklD6ZvIliQRsiEMePuIQs5i8/u9jO
...
gTUbb3MzN7f+G2zihIl5uu8Lp7hzeRnvJ6tP3jeVPog9SRcX6Ve8kZr/T+chVQ4t
da0O2tRUD1uRrlEovhL3PQT2fTzkV8F4YEOl5afVopLb1fK6sDef2i0jr1P0vw==
-----END RSA PRIVATE KEY-----
passphrase: swordfish # Optional
description: Bob's SSH Key # Optional
# playbook.yml
---
- hosts: jenkins-server
roles:
- solita.jenkins
Note
Use YAML’s pipe syntax to keep the linebreaks in the private key.
Remove the credentials with the ID eve
:
# playbook.yml
---
- hosts: jenkins-server
vars:
solita_jenkins_absent_credentials:
- eve
roles:
- solita.jenkins
Only update credentials:
ansible-playbook playbook.yml --tags solita_jenkins_credentials
Jobs and Views¶
You can define jobs and views with a Job DSL script. The role expects your Job DSL scripts to be stored in files ending with .groovy
in the jobs
directory next to your playbook. If you want to use Ansible variables in your script, you can turn the script file into a Jinja2 template by changing its filename to end with .groovy.j2
.
To change the Job DSL script directory, set the variable solita_jenkins_jobs_dir
.
To limit role application to job and view updates, use the tag solita_jenkins_jobs
.
Examples¶
If you create your script in the default location, no configuration is needed:
// jobs/Main.groovy
job('my-new-job') {
// ...
}
# playbook.yml
---
- hosts: jenkins-server
roles:
- solita.jenkins
If the script’s filename ends in .groovy.j2
, it can contain Ansible variables:
// jobs/Main.groovy.j2
job('{{ job_name | default("foo") }}') {
// ...
}
If you want to place your scripts somewhere else, set the variable solita_jenkins_jobs_dir
:
# playbook.yml
---
- hosts: jenkins-server
vars:
solita_jenkins_jobs_dir: "{{ playbook_dir }}/files/jenkins/jobs"
roles:
- solita.jenkins
Only update jobs and views:
ansible-playbook playbook.yml --tags solita_jenkins_jobs
solita.ansible¶
An Ansible role for installing Ansible.
Example¶
# playbook.yml
---
- hosts: servers
vars:
solita_ansible_version: 2.1.0.0
roles:
- solita.ansible
Installation¶
You can install this role with ansible-galaxy. First add the following lines
to your requirements.yml
:
# requirements.yml
---
- src: https://github.com/solita/ansible-role-solita.ansible.git
version: v1.1.0
name: solita.ansible
Then run ansible-galaxy
to install the role:
ansible-galaxy install -p path/to/your/roles -r requirements.yml
Ansible version¶
By default, the role will install the latest version of Ansible. To install a
specific version, set the variable solita_ansible_version
.
Examples¶
# playbook.yml
---
- hosts: servers
vars:
solita_ansible_version: 2.1.0.0
roles:
- solita.ansible
Roles¶
To install roles, list them in a requirements file called
requirements.yml
next to your playbook. The contents of
/etc/ansible/roles
will be updated to match requirements.yml
.
Note
/etc/ansible/roles
will be removed before installing the new roles, so
if you create requirements.yml
, make sure to list all your roles!
If you don’t have a requirements.yml
, no changes will be made to
/etc/ansible/roles
.
You can change the path to the requirements file by setting the variable
solita_ansible_requirements_file
. Set it to an empty string to disable role
installation.
Examples¶
Change the path to the requirements file:
# playbook.yml
---
- hosts: servers
vars:
solita_ansible_requirements_file: roles.yml
roles:
- solita.ansible
Disable role installation:
# playbook.yml
---
- hosts: servers
vars:
solita_ansible_requirements_file: ""
roles:
- solita.ansible
License¶
The MIT License (MIT)
Copyright (c) 2015 Solita
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.