Skip to content

Commit dac3150

Browse files
committed
windows master support
Signed-off-by: troyready <[email protected]>
1 parent d87e2c4 commit dac3150

File tree

17 files changed

+258
-45
lines changed

17 files changed

+258
-45
lines changed

.kitchen.yml

+38-8
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,50 @@ provisioner:
1414
name: chef_zero
1515
data_path: test/fixtures/keys
1616
data_bags_path: test/fixtures/data_bags
17-
attributes:
18-
jenkins:
19-
master:
20-
host: localhost
21-
install_method: war
22-
mirror: https://updates.jenkins.io
2317

2418
platforms:
2519
- name: amazonlinux
2620
driver_config:
2721
box: mvbcoding/awslinux
22+
attributes:
23+
jenkins:
24+
master:
25+
install_method: war
2826
- name: centos-6
27+
attributes:
28+
jenkins:
29+
master:
30+
install_method: war
2931
- name: centos-7
32+
attributes:
33+
jenkins:
34+
master:
35+
install_method: war
3036
- name: debian-7
37+
attributes:
38+
jenkins:
39+
master:
40+
install_method: war
3141
- name: debian-8
42+
attributes:
43+
jenkins:
44+
master:
45+
install_method: war
3246
- name: debian-9
47+
attributes:
48+
jenkins:
49+
master:
50+
install_method: war
3351
- name: ubuntu-14.04
52+
attributes:
53+
jenkins:
54+
master:
55+
install_method: war
3456
- name: ubuntu-16.04
57+
attributes:
58+
jenkins:
59+
master:
60+
install_method: war
3561
- name: windows-2012r2
3662
driver:
3763
box: chef/windows-server-2012r2-standard # private box
@@ -48,8 +74,6 @@ suites:
4874
excludes:
4975
- ubuntu-14.04
5076
- debian-7
51-
- windows-2012r2
52-
- windows-2016
5377

5478
- name: smoke_package_current
5579
run_list: jenkins_server_wrapper::default
@@ -69,13 +93,19 @@ suites:
6993
master:
7094
install_method: war
7195
source: https://updates.jenkins.io/stable/latest/jenkins.war
96+
excludes:
97+
- windows-2012r2
98+
- windows-2016
7299
- name: smoke_war_latest
73100
run_list: jenkins_server_wrapper::default
74101
attributes:
75102
jenkins:
76103
master:
77104
install_method: war
78105
source: https://updates.jenkins.io/latest/jenkins.war
106+
excludes:
107+
- windows-2012r2
108+
- windows-2016
79109

80110
#
81111
# Authentication suites

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ Installs and configures Jenkins CI master & node slaves. Resource providers to s
1111
- Debian 7+ (Package installs require 9+ due to dependencies)
1212
- Ubuntu 14.04+ (Package installs require 16.04+ due to dependencies)
1313
- RHEL/CentOS/Scientific/Oracle 6+
14+
- Windows 2008R2+
1415

1516
### Chef
1617

1718
- Chef 12.1+
1819

1920
### Cookbooks
2021

22+
- ark
2123
- compat_resource
2224
- runit
2325

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

3840
### master
3941

40-
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:
42+
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:
4143

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

4548
## Resource/Provider
4649

attributes/default.rb

+4-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@
4949
elsif ENV['JAVA_HOME']
5050
File.join(ENV['JAVA_HOME'], 'bin', 'java')
5151
else
52-
'java'
52+
case node['os']
53+
when 'windows' then 'C:\Program Files (x86)\Jenkins\jre\bin\java.exe'
54+
else 'java'
55+
end
5356
end
5457
end

attributes/master.rb

+66-22
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,28 @@
3333
# node.normal['jenkins']['master']['install_method'] = 'war'
3434
#
3535
master['install_method'] = case node['platform_family']
36-
when 'debian', 'rhel', 'amazon' then 'package'
36+
when 'debian', 'rhel', 'amazon'
37+
'package'
38+
when 'windows'
39+
'msi'
3740
else 'war'
3841
end
3942

43+
#
44+
# Installation options to pass to MSI installer.
45+
#
46+
# node.normal['jenkins']['master']['msi_install_options'] = "JENKINSDIR=\"#{node['jenkins']['master']['home']}\""
47+
#
48+
master['msi_install_options'] = nil
49+
4050
#
4151
# The version of the Jenkins master to install. This can be a specific
4252
# package version (from the yum or apt repo), or the version of the war
4353
# file to download from the Jenkins mirror.
4454
#
45-
master['version'] = nil
55+
master['version'] = case node['os']
56+
when 'windows' then '2.89.2'
57+
end
4658

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

6678
#
67-
# The full URL to the Jenkins WAR file on the remote mirror. This attribute is
68-
# only used in the "war" installation method. This is a compiled attribute
69-
# from the +mirror+ and +version+ attributes, but you can override this
70-
# attribute and specify the full URL path to a remote file for the Jenkins
71-
# war file. If you choose to override this file manually, it is highly
72-
# recommended that you also set the +checksum+ attribute.
79+
# The full URL to the Jenkins WAR/ZIP file on the remote mirror. This
80+
# attribute is only used in the "war" & "msi" installation methods. This is a
81+
# compiled attribute from the +mirror+ and +version+ attributes, but you can
82+
# override this attribute and specify the full URL path to a remote file for
83+
# the Jenkins war/zip file. If you choose to override this file manually, it
84+
# is highly recommended that you also set the +checksum+ attribute.
7385
#
7486
# node.normal['jenkins']['master']['source'] = 'http://fs01.example.com/jenkins.war'
7587
#
7688
# Warning: Setting this attribute will negate/ignore any values for +mirror+
77-
# and +version+.
78-
#
79-
master['source'] = "#{node['jenkins']['master']['mirror']}/"\
80-
"#{node['jenkins']['master']['version'] || node['jenkins']['master']['channel']}/"\
81-
'latest/jenkins.war'
89+
# and (for the "war" installation method) +version+.
90+
#
91+
master['source'] =
92+
case node['os']
93+
when 'windows'
94+
"http://mirrors.jenkins-ci.org/windows-#{node['jenkins']['master']['channel']}/"\
95+
"jenkins-#{node['jenkins']['master']['version']}.zip"
96+
else
97+
"#{node['jenkins']['master']['mirror']}/"\
98+
"#{node['jenkins']['master']['version'] || node['jenkins']['master']['channel']}/"\
99+
'latest/jenkins.war'
100+
end
82101

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

93114
#
94-
# The list of options to pass to the Java JVM script when using the package
95-
# installer. For example:
115+
# When installing Jenkins via a msi on Windows, this attribute can be used
116+
# to specify the msi's SHA-256 checksum.
117+
#
118+
# node.normal['jenkins']['master']['msi_checksum'] = 'abcd1234...'
119+
#
120+
master['msi_checksum'] = nil
121+
122+
#
123+
# The list of options to pass to the Java JVM script when using the
124+
# package/msi installer. For example:
96125
#
97126
# node.normal['jenkins']['master']['jvm_options'] = '-Xmx256m'
98127
#
99-
master['jvm_options'] = '-Djenkins.install.runSetupWizard=false'
128+
master['jvm_options'] =
129+
case node['os']
130+
when 'windows'
131+
'-Xrs -Xmx256m -Djenkins.install.runSetupWizard=false -Dhudson.lifecycle=hudson.lifecycle.WindowsServiceLifecycle -jar "%BASE%\jenkins.war" --httpPort=8080 --webroot="%BASE%\war"'
132+
else
133+
'-Djenkins.install.runSetupWizard=false'
134+
end
100135

101136
#
102137
# The list of Jenkins arguments to pass to the initialize script. This varies
@@ -125,13 +160,19 @@
125160
#
126161
# node.normal['jenkins']['master']['user'] = 'root'
127162
#
128-
master['user'] = 'jenkins'
163+
master['user'] = case node['os']
164+
when 'windows' then 'SYSTEM'
165+
else 'jenkins'
166+
end
129167

130168
#
131169
# The group under which Jenkins is running. Jenkins doesn't actually use or
132170
# honor this attribute - it is used for file permission purposes.
133171
#
134-
master['group'] = 'jenkins'
172+
master['group'] = case node['os']
173+
when 'windows' then 'Administrators'
174+
else 'jenkins'
175+
end
135176

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

185229
#
186230
# The directory where Jenkins should write its logfile(s). **This attribute

libraries/_helper.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,12 @@ def convert_blank_values_to_nil(hash)
220220
# the escaped value
221221
#
222222
def escape(value)
223-
Shellwords.escape(value)
223+
case node['os']
224+
when 'windows'
225+
"\"#{value}\""
226+
else
227+
Shellwords.escape(value)
228+
end
224229
end
225230

226231
#

libraries/plugin.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ def install_plugin_from_url(source_url, plugin_name, plugin_version = nil, opts
317317
# Jenkins that prevents Jenkins from following 302 redirects, so we
318318
# use Chef to download the plugin and then use Jenkins to install it.
319319
# It's a bit backwards, but so is Jenkins.
320-
executor.execute!('install-plugin', escape('file://' + plugin.path), '-name', escape(plugin_name), opts[:cli_opts])
320+
executor.execute!('install-plugin', escape("#{node['os'] == 'windows' ? '' : 'file://'}#{plugin.path}"), '-name', escape(plugin_name), opts[:cli_opts])
321321
end
322322

323323
#

metadata.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88

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

11-
%w(ubuntu debian redhat centos scientific oracle amazon).each do |os|
11+
%w(ubuntu debian redhat centos scientific oracle amazon windows).each do |os|
1212
supports os
1313
end
1414

15+
depends 'ark', '>= 2.2.0'
1516
depends 'runit', '>= 1.7'
1617
depends 'compat_resource', '>= 12.16.3'
1718
depends 'dpkg_autostart'

recipes/_master_msi.rb

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#
2+
# Cookbook Name:: jenkins
3+
# Recipe:: _master_msi
4+
#
5+
# Author: Troy Ready <[email protected]>
6+
#
7+
# Copyright:: 2017, Sturdy Networks
8+
# Copyright:: 2014-2017, Chef Software, Inc.
9+
#
10+
# Licensed under the Apache License, Version 2.0 (the "License");
11+
# you may not use this file except in compliance with the License.
12+
# You may obtain a copy of the License at
13+
#
14+
# http://www.apache.org/licenses/LICENSE-2.0
15+
#
16+
# Unless required by applicable law or agreed to in writing, software
17+
# distributed under the License is distributed on an "AS IS" BASIS,
18+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19+
# See the License for the specific language governing permissions and
20+
# limitations under the License.
21+
#
22+
23+
if ::File.extname(node['jenkins']['master']['source']) == '.zip'
24+
include_recipe 'ark::default'
25+
26+
cached_jenkins_msi = ::File.join(Chef::Config[:file_cache_path],
27+
"jenkins-#{node['jenkins']['master']['version']}.msi")
28+
jenkins_msi_source = cached_jenkins_msi
29+
30+
unless ::File.exist? cached_jenkins_msi
31+
ark "jenkins-#{node['jenkins']['master']['version']}" do
32+
url node['jenkins']['master']['source']
33+
checksum node['jenkins']['master']['checksum'] if node['jenkins']['master']['checksum']
34+
creates 'jenkins.msi'
35+
path Chef::Config[:file_cache_path]
36+
action :cherry_pick
37+
end
38+
ruby_block 'rename_generic_jenkins_msi_file' do
39+
block do
40+
require 'fileutils'
41+
::FileUtils.mv(::File.join(Chef::Config[:file_cache_path], 'jenkins.msi'), cached_jenkins_msi)
42+
end
43+
end
44+
end
45+
else
46+
jenkins_msi_source = node['jenkins']['master']['source']
47+
end
48+
49+
windows_package "Jenkins #{node['jenkins']['master']['version']}" do
50+
source jenkins_msi_source
51+
checksum node['jenkins']['master']['msi_checksum'] if node['jenkins']['master']['msi_checksum']
52+
options node['jenkins']['master']['msi_install_options'] if node['jenkins']['master']['msi_install_options']
53+
end
54+
55+
service 'jenkins' do
56+
action [:enable, :start]
57+
end
58+
59+
jenkins_service_file = ::File.join(node['jenkins']['master']['home'], 'jenkins.xml')
60+
ruby_block 'update_jenkins_jvm_options' do
61+
block do
62+
# This XML update would be nice to do with rexml, but the quotes in the
63+
# options (e.g. -jar "%BASE%\jenkins.war") get escaped (&quot;) in a less
64+
# than undesirable way
65+
fe = Chef::Util::FileEdit.new(jenkins_service_file)
66+
fe.search_file_replace(%r{^\s\s<arguments>.*</arguments>$},
67+
" <arguments>#{node['jenkins']['master']['jvm_options']}</arguments>")
68+
fe.write_file
69+
end
70+
not_if do
71+
require 'rexml/document'
72+
jenkinsdoc = ::REXML::Document.new ::File.read(jenkins_service_file)
73+
jenkinsdoc.elements['service'].elements['arguments'].text == node['jenkins']['master']['jvm_options']
74+
end
75+
notifies :restart, 'service[jenkins]', :immediately
76+
end

recipes/_master_package.rb

+5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
# limitations under the License.
2222
#
2323

24+
if Chef::Platform.windows?
25+
Chef::Application.fatal! 'Jenkins "package" installation method not '\
26+
'supported on Windows (use "msi" instead)'
27+
end
28+
2429
case node['platform_family']
2530
when 'debian'
2631
package 'apt-transport-https'

0 commit comments

Comments
 (0)