From e5e0df881bc4062af47436bac26cef9af18ba9e8 Mon Sep 17 00:00:00 2001 From: "Scott M. Likens" Date: Thu, 12 Apr 2012 08:42:07 -0700 Subject: [PATCH 1/2] Convert the Jenkins cookbook to use the WAR instead of the Debian package due to UCF reasons Signed-off-by: Scott M. Likens --- README.md | 27 +++-- attributes/default.rb | 6 +- metadata.rb | 10 +- providers/cli.rb | 1 + providers/job.rb | 3 +- recipes/default.rb | 81 +++++-------- recipes/proxy_nginx.rb | 3 + templates/default/jenkins | 243 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 307 insertions(+), 67 deletions(-) create mode 100644 templates/default/jenkins diff --git a/README.md b/README.md index e75eb3b..612f0b5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,14 @@ Description =========== + Installs and configures Jenkins CI server & node slaves. Resource providers to support automation via jenkins-cli, including job create/update. +Changelog +========= + +- 0.7 - Jenkins was binding to the ip address of the primary interface instead of listening to all addresses which caused nginx to be unable to connect over localhost to Jenkins. +- 0.8 - Convert the recipe to use only the WAR file and not the Debian package. + Requirements ============ @@ -40,9 +47,10 @@ Where the jenkins_login recipe is simply: jenkins_cli "login --username #{node[:jenkins][:username]} --password #{node[:jenkins][:password]}" Attributes -========== +---------- -* jenkins[:mirror] - Base URL for downloading Jenkins (server) +* jenkins[:version] - Specify the version of jenkins used. By default it is latest +* jenkins[:mirror_url] - Specify the URL to download the WAR from * jenkins[:java_home] - Java install path, used for for cli commands * jenkins[:server][:home] - JENKINS_HOME directory * jenkins[:server][:user] - User the Jenkins server runs as @@ -69,7 +77,7 @@ Attributes * jenkins[:node][:ssh_private_key] - jenkins master defaults to: `~/.ssh/id_rsa` (created by the default recipe) * jenkins[:node][:jvm_options] - SSH slave JVM options * jenkins[:iptables_allow] - if iptables is enabled, add a rule passing 'jenkins[:server][:port]' -* jenkins[:nginx][:http_proxy][:variant] - use `nginx` or `apache2` to proxy traffic to jenkins backend (`nil` by default) +* jenkins[:http_proxy][:variant] - use `nginx` or `apache2` to proxy traffic to jenkins backend (`nil` by default) * jenkins[:http_proxy][:www_redirect] - add a redirect rule for 'www.*' URL requests ("disable" by default) * jenkins[:http_proxy][:listen_ports] - list of HTTP ports for the HTTP proxy to listen on ([80] by default) * jenkins[:http_proxy][:host_name] - primary vhost name for the HTTP proxy to respond to (`node[:fqdn]` by default) @@ -77,12 +85,12 @@ Attributes * jenkins[:http_proxy][:client_max_body_size] - max client upload size ("1024m" by default, nginx only) Usage -===== +----- 'default' recipe ---------------- -Installs a Jenkins CI server using the http://jenkins-ci.org/redhat RPM. The recipe also generates an ssh private key and stores the ssh public key in the node 'jenkins[:pubkey]' attribute for use by the node recipes. +Installs a Jenkins CI server using the http://jenkins-ci.org/war-stable WAR. The recipe also generates an ssh private key and stores the ssh public key in the node 'jenkins[:pubkey]' attribute for use by the node recipes. 'node_ssh' recipe ----------------- @@ -117,8 +125,8 @@ Uses the nginx::source recipe from the nginx cookbook to install an HTTP fronten Uses the apache2 recipe from the apache2 cookbook to install an HTTP frontend proxy. To automatically activate this recipe set the `node[:jenkins][:http_proxy][:variant]` to `apache2`. -'jenkins_cli' resource provider ------------------------------- +'jenkins_cli' resource provider This resource can be used to execute the Jenkins cli from your recipes. For example, install plugins via update center and restart Jenkins: @@ -175,14 +183,14 @@ The script to generate groovy that manages a node can be used standalone. For e % ruby manage_node.rb name slave-hostname remote_fs /home/jenkins ... | java -jar jenkins-cli.jar -s http://jenkins:8080/ groovy = Issues -====== +------ * CLI authentication - http://issues.jenkins-ci.org/browse/JENKINS-3796 * CLI *-node commands fail with "No argument is allowed: nameofslave" - http://issues.jenkins-ci.org/browse/JENKINS-5973 -License & Author -================ +License & Author(s): +------------------- This is a downstream fork of Doug MacEachern's Hudson cookbook (https://github.com/dougm/site-cookbooks) and therefore deserves all the glory. @@ -192,6 +200,7 @@ Contributor:: AJ Christensen Contributor:: Fletcher Nichol Contributor:: Roman Kamyk Contributor:: Darko Fabijan +Contributor:: Scott Likens Copyright:: 2010, VMware, Inc diff --git a/attributes/default.rb b/attributes/default.rb index 42caf88..9815c2b 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -21,8 +21,8 @@ # limitations under the License. # -default[:jenkins][:mirror] = "http://mirrors.jenkins-ci.org" -default[:jenkins][:package_url] = "http://pkg.jenkins-ci.org" +default[:jenkins][:version]="latest" +default[:jenkins][:mirror_url] = "http://mirrors.jenkins-ci.org/war-stable" default[:jenkins][:java_home] = ENV['JAVA_HOME'] default[:jenkins][:server][:home] = "/var/lib/jenkins" @@ -36,7 +36,7 @@ end default[:jenkins][:server][:port] = 8080 -default[:jenkins][:server][:host] = node[:fqdn] +default[:jenkins][:server][:host] = "0.0.0.0" default[:jenkins][:server][:url] = "http://#{node[:jenkins][:server][:host]}:#{node[:jenkins][:server][:port]}" default[:jenkins][:iptables_allow] = "disable" diff --git a/metadata.rb b/metadata.rb index 5690c14..f94d217 100644 --- a/metadata.rb +++ b/metadata.rb @@ -1,9 +1,9 @@ - maintainer "AJ Christensen" +maintainer "AJ Christensen" maintainer_email "aj@junglist.gen.nz" license "Apache 2.0" description "Installs and configures Jenkins CI server & slaves" -long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) -version "0.6.3" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.8" -%w(runit java).each { |cb| depends cb } -%w(iptables yum apt).each { |cb| recommends cb } +%w(runit java nginx).each { |cb| depends cb } +%w(iptables apt).each { |cb| recommends cb } diff --git a/providers/cli.rb b/providers/cli.rb index ce354c9..04db5f6 100644 --- a/providers/cli.rb +++ b/providers/cli.rb @@ -49,5 +49,6 @@ def action_run jenkins_execute command do cwd home block { |stdout| new_resource.block.call(stdout) } if new_resource.block + only_if new_resource.only_if end end diff --git a/providers/job.rb b/providers/job.rb index 4b61dce..11a87b1 100644 --- a/providers/job.rb +++ b/providers/job.rb @@ -48,9 +48,10 @@ def post_job(url) res.error! unless res.kind_of?(Net::HTTPSuccess) end +#could also use: jenkins_cli "create-job #{@new_resource.job_name} < #{@new_resource.config}" def action_create unless job_exists - jenkins_cli "create-job #{@new_resource.job_name} < #{@new_resource.config}" + post_job(new_job_url) end end diff --git a/recipes/default.rb b/recipes/default.rb index 7c359e2..3be391f 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -3,6 +3,7 @@ # Based on hudson # Recipe:: default # +# Author:: Scott Likens # Author:: AJ Christensen # Author:: Doug MacEachern # Author:: Fletcher Nichol @@ -21,7 +22,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # - +pid_file = "/var/run/jenkins/jenkins.pid" pkey = "#{node[:jenkins][:server][:home]}/.ssh/id_rsa" tmp = "/tmp" @@ -65,43 +66,25 @@ backup false owner node[:jenkins][:server][:user] group node[:jenkins][:server][:group] - action :create_if_missing end end -case node.platform -when "ubuntu", "debian" - include_recipe "apt" - include_recipe "java" - - pid_file = "/var/run/jenkins/jenkins.pid" - install_starts_service = true - - apt_repository "jenkins" do - uri "#{node.jenkins.package_url}/debian" - components %w[binary/] - key "http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key" - action :add - end -when "centos", "redhat" - include_recipe "yum" - - pid_file = "/var/run/jenkins.pid" - install_starts_service = false - - yum_key "jenkins" do - url "#{node.jenkins.package_url}/redhat/jenkins-ci.org.key" - action :add - end +directory "/usr/share/jenkins" do + action :create + owner "nobody" + group "nogroup" + recursive true +end - yum_repository "jenkins" do - description "repository for jenkins" - url "#{node.jenkins.package_url}/redhat/" - key "jenkins" - action :add - end +remote_file "/usr/share/jenkins/jenkins.war" do + source "#{node[:jenkins][:mirror_url]}/#{node[:jenkins][:version]}/jenkins.war" + owner "root" + group "root" + mode 0644 end +package "daemon" +include_recipe "java" #"jenkins stop" may (likely) exit before the process is actually dead #so we sleep until nothing is listening on jenkins.server.port (according to netstat) ruby_block "netstat" do @@ -119,12 +102,6 @@ action :nothing end -service "jenkins" do - supports [ :stop, :start, :restart, :status ] - status_command "test -f #{pid_file} && kill -0 `cat #{pid_file}`" - action :nothing -end - ruby_block "block_until_operational" do block do until IO.popen("netstat -lnt").entries.select { |entry| @@ -145,20 +122,17 @@ action :nothing end -log "jenkins: install and start" do - notifies :install, "package[jenkins]", :immediately - notifies :start, "service[jenkins]", :immediately unless install_starts_service - notifies :create, "ruby_block[block_until_operational]", :immediately - not_if do - File.exists? "/usr/share/jenkins/jenkins.war" - end -end - template "/etc/default/jenkins" -package "jenkins" do +template "/etc/init.d/jenkins" do + source "jenkins" + mode 0755 +end + +service "jenkins" do + supports [ :stop, :start, :restart, :status ] + status_command "test -f #{pid_file} && kill -0 `cat #{pid_file}`" action :nothing - notifies :create, "template[/etc/default/jenkins]", :immediately end # restart if this run only added new plugins @@ -198,3 +172,12 @@ end end end +service "jenkins" do + supports [ :stop, :start, :restart, :status ] + status_command "test -f #{pid_file} && kill -0 `cat #{pid_file}`" + action [:start,:enable] +end +execute "start jenkins" do + command "/etc/init.d/jenkins start" + not_if 'ps auxwww | grep [j]enkins' +end diff --git a/recipes/proxy_nginx.rb b/recipes/proxy_nginx.rb index ee77b23..3573230 100644 --- a/recipes/proxy_nginx.rb +++ b/recipes/proxy_nginx.rb @@ -54,3 +54,6 @@ enable false end end +service "nginx" do + action [:start, :enable] +end diff --git a/templates/default/jenkins b/templates/default/jenkins new file mode 100644 index 0000000..3d57949 --- /dev/null +++ b/templates/default/jenkins @@ -0,0 +1,243 @@ +#!/bin/bash +# /etc/init.d/jenkins +# debian-compatible jenkins startup script. +# Amelia A Lewis +# +### BEGIN INIT INFO +# Provides: jenkins +# Required-Start: $remote_fs $syslog $network +# Required-Stop: $remote_fs $syslog $network +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start jenkins at boot time +# Description: Controls the jenkins continuous integration engine. +### END INIT INFO + +PATH=/bin:/usr/bin:/sbin:/usr/sbin + +DESC="Jenkins Continuous Integration Server" +NAME=jenkins +SCRIPTNAME=/etc/init.d/$NAME + +[ -r /etc/default/$NAME ] && . /etc/default/$NAME + +#DAEMON=$JENKINS_SH +DAEMON=/usr/bin/daemon +DAEMON_ARGS="--name=$NAME --inherit --env=JENKINS_HOME=$JENKINS_HOME --output=$JENKINS_LOG --pidfile=$PIDFILE" + +SU=/bin/su + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Exit if not supposed to run standalone +[ "$RUN_STANDALONE" = "false" ] && exit 0 + +# load environments +if [ -r /etc/default/locale ]; then + . /etc/default/locale + export LANG LANGUAGE +elif [ -r /etc/environment ]; then + . /etc/environment + export LANG LANGUAGE +fi + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +# Make sure we run as root, since setting the max open files through +# ulimit requires root access +if [ `id -u` -ne 0 ]; then + echo "The $NAME init script can only be run as root" + exit 1 +fi + + +check_tcp_port() { + local service=$1 + local assigned=$2 + local default=$3 + + if [ -n "$assigned" ]; then + port=$assigned + else + port=$default + fi + + count=`netstat --listen --numeric-ports | grep \:$port[[:space:]] | grep -c . ` + + if [ $count -ne 0 ]; then + echo "The selected $service port ($port) seems to be in use by another program " + echo "Please select another port to use for $NAME" + return 1 + fi +} + +# +# Function that starts the daemon/service +# +do_start() +{ + # the default location is /var/run/jenkins/jenkins.pid but the parent directory needs to be created + mkdir `dirname $PIDFILE` > /dev/null 2>&1 || true + chown $JENKINS_USER `dirname $PIDFILE` + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + $DAEMON $DAEMON_ARGS --running && return 1 + + # Verify that the jenkins port is not already in use, winstone does not exit + # even for BindException + check_tcp_port "http" "$HTTP_PORT" "8080" || return 1 + + # If the var MAXOPENFILES is enabled in /etc/default/jenkins then set the max open files to the + # proper value + if [ -n "$MAXOPENFILES" ]; then + [ "$VERBOSE" != no ] && echo Setting up max open files limit to $MAXOPENFILES + ulimit -n $MAXOPENFILES + fi + + # --user in daemon doesn't prepare environment variables like HOME, USER, LOGNAME or USERNAME, + # so we let su do so for us now + $SU -l $JENKINS_USER --shell=/bin/bash -c "$DAEMON $DAEMON_ARGS -- $JAVA $JAVA_ARGS -jar $JENKINS_WAR $JENKINS_ARGS" || return 2 +} + + +# +# Verify that all jenkins processes have been shutdown +# and if not, then do killall for them +# +get_running() +{ + return `ps -U $JENKINS_USER --no-headers -f | egrep -e '(java|daemon)' | grep -c . ` +} + +force_stop() +{ + get_running + if [ $? -ne 0 ]; then + killall -u $JENKINS_USER java daemon || return 3 + fi +} + +# Get the status of the daemon process +get_daemon_status() +{ + $DAEMON $DAEMON_ARGS --running || return 1 +} + + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + get_daemon_status + case "$?" in + 0) + $DAEMON $DAEMON_ARGS --stop || return 2 + # wait for the process to really terminate + for n in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do + sleep 1 + $DAEMON $DAEMON_ARGS --running || break + done + if get_daemon_status; then + force_stop || return 3 + fi + ;; + *) + force_stop || return 3 + ;; + esac + + # Many daemons don't delete their pidfiles when they exit. + rm -f $PIDFILE + return 0 +} + +case "$1" in + start) + log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) log_end_msg 0 ;; + 2) log_end_msg 1 ;; + esac + ;; + stop) + log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) log_end_msg 0 ;; + 2) log_end_msg 1 ;; + esac + ;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + status) + get_daemon_status + case "$?" in + 0) + echo "$DESC is running with the pid `cat $PIDFILE`" + rc=0 + ;; + *) + get_running + procs=$? + if [ $procs -eq 0 ]; then + echo -n "$DESC is not running" + if [ -f $PIDFILE ]; then + echo ", but the pidfile ($PIDFILE) still exists" + rc=1 + else + echo + rc=3 + fi + + else + echo "$procs instances of jenkins are running at the moment" + echo "but the pidfile $PIDFILE is missing" + rc=0 + fi + + exit $rc + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +exit 0 From 3492682b3a1413614945d6246ead11ef6fdd06b2 Mon Sep 17 00:00:00 2001 From: "Scott M. Likens" Date: Fri, 13 Apr 2012 10:58:01 -0700 Subject: [PATCH 2/2] this is a markdown file --- metadata.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metadata.rb b/metadata.rb index f94d217..247e4d9 100644 --- a/metadata.rb +++ b/metadata.rb @@ -2,7 +2,7 @@ maintainer_email "aj@junglist.gen.nz" license "Apache 2.0" description "Installs and configures Jenkins CI server & slaves" -long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) version "0.8" %w(runit java nginx).each { |cb| depends cb }