How to install and configure Jenkins using Chef Custom Resource

How to install and configure Jenkins using Chef Custom Resource

chef_install_jenkins

Here in this article we will try to install and configure a basic Jenkins server using Chef Custom resource.

Test Environment

CentOS 7 with ChefDK installed

Before going into the concept of creating a custom resource let’s see what are the default repository listing for my centos machine and try creating a cookbook with a default recipe to install jenkins and see what happens.

Below is the list of repositories that are currently configured on my default CentOS 7 machine.

sudo yum repolist

Output:

Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
 * base: mirror.math.princeton.edu
 * extras: mirrors.mit.edu
 * rpmforge: repoforge.spinellicreations.com
 * updates: www.gtlib.gatech.edu
repo id                                                      repo name                                                                status
base/7/x86_64                                                CentOS-7 - Base                                                          9,363
extras/7/x86_64                                              CentOS-7 - Extras                                                          451
rpmforge                                                     RHEL 7 - RPMforge.net - dag                                              4,718
updates/7/x86_64                                             CentOS-7 - Updates                                                       2,146
repolist: 16,678

Let me generate a cookbook named ‘jenkins’ and update the default recipe in it to install package named jenkins.

chef generate cookbook jenkins

File: default.rb

#
# Cookbook Name:: jenkins
# Recipe:: default
#
# Copyright (c) 2017 The Authors, All Rights Reserved.


package 'jenkins' do
                action :install
end

Now, lets try to run the default recipe inside the cookbook ‘jenkins’ to install jenkins locally on the CentOS 7 machine.

sudo chef-client --local-mode --runlist 'recipe[jenkins::default]'

Output:

[2017-09-11T11:21:46-07:00] WARN: No config file found or specified on command line, using command line options.
Starting Chef Client, version 12.12.15
resolving cookbooks for run list: ["jenkins::default"]
Synchronizing Cookbooks:
  - jenkins (0.1.0)
Installing Cookbook Gems:
Compiling Cookbooks...
Converging 1 resources
Recipe: jenkins::default
  * yum_package[jenkins] action install
    * No candidate version available for jenkins
    ================================================================================
    Error executing action `install` on resource 'yum_package[jenkins]'
    ================================================================================


    Chef::Exceptions::Package
...
...


Running handlers:
[2017-09-11T11:23:24-07:00] ERROR: Running exception handlers
Running handlers complete
[2017-09-11T11:23:24-07:00] ERROR: Exception handlers complete
Chef Client failed. 0 resources updated in 01 minutes 36 seconds
[2017-09-11T11:23:24-07:00] FATAL: Stacktrace dumped to /root/.chef/local-mode-cache/cache/chef-stacktrace.out
[2017-09-11T11:23:24-07:00] FATAL: Please provide the contents of the stacktrace.out file if you file a bug report
[2017-09-11T11:23:24-07:00] ERROR: yum_package[jenkins] (jenkins::default line 7) had an error: Chef::Exceptions::Package: No candidate version available for jenkins
[2017-09-11T11:23:25-07:00] FATAL: Chef::Exceptions::ChildConvergeError: Chef run process exited unsuccessfully (exit code 1)

As you can see from the highlighted lines in RED, Chef client failed to run the default recipe because it is unable to find any package named jenkins to install from the default repositories that are pre-configured in the machine.

To resolve these errors, we are going first create a repo file with the repository url for jenkins package using template resource, then we are going to create a custom resource named manageJenkins which we can use similar to resources like file, package, service and call the custom resource from the default cookbook recipe to install the Jenkins package from the repository that was configure in the first step.

Lets start with the step by step procedure as outlined below to achieve our goal or purpose.

Procedure

Step1: Setup the Jenkins repository

First, we need to generate a template file for jenkins repoistory content.

sudo chef generate template jenkins.repository

Update the default jenkins.repository.erb file with the repo content pointing to jenkins repository as show below.

File: jenkins.repository.erb

[jenkins]
name=Jenkins
baseurl=http://pkg.jenkins.io/redhat
gpgcheck=1

Now, lets configure the jenkins repository locally by using template resource in the default cookbook recipe as show below.

File: default.rb

#
# Cookbook Name:: jenkins
# Recipe:: default
#
# Copyright (c) 2017 The Authors, All Rights Reserved.


template '/etc/yum.repos.d/jenkins.repo' do
                source 'jenkins.repository.erb'
                owner 'root'
                group 'root'
                mode '0755'
end

As you can see we have deleted the old content from the recipe wherein we were trying to install jenkins package using package resource. The file is now updated with the template resource to configure the jenkins repository.

Now, lets run the recipe and see what happens.

Before default recipe execution

sudo ls -ltr /etc/yum.repos.d/

Output:

total 44
-rw-r--r--. 1 root root 1128 Mar 20  2013 rpmforge.repo
-rw-r--r--. 1 root root  728 Mar 20  2013 mirrors-rpmforge-testing
-rw-r--r--. 1 root root  717 Mar 20  2013 mirrors-rpmforge-extras
-rw-r--r--. 1 root root  739 Mar 20  2013 mirrors-rpmforge
-rw-r--r--. 1 root root 1952 Dec  9  2015 CentOS-Vault.repo
-rw-r--r--. 1 root root 1331 Dec  9  2015 CentOS-Sources.repo
-rw-r--r--. 1 root root  630 Dec  9  2015 CentOS-Media.repo
-rw-r--r--. 1 root root  290 Dec  9  2015 CentOS-fasttrack.repo
-rw-r--r--. 1 root root  649 Dec  9  2015 CentOS-Debuginfo.repo
-rw-r--r--. 1 root root 1309 Dec  9  2015 CentOS-CR.repo
-rw-r--r--. 1 root root 1664 Dec  9  2015 CentOS-Base.repo

Executing the recipe now as shown below.

sudo chef-client --local-mode --runlist 'recipe[jenkins::default]'

Output:

[2017-09-11T11:45:48-07:00] WARN: No config file found or specified on command line, using command line options.
Starting Chef Client, version 12.12.15
resolving cookbooks for run list: ["jenkins::default"]
Synchronizing Cookbooks:
  - jenkins (0.1.0)
Installing Cookbook Gems:
Compiling Cookbooks...
Converging 1 resources
Recipe: jenkins::default
  * template[/etc/yum.repos.d/jenkins.repo] action create
    - create new file /etc/yum.repos.d/jenkins.repo
    - update content in file /etc/yum.repos.d/jenkins.repo from none to 201d31
    --- /etc/yum.repos.d/jenkins.repo      2017-09-11 11:45:51.833807412 -0700
    +++ /etc/yum.repos.d/.chef-jenkins.repo20170911-7866-8n2km5        2017-09-11 11:45:51.750805465 -0700
    @@ -1 +1,5 @@
    +[jenkins]
    +name=Jenkins
    +baseurl=http://pkg.jenkins.io/redhat
    +gpgcheck=1
    - change mode from '' to '0755'
    - change owner from '' to 'root'
    - change group from '' to 'root'
    - restore selinux security context


Running handlers:
Running handlers complete
Chef Client finished, 1/1 resources updated in 03 seconds

After default recipe execution

Output:

total 48
-rw-r--r--. 1 root root 1128 Mar 20  2013 rpmforge.repo
-rw-r--r--. 1 root root  728 Mar 20  2013 mirrors-rpmforge-testing
-rw-r--r--. 1 root root  717 Mar 20  2013 mirrors-rpmforge-extras
-rw-r--r--. 1 root root  739 Mar 20  2013 mirrors-rpmforge
-rw-r--r--. 1 root root 1952 Dec  9  2015 CentOS-Vault.repo
-rw-r--r--. 1 root root 1331 Dec  9  2015 CentOS-Sources.repo
-rw-r--r--. 1 root root  630 Dec  9  2015 CentOS-Media.repo
-rw-r--r--. 1 root root  290 Dec  9  2015 CentOS-fasttrack.repo
-rw-r--r--. 1 root root  649 Dec  9  2015 CentOS-Debuginfo.repo
-rw-r--r--. 1 root root 1309 Dec  9  2015 CentOS-CR.repo
-rw-r--r--. 1 root root 1664 Dec  9  2015 CentOS-Base.repo
-rwxr-xr-x. 1 root root   71 Sep 11 11:45 jenkins.repo

Our repository is now configure with the help of template resource. Let get onto our next chef creating custom resource.

Step2: Create a custom resource

As a first i am create a lightweight resource provider named ‘manageJenkins’ using the below command.

sudo chef generate lwrp manageJenkins

Output:

Recipe: code_generator::lwrp
  * directory[/home/skytap/chefspace/cookbooks/jenkins/resources] action create
    - create new directory /home/skytap/chefspace/cookbooks/jenkins/resources
    - restore selinux security context
  * template[/home/skytap/chefspace/cookbooks/jenkins/resources/manageJenkins.rb] action create
    - create new file /home/skytap/chefspace/cookbooks/jenkins/resources/manageJenkins.rb
    - update content in file /home/skytap/chefspace/cookbooks/jenkins/resources/manageJenkins.rb from none to e3b0c4
    (diff output suppressed by config)
    - restore selinux security context
  * directory[/home/skytap/chefspace/cookbooks/jenkins/providers] action create
    - create new directory /home/skytap/chefspace/cookbooks/jenkins/providers
    - restore selinux security context
  * template[/home/skytap/chefspace/cookbooks/jenkins/providers/manageJenkins.rb] action create
    - create new file /home/skytap/chefspace/cookbooks/jenkins/providers/manageJenkins.rb
    - update content in file /home/skytap/chefspace/cookbooks/jenkins/providers/manageJenkins.rb from none to e3b0c4
    (diff output suppressed by config)
    - restore selinux security context

Once our custom resource files are create, lets update the custom resource with below content. Here i am giving my custom resource a name called ‘manageJenkins’ and updating it with two action items that are install and uninstall.

In ‘install’ action we are going to install jenkins using the package resource and then enable and start up the jenkins service.

In ‘uninstall’ action we are going to remove the jenkins package from the machine.

File: manageJenkins.rb

Output:

resource_name : manageJenkins


action :install do
                package 'jenkins'

                service 'jenkins' do
                                action [:enable, :start]
                end
end

action :uninstall do
                package 'jenkins' do
                                action :remove
                end
end

The next step is to call the custom resource from our cookbooks default recipe.

Step3: Use the Custom resource in the default recipe

Here is our updated default.rb file with custom resource reference.

File: default.rb

#
# Cookbook Name:: jenkins
# Recipe:: default
#
# Copyright (c) 2017 The Authors, All Rights Reserved.


template '/etc/yum.repos.d/jenkins.repo' do
                source 'jenkins.repository.erb'
                owner 'root'
                group 'root'
                mode '0755'
end


manageJenkins 'install' do
                action    :install
end

After updating the default recipe as above, we can tried to run the recipe with the command in Step4 but it failed with below error.

Error:

      ================================================================================
      Error executing action `install` on resource 'yum_package[jenkins]'
      ================================================================================


      Chef::Exceptions::Exec
      ----------------------
      yum -d0 -e0 -y install jenkins-2.78-1.1 returned 1:
      STDOUT: Public key for jenkins-2.78-1.1.noarch.rpm is not installed


      STDERR: warning: /var/cache/yum/x86_64/7/jenkins/packages/jenkins-2.78-1.1.noarch.rpm: Header V4 DSA/SHA1 Signature, key ID d50582e6: NOKEY




      Public key for jenkins-2.78-1.1.noarch.rpm is not installed

To recover from the above error, we have to update the template file with gpgkey as below.

Here is the updated custom resource file.

File: jenkins.repository.erb

Output:

[jenkins]
name=Jenkins
baseurl=http://pkg.jenkins.io/redhat
gpgkey=https://pkg.jenkins.io/redhat/jenkins.io.key
gpgcheck=1

Yes, with the above change you should be able to successfully install jenkins and startup the service. Sample output is show in below.

Step4: Run the Cookbook in local mode

Let’s now run our cookbook with the recipe “jenkins” in local mode as shown below.

sudo chef-client --local-mode --runlist 'recipe[jenkins]'

Output:

[2017-09-09T04:15:20-07:00] WARN: No config file found or specified on command line, using command line options.
Starting Chef Client, version 12.12.15


resolving cookbooks for run list: ["jenkins"]
Synchronizing Cookbooks:
  - jenkins (0.1.0)
Installing Cookbook Gems:
Compiling Cookbooks...
Converging 1 resources
Recipe: jenkins::default
  * manageJenkins[install] action install
    * yum_package[jenkins] action install
      - install version 2.77-1.1 of package jenkins
    * service[jenkins] action enable (up to date)
    * service[jenkins] action start
      - start service service[jenkins]

As a last step, we need to validate if jenkins is actually installed or not.

Step5: Validate the Jenkins installation

Now let’s check the status of jenkins service.

sudo systemctl status jenkins

Output:

● jenkins.service - LSB: Jenkins Automation Server
   Loaded: loaded (/etc/rc.d/init.d/jenkins)
   Active: active (running) since Sat 2017-09-09 04:20:40 PDT; 3min 34s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 9410 ExecStart=/etc/rc.d/init.d/jenkins start (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/jenkins.service
           └─9425 /etc/alternatives/java -Dcom.sun.akuma.Daemon=daemonized -Djava.awt.headless=true -DJENKINS_HOME=/var/lib/jenkins -jar ...


Sep 09 04:20:35 host-1 systemd[1]: Starting LSB: Jenkins Automation Server...
Sep 09 04:20:36 host-1 runuser[9411]: pam_unix(runuser:session): session opened for user jenkins by (uid=0)
Sep 09 04:20:39 host-1 runuser[9411]: pam_unix(runuser:session): session closed for user jenkins
Sep 09 04:20:40 host-1 jenkins[9410]: Starting Jenkins [  OK  ]
Sep 09 04:20:40 host-1 systemd[1]: Started LSB: Jenkins Automation Server.

Access Jenkins using below url.

URL - http://localhost:8080/

In this article we haven’t touched on securing the jenkins instance, but when you access the above URL, it show as message stating that your jenkins instances configured with administrator password by default for security reasons, so you can login with the default password shown on the page which is also logged in the log file mentioned in the message.

Hope you enjoyed reading this article. Thank you..