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

windows master support #668

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
46 changes: 38 additions & 8 deletions .kitchen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,50 @@ provisioner:
name: chef_zero
data_path: test/fixtures/keys
data_bags_path: test/fixtures/data_bags
attributes:
jenkins:
master:
host: localhost
install_method: war
mirror: https://updates.jenkins.io

platforms:
- name: amazonlinux
driver_config:
box: mvbcoding/awslinux
attributes:
jenkins:
master:
install_method: war
- name: centos-6
attributes:
jenkins:
master:
install_method: war
- name: centos-7
attributes:
jenkins:
master:
install_method: war
- name: debian-7
attributes:
jenkins:
master:
install_method: war
- name: debian-8
attributes:
jenkins:
master:
install_method: war
- name: debian-9
attributes:
jenkins:
master:
install_method: war
- name: ubuntu-14.04
attributes:
jenkins:
master:
install_method: war
- name: ubuntu-16.04
attributes:
jenkins:
master:
install_method: war
- name: windows-2012r2
driver:
box: chef/windows-server-2012r2-standard # private box
Expand All @@ -48,8 +74,6 @@ suites:
excludes:
- ubuntu-14.04
- debian-7
- windows-2012r2
- windows-2016

- name: smoke_package_current
run_list: jenkins_server_wrapper::default
Expand All @@ -69,13 +93,19 @@ suites:
master:
install_method: war
source: https://updates.jenkins.io/stable/latest/jenkins.war
excludes:
- windows-2012r2
- windows-2016
- name: smoke_war_latest
run_list: jenkins_server_wrapper::default
attributes:
jenkins:
master:
install_method: war
source: https://updates.jenkins.io/latest/jenkins.war
excludes:
- windows-2012r2
- windows-2016

#
# Authentication suites
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ Installs and configures Jenkins CI master & node slaves. Resource providers to s
- Debian 7+ (Package installs require 9+ due to dependencies)
- Ubuntu 14.04+ (Package installs require 16.04+ due to dependencies)
- RHEL/CentOS/Scientific/Oracle 6+
- Windows 2008R2+

### Chef

- Chef 12.1+

### Cookbooks

- ark
- compat_resource
- runit

Expand All @@ -37,10 +39,11 @@ Documentation and examples are provided inline using YARD. The tests and fixture

### master

The master recipe will create the required directory structure and install jenkins. There are two installation methods, controlled by the `node['jenkins']['master']['install_method']` attribute:
The master recipe will create the required directory structure and install jenkins. There are three installation methods, controlled by the `node['jenkins']['master']['install_method']` attribute:

- `package` - Install Jenkins from the official jenkins-ci.org packages
- `war` - Download the latest version of the WAR file and configure it with Runit
- `msi` - Install Jenkins on Windows from the official jenkins-ci.org packages

## Resource/Provider

Expand Down
5 changes: 4 additions & 1 deletion attributes/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@
elsif ENV['JAVA_HOME']
File.join(ENV['JAVA_HOME'], 'bin', 'java')
else
'java'
case node['os']
when 'windows' then 'C:\Program Files (x86)\Jenkins\jre\bin\java.exe'
else 'java'
end
end
end
88 changes: 66 additions & 22 deletions attributes/master.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,28 @@
# node.normal['jenkins']['master']['install_method'] = 'war'
#
master['install_method'] = case node['platform_family']
when 'debian', 'rhel', 'amazon' then 'package'
when 'debian', 'rhel', 'amazon'
'package'
when 'windows'
'msi'
else 'war'
end

#
# Installation options to pass to MSI installer.
#
# node.normal['jenkins']['master']['msi_install_options'] = "JENKINSDIR=\"#{node['jenkins']['master']['home']}\""
#
master['msi_install_options'] = nil

#
# The version of the Jenkins master to install. This can be a specific
# package version (from the yum or apt repo), or the version of the war
# file to download from the Jenkins mirror.
#
master['version'] = nil
master['version'] = case node['os']
when 'windows' then '2.89.2'
end

#
# The "channel" to use, default is stable
Expand All @@ -64,39 +76,62 @@
master['mirror'] = 'https://updates.jenkins.io'

#
# The full URL to the Jenkins WAR file on the remote mirror. This attribute is
# only used in the "war" installation method. This is a compiled attribute
# from the +mirror+ and +version+ attributes, but you can override this
# attribute and specify the full URL path to a remote file for the Jenkins
# war file. If you choose to override this file manually, it is highly
# recommended that you also set the +checksum+ attribute.
# The full URL to the Jenkins WAR/ZIP file on the remote mirror. This
# attribute is only used in the "war" & "msi" installation methods. This is a
# compiled attribute from the +mirror+ and +version+ attributes, but you can
# override this attribute and specify the full URL path to a remote file for
# the Jenkins war/zip file. If you choose to override this file manually, it
# is highly recommended that you also set the +checksum+ attribute.
#
# node.normal['jenkins']['master']['source'] = 'http://fs01.example.com/jenkins.war'
#
# Warning: Setting this attribute will negate/ignore any values for +mirror+
# and +version+.
#
master['source'] = "#{node['jenkins']['master']['mirror']}/"\
"#{node['jenkins']['master']['version'] || node['jenkins']['master']['channel']}/"\
'latest/jenkins.war'
# and (for the "war" installation method) +version+.
#
master['source'] =
case node['os']
when 'windows'
"http://mirrors.jenkins-ci.org/windows-#{node['jenkins']['master']['channel']}/"\
"jenkins-#{node['jenkins']['master']['version']}.zip"
else
"#{node['jenkins']['master']['mirror']}/"\
"#{node['jenkins']['master']['version'] || node['jenkins']['master']['channel']}/"\
'latest/jenkins.war'
end

#
# The checksum of the war file. This is use to verify that the remote war file
# has not been tampered with (such as a MITM attack). If you leave this #
# The checksum of the war or zip file. This is use to verify that the remote
# file has not been tampered with (such as a MITM attack). If you leave this
# attribute set to +nil+, no validation will be performed. If this attribute
# is set to the wrong SHA-256 checksum, the Chef Client run will fail.
#
# node.normal['jenkins']['master']['checksum'] = 'abcd1234...'
#
master['checksum'] = nil
master['checksum'] = case node['os']
when 'windows' then 'b0c65a14d554d2b5b588c3ee8ab69af68334aea1bcfeebefb40c84fa7b6d5526'
end

#
# The list of options to pass to the Java JVM script when using the package
# installer. For example:
# When installing Jenkins via a msi on Windows, this attribute can be used
# to specify the msi's SHA-256 checksum.
#
# node.normal['jenkins']['master']['msi_checksum'] = 'abcd1234...'
#
master['msi_checksum'] = nil

#
# The list of options to pass to the Java JVM script when using the
# package/msi installer. For example:
#
# node.normal['jenkins']['master']['jvm_options'] = '-Xmx256m'
#
master['jvm_options'] = '-Djenkins.install.runSetupWizard=false'
master['jvm_options'] =
case node['os']
when 'windows'
'-Xrs -Xmx256m -Djenkins.install.runSetupWizard=false -Dhudson.lifecycle=hudson.lifecycle.WindowsServiceLifecycle -jar "%BASE%\jenkins.war" --httpPort=8080 --webroot="%BASE%\war"'
else
'-Djenkins.install.runSetupWizard=false'
end

#
# The list of Jenkins arguments to pass to the initialize script. This varies
Expand Down Expand Up @@ -125,13 +160,19 @@
#
# node.normal['jenkins']['master']['user'] = 'root'
#
master['user'] = 'jenkins'
master['user'] = case node['os']
when 'windows' then 'SYSTEM'
else 'jenkins'
end

#
# The group under which Jenkins is running. Jenkins doesn't actually use or
# honor this attribute - it is used for file permission purposes.
#
master['group'] = 'jenkins'
master['group'] = case node['os']
when 'windows' then 'Administrators'
else 'jenkins'
end

#
# Jenkins user/group should be created as `system` accounts for `war` install.
Expand Down Expand Up @@ -180,7 +221,10 @@
# configuration and build artifacts. You should ensure this directory resides
# on a volume with adequate disk space.
#
master['home'] = '/var/lib/jenkins'
master['home'] = case node['os']
when 'windows' then 'C:\Program Files (x86)\Jenkins'
else '/var/lib/jenkins'
end

#
# The directory where Jenkins should write its logfile(s). **This attribute
Expand Down
7 changes: 6 additions & 1 deletion libraries/_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,12 @@ def convert_blank_values_to_nil(hash)
# the escaped value
#
def escape(value)
Shellwords.escape(value)
case node['os']
when 'windows'
"\"#{value}\""
else
Shellwords.escape(value)
end
end

#
Expand Down
2 changes: 1 addition & 1 deletion libraries/plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ def install_plugin_from_url(source_url, plugin_name, plugin_version = nil, opts
# Jenkins that prevents Jenkins from following 302 redirects, so we
# use Chef to download the plugin and then use Jenkins to install it.
# It's a bit backwards, but so is Jenkins.
executor.execute!('install-plugin', escape('file://' + plugin.path), '-name', escape(plugin_name), opts[:cli_opts])
executor.execute!('install-plugin', escape("#{node['os'] == 'windows' ? '' : 'file://'}#{plugin.path}"), '-name', escape(plugin_name), opts[:cli_opts])
end

#
Expand Down
3 changes: 2 additions & 1 deletion metadata.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@

recipe 'jenkins::master', 'Installs a Jenkins master'

%w(ubuntu debian redhat centos scientific oracle amazon).each do |os|
%w(ubuntu debian redhat centos scientific oracle amazon windows).each do |os|
supports os
end

depends 'ark', '>= 2.2.0'
depends 'runit', '>= 1.7'
depends 'compat_resource', '>= 12.16.3'
depends 'dpkg_autostart'
Expand Down
76 changes: 76 additions & 0 deletions recipes/_master_msi.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#
# Cookbook Name:: jenkins
# Recipe:: _master_msi
#
# Author: Troy Ready <[email protected]>
#
# Copyright:: 2017, Sturdy Networks
# Copyright:: 2014-2017, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

if ::File.extname(node['jenkins']['master']['source']) == '.zip'
include_recipe 'ark::default'

cached_jenkins_msi = ::File.join(Chef::Config[:file_cache_path],
"jenkins-#{node['jenkins']['master']['version']}.msi")
jenkins_msi_source = cached_jenkins_msi

unless ::File.exist? cached_jenkins_msi
ark "jenkins-#{node['jenkins']['master']['version']}" do
url node['jenkins']['master']['source']
checksum node['jenkins']['master']['checksum'] if node['jenkins']['master']['checksum']
creates 'jenkins.msi'
path Chef::Config[:file_cache_path]
action :cherry_pick
end
ruby_block 'rename_generic_jenkins_msi_file' do
block do
require 'fileutils'
::FileUtils.mv(::File.join(Chef::Config[:file_cache_path], 'jenkins.msi'), cached_jenkins_msi)
end
end
end
else
jenkins_msi_source = node['jenkins']['master']['source']
end

windows_package "Jenkins #{node['jenkins']['master']['version']}" do
source jenkins_msi_source
checksum node['jenkins']['master']['msi_checksum'] if node['jenkins']['master']['msi_checksum']
options node['jenkins']['master']['msi_install_options'] if node['jenkins']['master']['msi_install_options']
end

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

jenkins_service_file = ::File.join(node['jenkins']['master']['home'], 'jenkins.xml')
ruby_block 'update_jenkins_jvm_options' do
block do
# This XML update would be nice to do with rexml, but the quotes in the
# options (e.g. -jar "%BASE%\jenkins.war") get escaped (&quot;) in an
# undesirable way
fe = Chef::Util::FileEdit.new(jenkins_service_file)
fe.search_file_replace(%r{^\s\s<arguments>.*</arguments>$},
" <arguments>#{node['jenkins']['master']['jvm_options']}</arguments>")
fe.write_file
end
not_if do
require 'rexml/document'
jenkinsdoc = ::REXML::Document.new ::File.read(jenkins_service_file)
jenkinsdoc.elements['service'].elements['arguments'].text == node['jenkins']['master']['jvm_options']
end
notifies :restart, 'service[jenkins]', :immediately
end
5 changes: 5 additions & 0 deletions recipes/_master_package.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
# limitations under the License.
#

if Chef::Platform.windows?
Chef::Application.fatal! 'Jenkins "package" installation method not '\
'supported on Windows (use "msi" instead)'
end

case node['platform_family']
when 'debian'
package 'apt-transport-https'
Expand Down
Loading