diff --git a/.github/workflows/criteo-cookbooks-ci.yml b/.github/workflows/criteo-cookbooks-ci.yml new file mode 100644 index 0000000..94f7d1b --- /dev/null +++ b/.github/workflows/criteo-cookbooks-ci.yml @@ -0,0 +1,45 @@ +# This is a basic workflow to help you get started with Actions +name: Criteo Cookbooks CI +on: + # Triggers the workflow on push or pull request events but only for the master branch + push: + branches: [ master ] + tags: [ 'v*' ] + pull_request: + branches: [ master ] + +jobs: + cookstyle: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.1 + bundler-cache: true + - name: Run Cookstyle + run: bundle exec cookstyle --display-cop-names --extra-details + rspec: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.1 + bundler-cache: true + - name: Run RSpec + run: bundle exec rspec + supermarket: + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') + needs: [cookstyle, rspec] + steps: + - uses: actions/checkout@v4 + - name: Publish to supermarket + uses: afaundez/chef-supermarket-action@8cdbe1cccbe1ecd8685b2ea8f48780135bae7cee + with: + user: criteo + cookbook: wsus-server + category: Package Management + env: + SUPERMARKET_API_KEY: ${{ secrets.SUPERMARKET_API_KEY }} diff --git a/.gitignore b/.gitignore index 190eaf8..46c9d6d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,7 @@ pkg/ # Berkshelf .vagrant /cookbooks -Berksfile.lock +Policyfile.lock.json # Bundler Gemfile.lock diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 14e19d3..0000000 --- a/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: ruby -cache: bundler -rvm: -- 2.3.0 -sudo: false -deploy: - edge: - source: criteo-forks/dpl - branch: chef_ruby2 - provider: chef-supermarket - user_id: criteo - cookbook_category: Package Management - client_key: .travis/client.pem - skip_cleanup: true - on: - tags: true -before_deploy: -- openssl aes-256-cbc -K $encrypted_279b18d6fd1c_key -iv $encrypted_279b18d6fd1c_iv - -in .travis/client.pem.enc -out .travis/client.pem -d diff --git a/.travis/client.pem.enc b/.travis/client.pem.enc deleted file mode 100644 index 9316aba..0000000 Binary files a/.travis/client.pem.enc and /dev/null differ diff --git a/Berksfile b/Berksfile deleted file mode 100644 index 34fea21..0000000 --- a/Berksfile +++ /dev/null @@ -1,3 +0,0 @@ -source 'https://supermarket.chef.io' - -metadata diff --git a/Gemfile b/Gemfile index 569bc05..943dc46 100644 --- a/Gemfile +++ b/Gemfile @@ -1,15 +1,10 @@ source 'https://rubygems.org' -gem 'rake' - group :test do - gem 'rspec-mocks' - gem 'chefspec', '>= 4.2' - gem 'fauxhai', '>= 2.2' - gem 'foodcritic', '>= 4.0' - gem 'gherkin', '~> 5.1' - - platforms :mri_19 do - gem 'ohai', '~> 7.4.0' - end + gem 'chef', '= 17.9.46' + gem 'cookstyle', '>= 7.32.8' + gem 'fauxhai-chef', '>= 9.3.16' + # TODO: Unpin chefspec and remove rspec pin once chefspec integrates breaking rspec-expectations change + gem 'chefspec', '= 9.3.6' + gem 'rspec-expectations', '= 3.12.3' end diff --git a/Policyfile.rb b/Policyfile.rb new file mode 100644 index 0000000..3623448 --- /dev/null +++ b/Policyfile.rb @@ -0,0 +1,8 @@ +name 'wsus-server' + +run_list %w(wsus-server) + +default_source :supermarket + +# Current cookbook +cookbook 'wsus-server', path: '.' diff --git a/README.md b/README.md index 1eb2a41..711f1bc 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,6 @@ Requirements This cookbook requires Chef 12.1+. ### Platforms -* Windows Server 2008 (R1, R2) -* Windows Server 2012 (R1, R2) * Windows Server 2016 * Windows Server 2019 @@ -196,28 +194,6 @@ source | Source of the windows package | String | *depen checksum | Checksum of the windows package | String | *depends of the architecture* options | Options to use when installing the windows package | String | `/q` -## wsus-server::report_viewer -Install reporting viewer 2012 to enable wsus reports. - -### Attributes -Attributes to configure Reportviewer prerequisite package are accessible via `node['wsus_server']['report_viewer']['prerequisite']`. - -Attribute | Description | Type | Default -----------|----------------------------------------------------|--------|-------- -name | Name of the windows package | String | `Microsoft System CLR Types for SQL Server 2012 (x64)` -source | Source of the windows package | String | [https://download.microsoft.com/.../SQLSysClrTypes.msi][sql_clr_types] -checksum | Checksum of the windows package | String | `674c396e9c9bf389dd21c...c570fa927b07fa620db7d4537` -options | Options to use when installing the windows package | String | `/q` - -Attributes to configure Reportviewer runtime package are accessible via `node['wsus_server']['report_viewer']['runtime']`. - -Attribute | Description | Type | Default -----------|----------------------------------------------------|--------|-------- -name | Name of the windows package | String | `Microsoft Report Viewer 2012 Runtime` -source | Source of the windows package | String | [https://download.microsoft.com/.../ReportViewer.exe][report_viewer] -checksum | Checksum of the windows package | String | `948f28452abddd90b27dc...d42254c71b5b1e19ac5c6daf` -options | Options to use when installing the windows package | String | `/q` - ## wsus-server::synchronize This recipe performs a synchronous update of the update catalog, according to the configured subscriptions. @@ -269,8 +245,6 @@ limitations under the License. [subscription]: http://msdn.microsoft.com/library/microsoft.updateservices.administration.isubscription [subscription_members]: http://msdn.microsoft.com/library/microsoft.updateservices.administration.isubscription_members [frontend_server]: http://technet.microsoft.com/library/dd939896 -[report_viewer]: https://download.microsoft.com/download/F/B/7/FB728406-A1EE-4AB5-9C56-74EB8BDDF2FF/ReportViewer.msi -[sql_clr_types]: https://download.microsoft.com/download/F/E/D/FEDB200F-DE2A-46D8-B661-D019DFE9D470/ENU/x64/SQLSysClrTypes.msi [build_status]: https://api.travis-ci.org/criteo-cookbooks/wsus-server.svg?branch=master [cookbook_version]: https://img.shields.io/cookbook/v/wsus-server.svg [cookbook]: https://supermarket.chef.io/cookbooks/wsus-server diff --git a/Rakefile b/Rakefile deleted file mode 100644 index 4cf4b7e..0000000 --- a/Rakefile +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env rake - -require 'foodcritic' - -task :default => [:foodcritic] - -FoodCritic::Rake::LintTask.new diff --git a/attributes/configure.rb b/attributes/configure.rb index 661cfcb..46200c3 100644 --- a/attributes/configure.rb +++ b/attributes/configure.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Attribute:: server_configuration # # Copyright:: Copyright (c) 2014 Criteo. diff --git a/attributes/freeze.rb b/attributes/freeze.rb index f6ae5d8..c709df2 100644 --- a/attributes/freeze.rb +++ b/attributes/freeze.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Attribute:: freeze # # Copyright:: Copyright (c) 2014 Criteo. diff --git a/attributes/install.rb b/attributes/install.rb index 1594d4b..34025d5 100644 --- a/attributes/install.rb +++ b/attributes/install.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Attribute:: install # # Copyright:: Copyright (c) 2014 Criteo. @@ -31,29 +31,3 @@ default['wsus_server']['setup']['content_dir'] = nil # Defines the local or remote SQL instance used for WSUS configuration database. default['wsus_server']['setup']['sqlinstance_name'] = nil - -# Following attributes are not required anymore on Windows Server 2012 and later -if node['platform_version'].to_f < 6.2 - # Enables the inventory feature. - default['wsus_server']['setup']['enable_inventory'] = false - # Determines whether WSUS should be setup as an additional frontend server. - # Frontend server shares the configuration of the main server, using the value of above attribute sqlinstance_name. - # see http://technet.microsoft.com/en-us/library/dd939896.aspx - default['wsus_server']['setup']['frontend_setup'] = false - # Joins the Microsoft Update Improvement Program. - default['wsus_server']['setup']['join_improvement_program'] = false - # Determines whether WSUS should be set as default website - port 80 - or not - port 8530. - default['wsus_server']['setup']['use_default_website'] = false - # Defines path to windows internal database data directory. - default['wsus_server']['setup']['wyukon_data_dir'] = nil - - default['wsus_server']['package']['name'] = 'Windows Server Update Services 3.0 SP2' - default['wsus_server']['package']['options'] = '/q' - if node['kernel']['machine'] == 'x86_64' - default['wsus_server']['package']['source'] = 'http://download.microsoft.com/download/B/0/6/B06A69C3-CF97-42CF-86BF-3C59D762E0B2/WSUS30-KB972455-x64.exe' - default['wsus_server']['package']['checksum'] = '50d027431d64c35ad62291825eed35d7ffd3c3ecc96421588465445e195571d0' - else - default['wsus_server']['package']['source'] = 'http://download.microsoft.com/download/B/0/6/B06A69C3-CF97-42CF-86BF-3C59D762E0B2/WSUS30-KB972455-x86.exe' - default['wsus_server']['package']['checksum'] = 'bec8bdd6cdad1edd50cc43e6121b73188b31ba4ad08e55b49f4287923a7f3290' - end -end diff --git a/attributes/report_viewer.rb b/attributes/report_viewer.rb deleted file mode 100644 index 0fc8c31..0000000 --- a/attributes/report_viewer.rb +++ /dev/null @@ -1,31 +0,0 @@ -# -# Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server -# Attribute:: report_viewer -# -# Copyright:: Copyright (c) 2014 Criteo. -# -# 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. -# -# WSUS is a windows only feature -return unless platform?('windows') - -default['wsus_server']['report_viewer']['prerequisite']['name'] = 'Microsoft System CLR Types for SQL Server 2012 (x64)' -default['wsus_server']['report_viewer']['prerequisite']['source'] = 'https://download.microsoft.com/download/F/E/D/FEDB200F-DE2A-46D8-B661-D019DFE9D470/ENU/x64/SQLSysClrTypes.msi' -default['wsus_server']['report_viewer']['prerequisite']['checksum'] = '674c396e9c9bf389dd21cec0780b3b4c808ff50c570fa927b07fa620db7d4537' -default['wsus_server']['report_viewer']['prerequisite']['options'] = '/q' - -default['wsus_server']['report_viewer']['runtime']['name'] = 'Microsoft Report Viewer Runtime 2012' -default['wsus_server']['report_viewer']['runtime']['source'] = 'https://download.microsoft.com/download/F/B/7/FB728406-A1EE-4AB5-9C56-74EB8BDDF2FF/ReportViewer.msi' -default['wsus_server']['report_viewer']['runtime']['checksum'] = '948f28452abddd90b27dc80aba1b48c3faedcf2bd42254c71b5b1e19ac5c6daf' -default['wsus_server']['report_viewer']['runtime']['options'] = '/q' diff --git a/attributes/synchronize.rb b/attributes/synchronize.rb index 109c179..cacee56 100644 --- a/attributes/synchronize.rb +++ b/attributes/synchronize.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Attribute:: synchronize # # Copyright:: Copyright (c) 2014 Criteo. diff --git a/libraries/base_provider.rb b/libraries/base_provider.rb index 2adcff0..0e65ac9 100644 --- a/libraries/base_provider.rb +++ b/libraries/base_provider.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Library:: base_provider # # Copyright:: Copyright (c) 2014 Criteo. @@ -24,11 +24,6 @@ module BaseProvider require 'yaml' require 'base64' include Chef::Mixin::ShellOut - include Windows::Helper - - def whyrun_supported? - true - end def self.uri_to_wsus_endpoint_params(uri) uri = URI uri @@ -50,11 +45,7 @@ def endpoint_params @endpoint ||= @new_resource.endpoint ? WsusServer::BaseProvider.uri_to_wsus_endpoint_params(@new_resource.endpoint) : '' end - def powershell - locate_sysnative_cmd('powershell.exe') - end - - def powershell_out64(cmd, timeout=300) + def powershell_out64(cmd, timeout = 300) flags = [ # Hides the copyright banner at startup. '-NoLogo', @@ -74,9 +65,9 @@ def powershell_out64(cmd, timeout=300) # Use powershell with absolute path to the binary (it's the same path for all versions) # Use the locate_sysnative helper to target the right powershell binary # => https://msdn.microsoft.com/en-us/library/windows/desktop/aa384187.aspx - cmd = shell_out "#{powershell} #{flags.join(' ')} -EncodedCommand #{encoded_command}", timeout: timeout + cmd = shell_out "powershell.exe #{flags.join(' ')} -EncodedCommand #{encoded_command}", timeout: timeout cmd.error! - fail 'Invalid syntax in PowershellScript' if cmd.stderr && cmd.stderr.include?('ParserError') + raise 'Invalid syntax in PowershellScript' if cmd.stderr && cmd.stderr.include?('ParserError') cmd end diff --git a/libraries/base_resource.rb b/libraries/base_resource.rb index 0225d21..6c21685 100644 --- a/libraries/base_resource.rb +++ b/libraries/base_resource.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Library:: base_resource # # Copyright:: Copyright (c) 2014 Criteo. @@ -22,15 +22,6 @@ module WsusServer module BaseResource require 'uri' - def initialize(name, run_context = nil) - super(name, run_context) - - @action = :configure - @allowed_actions.push(:configure) - - @properties = {} - end - def endpoint(uri = nil) @endpoint = validate_http_uri('endpoint', uri) unless uri.nil? @endpoint @@ -43,7 +34,7 @@ def properties(arg = nil) def validate_string(name, value, values) unless values.include? value - fail RangeError, "Invalid value for '#{name}', accepted values are '#{values.join('\', \'')}'" + raise RangeError, "Invalid value for '#{name}', accepted values are '#{values.join('\', \'')}'" end value end @@ -52,21 +43,21 @@ def validate_http_uri(name, value) uri = URI value uri = URI 'http://' + value unless uri.scheme # also validate the emptyness of the host unless %w(http https).include? uri.scheme.to_s.downcase - fail ArgumentError, "Invalid scheme for '#{name}' URI, accepted schemes are 'http' and 'https'" + raise ArgumentError, "Invalid scheme for '#{name}' URI, accepted schemes are 'http' and 'https'" end uri end def validate_boolean(name, value) unless value.is_a?(TrueClass) || value.is_a?(FalseClass) - fail TypeError, "Invalid value for '#{name}' expecting 'True' or 'False'" + raise TypeError, "Invalid value for '#{name}' expecting 'True' or 'False'" end value end def validate_time(name, value) unless value =~ /^([01]?[0-9]|2[0-3])(\:[0-5][0-9]){1,2}$/ - fail ArgumentError, "Invalid value for '#{name}', format is: 'HH:MM:SS'" + raise ArgumentError, "Invalid value for '#{name}', format is: 'HH:MM:SS'" end value end @@ -74,7 +65,7 @@ def validate_time(name, value) def validate_integer(name, value, min, max) i = value.to_i unless i >= min && i <= max && value.to_s =~ /^\d+$/ - fail ArgumentError, "Invalid value for '#{name}', value must be between #{min} and #{max}" + raise ArgumentError, "Invalid value for '#{name}', value must be between #{min} and #{max}" end i end diff --git a/libraries/matchers.rb b/libraries/matchers.rb deleted file mode 100644 index d383995..0000000 --- a/libraries/matchers.rb +++ /dev/null @@ -1,16 +0,0 @@ -if defined?(ChefSpec) - ChefSpec.define_matcher :wsus_server_configuration - def configure_wsus_server_configuration(resource) - ChefSpec::Matchers::ResourceMatcher.new(:wsus_server_configuration, :configure, resource) - end - - ChefSpec.define_matcher :wsus_server_notification - def configure_wsus_server_notification(resource) - ChefSpec::Matchers::ResourceMatcher.new(:wsus_server_notification, :configure, resource) - end - - ChefSpec.define_matcher :wsus_server_subscription - def configure_wsus_server_subscription(resource) - ChefSpec::Matchers::ResourceMatcher.new(:wsus_server_subscription, :configure, resource) - end -end diff --git a/metadata.rb b/metadata.rb index 228bed4..fe1beca 100644 --- a/metadata.rb +++ b/metadata.rb @@ -3,11 +3,9 @@ maintainer_email 'b.courtois@criteo.com' license 'Apache-2.0' description 'Installs wsus server' -long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) version '2.3.2' supports 'windows' -depends 'windows' -chef_version '>= 12.1' if respond_to?(:chef_version) -source_url 'https://github.com/criteo-cookbooks/wsus-server' if respond_to?(:source_url) -issues_url 'https://github.com/criteo-cookbooks/wsus-server/issues' if respond_to?(:issues_url) +chef_version '>= 12.1' +source_url 'https://github.com/criteo-cookbooks/wsus-server' +issues_url 'https://github.com/criteo-cookbooks/wsus-server/issues' diff --git a/providers/configuration.rb b/providers/configuration.rb index e1eb5b7..1d697a7 100644 --- a/providers/configuration.rb +++ b/providers/configuration.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Provider:: configuration # # Copyright:: Copyright (c) 2014 Criteo. @@ -17,7 +17,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -use_inline_resources include WsusServer::BaseProvider diff --git a/providers/notification.rb b/providers/notification.rb index dd0f06c..488f6b4 100644 --- a/providers/notification.rb +++ b/providers/notification.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Provider:: notification # # Copyright:: Copyright (c) 2014 Criteo. @@ -17,7 +17,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -use_inline_resources include WsusServer::BaseProvider diff --git a/providers/subscription.rb b/providers/subscription.rb index 95fe2f3..261abcf 100644 --- a/providers/subscription.rb +++ b/providers/subscription.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Provider:: subscription # # Copyright:: Copyright (c) 2014 Criteo. @@ -17,7 +17,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -use_inline_resources include WsusServer::BaseProvider diff --git a/recipes/configure.rb b/recipes/configure.rb index cb9a81f..1b4ef42 100644 --- a/recipes/configure.rb +++ b/recipes/configure.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Recipe:: configure # # Copyright:: Copyright (c) 2014 Criteo. diff --git a/recipes/default.rb b/recipes/default.rb index f8ad5ab..5baa2f3 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Recipe:: default # # Copyright:: Copyright (c) 2014 Criteo. diff --git a/recipes/freeze.rb b/recipes/freeze.rb index e2d632f..3477cf3 100644 --- a/recipes/freeze.rb +++ b/recipes/freeze.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus +# Cookbook:: wsus # Attribute:: server_freeze # # Copyright:: Copyright (c) 2014 Criteo. @@ -22,10 +22,9 @@ include_recipe 'wsus-server::install' - freeze = node['wsus_server']['freeze']['name'] -powershell_script 'WSUS Update Freeze' do # ~FC009 +powershell_script 'WSUS Update Freeze' do code <<-EOH [Reflection.Assembly]::LoadWithPartialName('Microsoft.UpdateServices.Administration') | Out-Null $wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer() @@ -51,7 +50,6 @@ } } EOH - guard_interpreter :powershell_script only_if <<-EOH [Reflection.Assembly]::LoadWithPartialName('Microsoft.UpdateServices.Administration') | Out-Null $wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer() diff --git a/recipes/install.rb b/recipes/install.rb index 7014558..9dbe8c6 100644 --- a/recipes/install.rb +++ b/recipes/install.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Recipe:: install # # Copyright:: Copyright (c) 2014 Criteo. @@ -23,13 +23,7 @@ setup_conf = node['wsus_server']['setup'] setup_options = '' -if setup_conf['sqlinstance_name'] - if node['platform_version'].to_f >= 6.2 - setup_options << " SQL_INSTANCE_NAME=\"#{setup_conf['sqlinstance_name']}\"" - else - setup_options << " SQLINSTANCE_NAME=\"#{setup_conf['sqlinstance_name']}\"" - end -end +setup_options << " SQL_INSTANCE_NAME=\"#{setup_conf['sqlinstance_name']}\"" if setup_conf['sqlinstance_name'] if setup_conf['content_dir'] setup_options << " CONTENT_LOCAL=1 CONTENT_DIR=\"#{setup_conf['content_dir']}\"" @@ -39,95 +33,43 @@ end end -require 'chef/win32/version' -if node['platform_version'].to_f >= 6.2 - [ - 'NET-WCF-HTTP-Activation45', # This feature is required for KB3159706 - 'UpdateServices', - 'UpdateServices-UI', - ].each do |feature_name| - windows_feature feature_name do - action :install - install_method :windows_feature_powershell if respond_to? :install_method - provider :windows_feature_powershell unless respond_to? :install_method - end - end - - windows_feature 'UpdateServices-WidDB' do - action setup_conf['sqlinstance_name'] ? :remove : :install - all true - install_method :windows_feature_powershell if respond_to? :install_method - provider :windows_feature_powershell unless respond_to? :install_method - end - - windows_feature 'UpdateServices-DB' do - action setup_conf['sqlinstance_name'] ? :install : :remove - all true +[ + 'NET-WCF-HTTP-Activation45', # This feature is required for KB3159706 + 'UpdateServices', + 'UpdateServices-UI', +].each do |feature_name| + windows_feature feature_name do + action :install install_method :windows_feature_powershell if respond_to? :install_method provider :windows_feature_powershell unless respond_to? :install_method end +end - guard_file = ::File.join(Chef::Config['file_cache_path'], 'wsus_postinstall') - execute 'WSUS PostInstall' do - command "WsusUtil.exe PostInstall #{setup_options}" - cwd 'C:\Program Files\Update Services\Tools' - not_if { ::File.exist?(guard_file) && ::File.read(guard_file) == setup_options } - end - - file guard_file do - path guard_file - content setup_options - end -else - setup_options << ' ENABLE_INVENTORY=' + (setup_conf['enable_inventory'] ? '1' : '0') - setup_options << ' MU_ROLLUP=' + (setup_conf['join_improvement_program'] ? '1' : '0') - setup_options << ' DEFAULT_WEBSITE=' + (setup_conf['use_default_website'] ? '1' : '0') - setup_options << ' FRONTEND_SETUP=1 CREATE_DATABASE=0' if setup_conf['frontend_setup'] - - if setup_conf['wyukon_data_dir'] - setup_options << " WYUKON_DATA_DIR=\"#{setup_conf['wyukon_data_dir']}\"" - directory setup_conf['wyukon_data_dir'] { recursive true } - end - - # WSUS 3.0 SP2 requires some IIS features: http://technet.microsoft.com/en-us/library/dd939916.aspx - features = %w( - IIS-WebServerRole - IIS-WebServer - IIS-ApplicationDevelopment - IIS-ISAPIFilter - IIS-ISAPIExtensions - IIS-NetFxExtensibility - IIS-ASPNET - IIS-WindowsAuthentication - IIS-HttpCompressionDynamic - IIS-IIS6ManagementCompatibility - IIS-WMICompatibility - IIS-Metabase - IIS-LegacyScripts - ) - - # IIS 6 SnapIn is not compatible with core version - features << 'IIS-LegacySnapIn' unless Chef::ReservedNames::Win32::Version.new.core? - features.each do |feature_name| - windows_feature feature_name do - action :install - install_method :windows_feature_powershell if respond_to? :install_method - provider :windows_feature_powershell unless respond_to? :install_method - end - end +windows_feature 'UpdateServices-WidDB' do + action setup_conf['sqlinstance_name'] ? :remove : :install + all true + install_method :windows_feature_powershell if respond_to? :install_method + provider :windows_feature_powershell unless respond_to? :install_method +end - include_recipe 'wsus-server::report_viewer' +windows_feature 'UpdateServices-DB' do + action setup_conf['sqlinstance_name'] ? :install : :remove + all true + install_method :windows_feature_powershell if respond_to? :install_method + provider :windows_feature_powershell unless respond_to? :install_method +end - package_info = node['wsus_server']['package'] +guard_file = ::File.join(Chef::Config['file_cache_path'], 'wsus_postinstall') +execute 'WSUS PostInstall' do + command "WsusUtil.exe PostInstall #{setup_options}" + cwd 'C:\Program Files\Update Services\Tools' + not_if { ::File.exist?(guard_file) && ::File.read(guard_file) == setup_options } +end - windows_package package_info['name'] do - action :install - installer_type :custom - options "#{package_info['options']} #{setup_options}" - source package_info['source'] - checksum package_info['checksum'] - end +file guard_file do + path guard_file + content setup_options end # Wsus does not need configuration when setup as frontend server -include_recipe 'wsus-server::configure' unless setup_conf['frontend_setup'] +include_recipe 'wsus-server::configure' unless setup_conf['frontend_setup'] diff --git a/recipes/report_viewer.rb b/recipes/report_viewer.rb deleted file mode 100644 index 8b688c7..0000000 --- a/recipes/report_viewer.rb +++ /dev/null @@ -1,33 +0,0 @@ -# -# Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server -# Recipe:: report_viewer -# -# Copyright:: Copyright (c) 2014 Criteo. -# -# 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. -# -# WSUS is a windows only feature -return unless platform?('windows') - -%w(prerequisite runtime).each do |package| - package_info = node['wsus_server']['report_viewer'][package] - - windows_package package_info['name'] do - action :install - installer_type :custom - source package_info['source'] - checksum package_info['checksum'] - options package_info['options'] - end -end diff --git a/recipes/synchronize.rb b/recipes/synchronize.rb index 7ecd601..54472dd 100644 --- a/recipes/synchronize.rb +++ b/recipes/synchronize.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Attribute:: synchronize # # Copyright:: Copyright (c) 2014 Criteo. diff --git a/resources/configuration.rb b/resources/configuration.rb index 4cff123..6dacadd 100644 --- a/resources/configuration.rb +++ b/resources/configuration.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Resource:: configuration # # Copyright:: Copyright (c) 2014 Criteo. @@ -20,10 +20,15 @@ include WsusServer::BaseResource default_action :configure +unified_mode true + +property :proxy_password, String +property :update_languages, Array def initialize(name, run_context = nil) super(name, run_context) + @properties = {} # Default computed value for master_server is nil @properties['UpstreamWsusServerName'] = nil @properties['SyncFromMicrosoftUpdate'] = true @@ -50,11 +55,3 @@ def master_server(arg = nil) @properties['IsReplicaServer'] = true end end - -def proxy_password(arg = nil) - set_or_return(:proxy_password, arg, kind_of: String) -end - -def update_languages(arg = nil) - set_or_return(:update_languages, arg, kind_of: Array) -end diff --git a/resources/notification.rb b/resources/notification.rb index 0768fa8..4305615 100644 --- a/resources/notification.rb +++ b/resources/notification.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Resource:: notification # # Copyright:: Copyright (c) 2014 Criteo. @@ -20,8 +20,17 @@ include WsusServer::BaseResource default_action :configure +unified_mode true -FREQUENCY_VALUES = %w(Daily Weekly) +FREQUENCY_VALUES = %w(Daily Weekly).freeze + +property :smtp_password, String + +def initialize(name, run_context = nil) + super(name, run_context) + + @properties = {} +end def enable_sync_notification(arg = nil) if arg.nil? @@ -79,10 +88,6 @@ def smtp_host(arg = nil) end end -def smtp_password(arg = nil) - set_or_return(:smtp_password, arg, kind_of: String) -end - def smtp_port(arg = nil) if arg.nil? @properties['SmtpPort'] diff --git a/resources/subscription.rb b/resources/subscription.rb index a2ee277..d4436eb 100644 --- a/resources/subscription.rb +++ b/resources/subscription.rb @@ -1,6 +1,6 @@ # # Author:: Baptiste Courtois () -# Cookbook Name:: wsus-server +# Cookbook:: wsus-server # Resource:: subscription # # Copyright:: Copyright (c) 2014 Criteo. @@ -20,6 +20,18 @@ include WsusServer::BaseResource default_action :configure +unified_mode true + +property :categories, Array +property :classifications, Array +property :synchronize_categories, [true, false] +property :configure_timeout, Integer + +def initialize(name, run_context = nil) + super(name, run_context) + + @properties = {} +end def automatic_synchronization(arg = nil) if arg.nil? @@ -29,14 +41,6 @@ def automatic_synchronization(arg = nil) end end -def categories(arg = nil) - set_or_return(:categories, arg, kind_of: Array) -end - -def classifications(arg = nil) - set_or_return(:classifications, arg, kind_of: Array) -end - def synchronization_per_day(arg = nil) if arg.nil? @properties['NumberOfSynchronizationsPerDay'] @@ -52,11 +56,3 @@ def synchronization_time(arg = nil) @properties['SynchronizeAutomaticallyTimeOfDay'] = validate_time('synchronization_time', arg) end end - -def synchronize_categories(arg = nil) - set_or_return(:synchronize_categories, arg, kind_of: [TrueClass, FalseClass]) -end - -def configure_timeout(arg = nil) - set_or_return(:configure_timeout, arg, kind_of: Fixnum) -end diff --git a/spec/recipes/configure_spec.rb b/spec/recipes/configure_spec.rb index b8f2aca..36240ff 100644 --- a/spec/recipes/configure_spec.rb +++ b/spec/recipes/configure_spec.rb @@ -3,39 +3,39 @@ describe 'wsus-server::configure' do describe 'On windows' do it 'installs wsus server' do - [windows2008_chef_run, windows2008_chef_run].each do |chef_run| + [windows2016_chef_run, windows2016_chef_run].each do |chef_run| expect(chef_run).to include_recipe('wsus-server::install') end end it 'configures wsus server' do - [windows2008_chef_run, windows2008_chef_run].each do |chef_run| + [windows2016_chef_run, windows2016_chef_run].each do |chef_run| expect(chef_run).to configure_wsus_server_configuration('Wsus server configuration') expect(chef_run).to configure_wsus_server_notification('Wsus server notification') end end it 'configures wsus server subscription' do - [windows2008_chef_run, windows2008_chef_run].each do |chef_run| + [windows2016_chef_run, windows2016_chef_run].each do |chef_run| expect(chef_run).to configure_wsus_server_subscription('Wsus server subscription') end end it 'configures wsus server notification' do - [windows2008_chef_run, windows2008_chef_run].each do |chef_run| + [windows2016_chef_run, windows2016_chef_run].each do |chef_run| expect(chef_run).to configure_wsus_server_notification('Wsus server notification') end end let(:wsus_replica_conf) { { wsus_server: { configuration: { IsReplicaServer: true, master_server: 'http://127.0.0.1' } } } } it 'does not configure subscription on replica server' do - [windows2008_chef_run(wsus_replica_conf), windows2012_chef_run(wsus_replica_conf)].each do |chef_run| + [windows2016_chef_run(wsus_replica_conf), windows2019_chef_run(wsus_replica_conf)].each do |chef_run| expect(chef_run).to_not configure_wsus_server_subscription('Wsus server subscription') end end it 'does not configure notification on replica server' do - [windows2008_chef_run(wsus_replica_conf), windows2012_chef_run(wsus_replica_conf)].each do |chef_run| + [windows2016_chef_run(wsus_replica_conf), windows2019_chef_run(wsus_replica_conf)].each do |chef_run| expect(chef_run).to_not configure_wsus_server_notification('Wsus server notification') end end diff --git a/spec/recipes/default_spec.rb b/spec/recipes/default_spec.rb index e6b9782..7006386 100644 --- a/spec/recipes/default_spec.rb +++ b/spec/recipes/default_spec.rb @@ -3,12 +3,12 @@ describe 'wsus-server::default' do describe 'On windows' do it 'installs wsus server' do - [windows2008_chef_run, windows2008_chef_run].each do |chef_run| + [windows2016_chef_run, windows2016_chef_run].each do |chef_run| expect(chef_run).to include_recipe('wsus-server::install') end end it 'synchronizes wsus server' do - [windows2008_chef_run, windows2008_chef_run].each do |chef_run| + [windows2016_chef_run, windows2016_chef_run].each do |chef_run| expect(chef_run).to include_recipe('wsus-server::synchronize') end end diff --git a/spec/recipes/freeze_spec.rb b/spec/recipes/freeze_spec.rb index c78e734..eeee06c 100644 --- a/spec/recipes/freeze_spec.rb +++ b/spec/recipes/freeze_spec.rb @@ -2,27 +2,27 @@ describe 'wsus-server::freeze' do describe 'On windows' do - def stub_powershell_guard(result=true) + def stub_powershell_guard(result = true) stub_command(" [Reflection.Assembly]::LoadWithPartialName('Microsoft.UpdateServices.Administration') | Out-Null\n $wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer()\n ($wsus.GetComputerTargetGroups() | where Name -eq '') -eq $null\n").and_return(result) end it 'installs WSUS server' do stub_powershell_guard - [windows2008_chef_run, windows2008_chef_run].each do |chef_run| + [windows2016_chef_run, windows2016_chef_run].each do |chef_run| expect(chef_run).to include_recipe('wsus-server::install') end end it 'freezes updates when target group does not exist' do stub_powershell_guard(true) - [windows2008_chef_run, windows2008_chef_run].each do |chef_run| + [windows2016_chef_run, windows2016_chef_run].each do |chef_run| expect(chef_run).to run_powershell_script('WSUS Update Freeze') end end it 'does not freeze updates when target group already exist' do stub_powershell_guard(false) - [windows2008_chef_run, windows2008_chef_run].each do |chef_run| + [windows2016_chef_run, windows2016_chef_run].each do |chef_run| expect(chef_run).to_not run_powershell_script('WSUS Update Freeze') end end diff --git a/spec/recipes/install_spec.rb b/spec/recipes/install_spec.rb index 973116a..2eba796 100644 --- a/spec/recipes/install_spec.rb +++ b/spec/recipes/install_spec.rb @@ -1,90 +1,76 @@ require 'spec_helper' describe 'wsus-server::install' do - describe 'On windows' do it 'creates the WSUS content directory when content_dir is provided' do conf = { wsus_server: { setup: { content_dir: 'content_dir' } } } - [windows2008_chef_run(conf), windows2012_chef_run(conf)].each do |chef_run| + [windows2016_chef_run(conf), windows2019_chef_run(conf)].each do |chef_run| expect(chef_run).to create_directory('content_dir').with(recursive: true) end end it 'does not create the WSUS content directory when content_dir is not provided' do conf = { wsus_server: { setup: { content_dir: nil } } } - [windows2008_chef_run(conf), windows2012_chef_run(conf)].each do |chef_run| + [windows2016_chef_run(conf), windows2019_chef_run(conf)].each do |chef_run| expect(chef_run).to_not create_directory('content_dir') end end it 'configures the WSUS server when frontend_setup is false' do conf = { wsus_server: { setup: { frontend_setup: false } } } - [windows2008_chef_run(conf), windows2012_chef_run(conf)].each do |chef_run| + [windows2016_chef_run(conf), windows2019_chef_run(conf)].each do |chef_run| expect(chef_run).to include_recipe('wsus-server::configure') end end it 'does not configure the WSUS server when frontend_setup is true' do conf = { wsus_server: { setup: { frontend_setup: true } } } - [windows2008_chef_run(conf), windows2012_chef_run(conf)].each do |chef_run| + [windows2016_chef_run(conf), windows2019_chef_run(conf)].each do |chef_run| expect(chef_run).to_not include_recipe('wsus-server::configure') end end - end - - describe 'On windows 2012R2' do it 'installs windows feature UpdateServices' do - expect(windows2012_chef_run).to install_windows_feature('UpdateServices').with(all: true) + [windows2016_chef_run, windows2019_chef_run].each do |chef_run| + expect(chef_run).to install_windows_feature('UpdateServices') + end end - it 'installs windows feature UpdateServices-UI' do - expect(windows2012_chef_run).to install_windows_feature('UpdateServices-UI').with(all: true) + [windows2016_chef_run, windows2019_chef_run].each do |chef_run| + expect(chef_run).to install_windows_feature('UpdateServices-UI') + end end - - it 'installs windows feature UpdateServices-WidDatabase when no sql_instance_name is provided' do - chef_run = windows2012_chef_run(wsus_server: { setup: { sqlinstance_name: nil } }) - expect(chef_run).to install_windows_feature('UpdateServices-WidDatabase').with(all: true) - expect(chef_run).to remove_windows_feature('UpdateServices-Database').with(all: true) + it 'installs windows feature UpdateServices-WidDB when no sql_instance_name is provided' do + conf = { wsus_server: { setup: { sqlinstance_name: nil } } } + [windows2016_chef_run(conf), windows2019_chef_run(conf)].each do |chef_run| + expect(chef_run).to install_windows_feature('UpdateServices-WidDB').with(all: true) + expect(chef_run).to remove_windows_feature('UpdateServices-WidDB').with(all: true) + end end - - it 'installs windows feature UpdateServices-Database instead when sql_instance_name is provided' do - chef_run = windows2012_chef_run(wsus_server: { setup: { sqlinstance_name: 'instance' } }) - expect(chef_run).to remove_windows_feature('UpdateServices-WidDatabase').with(all: true) - expect(chef_run).to install_windows_feature('UpdateServices-Database').with(all: true) + it 'installs windows feature UpdateServices-DB instead when sql_instance_name is provided' do + conf = { wsus_server: { setup: { sqlinstance_name: 'instance' } } } + [windows2016_chef_run(conf), windows2019_chef_run(conf)].each do |chef_run| + expect(chef_run).to remove_windows_feature('UpdateServices-DB').with(all: true) + expect(chef_run).to install_windows_feature('UpdateServices-DB').with(all: true) + end end - it 'executes WSUS PostInstall when there is no guard file' do - allow(::File).to receive(:exist?).and_call_original - expect(::File).to receive(:exist?).with('/wsus_postinstall').and_return false - expect(windows2012_chef_run).to run_execute('WSUS PostInstall') + [windows2016_chef_run, windows2019_chef_run].each do |chef_run| + allow(::File).to receive(:exist?).and_call_original + expect(::File).to receive(:exist?).with('/wsus_postinstall').and_return false + expect(chef_run).to run_execute('WSUS PostInstall') + end end - it 'does not execute WSUS PostInstall when there is a guard file' do - allow(::File).to receive(:exist?).and_call_original - expect(::File).to receive(:exist?).with('/wsus_postinstall').and_return true - allow(::File).to receive(:read).and_call_original - expect(::File).to receive(:read).with('/wsus_postinstall').and_return '' - expect(windows2012_chef_run).to_not run_execute('WSUS PostInstall') + [windows2016_chef_run, windows2019_chef_run].each do |chef_run| + allow(::File).to receive(:exist?).and_call_original + expect(::File).to receive(:exist?).with('/wsus_postinstall').and_return true + allow(::File).to receive(:read).and_call_original + expect(::File).to receive(:read).with('/wsus_postinstall').and_return '' + expect(chef_run).to_not run_execute('WSUS PostInstall') + end end - it 'creates WSUS PostInstall guard file' do - expect(windows2012_chef_run).to create_file('/wsus_postinstall') - end - end - - describe 'On windows 2008R2' do - it 'enables IIS features' do - chef_run = windows2008_chef_run - features = %w( - IIS-WebServerRole IIS-WebServer IIS-ApplicationDevelopment IIS-ISAPIFilter - IIS-ISAPIExtensions IIS-NetFxExtensibility IIS-ASPNET IIS-WindowsAuthentication - IIS-HttpCompressionDynamic IIS-IIS6ManagementCompatibility IIS-WMICompatibility - IIS-Metabase IIS-LegacyScripts IIS-LegacySnapIn - ).each do |feature| - expect(chef_run).to install_windows_feature(feature) + [windows2016_chef_run, windows2019_chef_run].each do |chef_run| + expect(chef_run).to create_file('/wsus_postinstall') end end - - it 'installs wsus package' do - expect(windows2008_chef_run).to install_windows_package('Windows Server Update Services 3.0 SP2').with(installer_type: :custom) - end end describe 'On linux' do diff --git a/spec/recipes/report_viewer_spec.rb b/spec/recipes/report_viewer_spec.rb deleted file mode 100644 index d1a7871..0000000 --- a/spec/recipes/report_viewer_spec.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'spec_helper' - -describe 'wsus-server::report_viewer' do - describe 'On windows' do - it 'installs the report viewer' do - [windows2008_chef_run, windows2008_chef_run].each do |chef_run| - expect(chef_run).to install_windows_package('Microsoft Report Viewer Redistributable 2008 SP1') - end - end - end - - describe 'On linux' do - it 'does nothing' do - expect(linux_chef_run.resource_collection).to be_empty - end - end -end diff --git a/spec/recipes/synchronize_spec.rb b/spec/recipes/synchronize_spec.rb index c092299..9331fdd 100644 --- a/spec/recipes/synchronize_spec.rb +++ b/spec/recipes/synchronize_spec.rb @@ -3,13 +3,13 @@ describe 'wsus-server::synchronize' do describe 'On windows' do it 'installs WSUS server' do - [windows2008_chef_run, windows2008_chef_run].each do |chef_run| + [windows2016_chef_run, windows2016_chef_run].each do |chef_run| expect(chef_run).to include_recipe('wsus-server::install') end end it 'synchronizes updates' do - [windows2008_chef_run, windows2008_chef_run].each do |chef_run| + [windows2016_chef_run, windows2016_chef_run].each do |chef_run| expect(chef_run).to run_powershell_script('WSUS Update Synchronization') end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8532258..672f780 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,28 +4,31 @@ # loaded once. # require 'chefspec' -require 'chefspec/berkshelf' +require 'chefspec/policyfile' -WINDOWS_2008_OHAI = { platform: 'windows', version: '2008R2' } -WINDOWS_2012_OHAI = { platform: 'windows', version: '2012R2' } -LINUX_OHAI = { platform: 'centos', version: '6.5' } +WINDOWS_2016_OHAI = { platform: 'windows', version: '2016' }.freeze +WINDOWS_2019_OHAI = { platform: 'windows', version: '2019' }.freeze +LINUX_OHAI = { platform: 'centos', version: '8' }.freeze -def chef_run(ohais = {}, attributes = {}) +def custom_chef_run(ohais = {}, attributes = {}) # Mock file_cache_path allow(Chef::Config).to receive(:[]).and_call_original allow(Chef::Config).to receive(:[]).with('file_cache_path').and_return('') ChefSpec::SoloRunner.new(ohais) do |node| - node.set.merge!(attributes) + node.override.merge!(attributes) end.converge(described_recipe) end -def windows2008_chef_run(attributes= {}) - chef_run(WINDOWS_2008_OHAI, attributes) + +def windows2016_chef_run(attributes = {}) + custom_chef_run(WINDOWS_2016_OHAI, attributes) end -def windows2012_chef_run(attributes = {}) - chef_run(WINDOWS_2012_OHAI, attributes) + +def windows2019_chef_run(attributes = {}) + custom_chef_run(WINDOWS_2019_OHAI, attributes) end + def linux_chef_run(attributes = {}) - chef_run(LINUX_OHAI, attributes) + custom_chef_run(LINUX_OHAI, attributes) end # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration