Skip to content

Commit

Permalink
Allow build jobs to be configured and managed by puppet. Includes vox…
Browse files Browse the repository at this point in the history
  • Loading branch information
jchristi authored and jeremy committed Sep 25, 2014
1 parent 60d8f25 commit 58a5992
Show file tree
Hide file tree
Showing 15 changed files with 470 additions and 4 deletions.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,33 @@ puppet module install rtyler/jenkins
```
Then the service should be running at [http://hostname.example.com:8080/](http://hostname.example.com:8080/).

### Managing Jenkins jobs


Build jobs can be managed using the `jenkins::job` define

#### Creating or updating a build job
```puppet
jenkins::job { 'test-build-job':
config => template("${templates}/test-build-job.xml.erb"),
}
```

#### Disabling a build job
```puppet
jenkins::job { 'test-build-job':
enabled => 0,
config => template("${templates}/test-build-job.xml.erb"),
}
```

#### Removing an existing build job
```puppet
jenkins::job { 'test-build-job':
ensure => 'absent',
}
```

### Installing Jenkins plugins


Expand Down
20 changes: 20 additions & 0 deletions contrib/examples/job-configuration/build.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class jenkins::job::build(
$config = undef,
$jobname = $title,
$enabled = 1,
$ensure = 'present',
) {

if $config == undef {
$real_content = template('jenkins/job/build.xml.erb')
} else {
$real_content = $config
}

jenkins::job { 'build':
config => $real_content,
jobname => $jobname,
enabled => $enabled,
ensure => $ensure,
}
}
17 changes: 17 additions & 0 deletions contrib/examples/job-configuration/templates/build.xml.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version='1.0' encoding='UTF-8'?>
<project>
<actions/>
<description></description>
<keepDependencies>false</keepDependencies>
<properties></properties>
<scm class="hudson.scm.NullSCM"/>
<canRoam>true</canRoam>
<disabled>false</disabled>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<triggers/>
<concurrentBuild>false</concurrentBuild>
<builders/>
<publishers/>
<buildWrappers/>
</project>
37 changes: 36 additions & 1 deletion manifests/cli.pp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,41 @@
path => ['/bin', '/usr/bin'],
cwd => '/tmp',
creates => $jar,
require => Package['jenkins'],
require => Service['jenkins'],
}

file { $jar:
ensure => file,
require => Exec['jenkins-cli'],
}

# Get the value of JENKINS_PORT from config_hash or default
$hash = $::jenkins::config_hash
if is_hash($hash) and has_key($hash, 'JENKINS_PORT') and
has_key($hash['JENKINS_PORT'], 'value') {
$port = $hash['JENKINS_PORT']['value']
} else {
$port = '8080'
}

# The jenkins cli command with required parameter(s)
$cmd = "java -jar ${jar} -s http://localhost:${port}"

# Reload all Jenkins config from disk (only when notified)
exec { 'reload-jenkins':
command => "${cmd} reload-configuration",
tries => 10,
try_sleep => 2,
refreshonly => true,
require => File[$jar],
}

# Do a safe restart of Jenkins (only when notified)
exec { 'safe-restart-jenkins':
command => "${cmd} safe-restart && /bin/sleep 10",
tries => 10,
try_sleep => 2,
refreshonly => true,
require => File[$jar],
}
}
13 changes: 12 additions & 1 deletion manifests/init.pp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
$service_ensure = $jenkins::params::service_ensure,
$config_hash = {},
$plugin_hash = {},
$job_hash = {},
$configure_firewall = undef,
$install_java = $jenkins::params::install_java,
$proxy_host = undef,
Expand Down Expand Up @@ -131,17 +132,27 @@
include jenkins::firewall
}
}

if $cli {
include jenkins::cli
}

Anchor['jenkins::begin'] ->
Class['jenkins::package'] ->
Class['jenkins::config'] ->
Class['jenkins::plugins']~>
Class['jenkins::plugins'] ~>
Class['jenkins::service'] ->
Class['jenkins::jobs'] ->
Anchor['jenkins::end']

if $cli {
Anchor['jenkins::begin'] ->
Class['jenkins::service'] ->
Class['jenkins::cli'] ->
Class['jenkins::jobs'] ->
Anchor['jenkins::end']
}

if $install_java {
Anchor['jenkins::begin'] ->
Class['java'] ->
Expand Down
38 changes: 38 additions & 0 deletions manifests/job.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Define: jenkins::job
#
# This class create a new jenkins job given a name and config xml
#
# Parameters:
#
# config
# the content of the jenkins job config file (required)
#
# jobname = $title
# the name of the jenkins job
#
# enabled = true
# whether to enable the job
#
# ensure = 'present'
# choose 'absent' to ensure the job is removed
#
define jenkins::job(
$config,
$jobname = $title,
$enabled = 1,
$ensure = 'present',
){

if ($ensure == 'absent') {
jenkins::job::absent { $title:
jobname => $jobname,
}
} else {
jenkins::job::present { $title:
config => $config,
jobname => $jobname,
enabled => $enabled,
}
}

}
39 changes: 39 additions & 0 deletions manifests/job/absent.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Define: jenkins::job::absent
#
# Removes a jenkins build job
#
# Parameters:
#
# config
# the content of the jenkins job config file (required)
#
# jobname = $title
# the name of the jenkins job
#
define jenkins::job::absent(
$jobname = $title,
){
include jenkins::cli

if $jenkins::service_ensure == 'stopped' or $jenkins::service_ensure == false {
fail('Management of Jenkins jobs requires \$jenkins::service_ensure to be set to \'running\'')
}

$tmp_config_path = "/tmp/${jobname}-config.xml"
$job_dir = "/var/lib/jenkins/jobs/${jobname}"
$config_path = "${job_dir}/config.xml"

# Temp file to use as stdin for Jenkins CLI executable
file { $tmp_config_path:
ensure => absent,
}

# Delete the job
exec { "jenkins delete-job ${jobname}":
command => "${jenkins::cli::cmd} delete-job ${jobname}",
logoutput => false,
onlyif => "test -f ${config_path}",
require => Exec['jenkins-cli'],
}

}
100 changes: 100 additions & 0 deletions manifests/job/present.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Define: jenkins::job::present
#
# Creates or updates a jenkins build job
#
# Parameters:
#
# config
# the content of the jenkins job config file (required)
#
# jobname = $title
# the name of the jenkins job
#
# enabled = 1
# if the job should be enabled
#
define jenkins::job::present(
$config,
$jobname = $title,
$enabled = 1,
){
include jenkins::cli

if $jenkins::service_ensure == 'stopped' or $jenkins::service_ensure == false {
fail('Management of Jenkins jobs requires \$jenkins::service_ensure to be set to \'running\'')
}

$jenkins_cli = $jenkins::cli::cmd
$tmp_config_path = "/tmp/${jobname}-config.xml"
$job_dir = "/var/lib/jenkins/jobs/${jobname}"
$config_path = "${job_dir}/config.xml"

Exec {
logoutput => false,
path => '/bin:/usr/bin:/sbin:/usr/sbin',
tries => 5,
try_sleep => 5,
}

#
# When a Jenkins job is imported via the cli, Jenkins will
# re-format the xml file based on its own internal rules.
# In order to make job management idempotent, we need to
# apply that formatting before the import, so we can do a diff
# on any pre-existing job to determine if an update is needed.
#
# Jenkins likes to change single quotes to double quotes
$a = regsubst($config, 'version=\'1.0\' encoding=\'UTF-8\'',
'version="1.0" encoding="UTF-8"')
# Change empty tags into self-closing tags
$b = regsubst($a, '<([a-z]+)><\/\1>', '<\1/>', 'IG')
# Change &quot; to " since Jenkins is wierd like that
$c = regsubst($b, '&quot;', '"', 'MG')

# Temp file to use as stdin for Jenkins CLI executable
file { $tmp_config_path:
content => $c,
require => Exec['jenkins-cli'],
}

# Use Jenkins CLI to create the job
$cat_config = "cat ${tmp_config_path}"
$create_job = "${jenkins_cli} create-job ${jobname}"
exec { "jenkins create-job ${jobname}":
command => "${cat_config} | ${create_job}",
creates => [$config_path, "${job_dir}/builds"],
require => File[$tmp_config_path],
}

# Use Jenkins CLI to update the job if it already exists
$update_job = "${jenkins_cli} update-job ${jobname}"
exec { "jenkins update-job ${jobname}":
command => "${cat_config} | ${update_job}",
onlyif => "test -e ${config_path}",
unless => "diff -b -q ${config_path} ${tmp_config_path}",
require => File[$tmp_config_path],
notify => Exec['reload-jenkins'],
}

# Enable or disable the job (if necessary)
if ($enabled == 1) {
exec { "jenkins enable-job ${jobname}":
command => "${jenkins_cli} enable-job ${jobname}",
onlyif => "cat ${config_path} | grep '<disabled>true'",
require => [
Exec["jenkins create-job ${jobname}"],
Exec["jenkins update-job ${jobname}"],
],
}
} else {
exec { "jenkins disable-job ${jobname}":
command => "${jenkins_cli} disable-job ${jobname}",
onlyif => "cat ${config_path} | grep '<disabled>false'",
require => [
Exec["jenkins create-job ${jobname}"],
Exec["jenkins update-job ${jobname}"],
],
}
}

}
11 changes: 11 additions & 0 deletions manifests/jobs.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Class: jenkins::jobs
#
class jenkins::jobs {

if $caller_module_name != $module_name {
fail("Use of private class ${name} by ${caller_module_name}")
}

create_resources('jenkins::job',$::jenkins::job_hash)

}
7 changes: 6 additions & 1 deletion spec/classes/jenkins_cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,14 @@
end

context '$cli => true' do
let(:params) { { :cli => true } }
let(:params) {{ :cli => true,
:config_hash => { 'JENKINS_PORT' => { 'value' => '9000' } }
}}
it { should create_class('jenkins::cli') }
it { should contain_exec('jenkins-cli') }
it { should contain_exec('reload-jenkins').with_command(/http:\/\/localhost:9000/) }
it { should contain_exec('safe-restart-jenkins') }
it { should contain_jenkins__sysconfig('JENKINS_PORT').with_value('9000') }
end
end

Expand Down
2 changes: 1 addition & 1 deletion spec/classes/jenkins_config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

context 'create config' do
let(:params) { { :config_hash => { 'AJP_PORT' => { 'value' => '1234' } } }}
it { should contain_jenkins__sysconfig('AJP_PORT') }
it { should contain_jenkins__sysconfig('AJP_PORT').with_value('1234') }
end
end

Expand Down
25 changes: 25 additions & 0 deletions spec/classes/jenkins_jobs_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require 'spec_helper'

describe 'jenkins', :type => :module do
let(:facts) { { :osfamily => 'RedHat', :operatingsystem => 'RedHat' } }

context 'jobs' do
context 'default' do
it { should contain_class('jenkins::jobs') }
end

context 'with one job' do
let(:params) { { :job_hash => { 'build' => { 'config' => '<xml/>' } } } }
it { should contain_jenkins__job('build').with_config('<xml/>') }
end

context 'with cli disabled' do
let(:params) { { :service_ensure => 'stopped',
:cli => false,
:job_hash => { 'build' => { 'config' => '<xml/>' } } } }
it { expect { should compile }.to raise_error }
end

end

end
Loading

0 comments on commit 58a5992

Please sign in to comment.