Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow build jobs to be configured and managed by puppet. Includes #163 a... #169

Merged
merged 1 commit into from
Oct 3, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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