From 54b5184cdbaedf67ef914dc6495d40a0713ea9cb Mon Sep 17 00:00:00 2001 From: Suyash Mohan Date: Tue, 31 Mar 2020 17:39:34 +0800 Subject: [PATCH 1/5] update windows and add iis cookbook --- cookbooks/iis | 1 + .../windows/.github/workflows/delivery.yml | 16 ++++++++ cookbooks/windows/CHANGELOG.md | 9 +++++ cookbooks/windows/Gemfile | 2 +- cookbooks/windows/README.md | 20 +++++++++- cookbooks/windows/appveyor.yml | 1 + cookbooks/windows/kitchen.appveyor.yml | 5 ++- cookbooks/windows/kitchen.yml | 5 ++- cookbooks/windows/metadata.rb | 3 +- cookbooks/windows/providers/dns.rb | 5 --- cookbooks/windows/resources/certificate.rb | 5 +-- .../windows/resources/certificate_binding.rb | 3 +- cookbooks/windows/resources/dns.rb | 5 +-- cookbooks/windows/resources/http_acl.rb | 2 +- cookbooks/windows/resources/schannel.rb | 39 +++++++++++++++++++ cookbooks/windows/resources/share.rb | 2 - cookbooks/windows/resources/zipfile.rb | 1 + .../cookbooks/test/recipes/certificate.rb | 2 +- .../test/cookbooks/test/recipes/schannel.rb | 2 + .../integration/schannel/schannel_spec.rb | 3 ++ 20 files changed, 108 insertions(+), 23 deletions(-) create mode 160000 cookbooks/iis create mode 100644 cookbooks/windows/.github/workflows/delivery.yml create mode 100644 cookbooks/windows/resources/schannel.rb create mode 100644 cookbooks/windows/test/cookbooks/test/recipes/schannel.rb create mode 100644 cookbooks/windows/test/integration/schannel/schannel_spec.rb diff --git a/cookbooks/iis b/cookbooks/iis new file mode 160000 index 00000000..e19362a1 --- /dev/null +++ b/cookbooks/iis @@ -0,0 +1 @@ +Subproject commit e19362a1ae9bfe9748ebcfde2f21951f1fd19b1b diff --git a/cookbooks/windows/.github/workflows/delivery.yml b/cookbooks/windows/.github/workflows/delivery.yml new file mode 100644 index 00000000..4b5c4676 --- /dev/null +++ b/cookbooks/windows/.github/workflows/delivery.yml @@ -0,0 +1,16 @@ +name: delivery + +on: [push, pull_request] + +jobs: + delivery: + + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@master + - name: Run Chef Delivery + uses: actionshub/chef-delivery@master + env: + CHEF_LICENSE: accept-no-persist \ No newline at end of file diff --git a/cookbooks/windows/CHANGELOG.md b/cookbooks/windows/CHANGELOG.md index d88694ce..fa1bd5f3 100644 --- a/cookbooks/windows/CHANGELOG.md +++ b/cookbooks/windows/CHANGELOG.md @@ -2,6 +2,15 @@ This file is used to list changes made in each version of the windows cookbook. +## Unreleased + +- Added windows_schannel to configure schannel (tls settings for dotnet apps and powershell) + +## 6.0.1 (2019-10-01) + +- Update README.md for Windows cookbook suggesting core dns resources (#616) - [@NAshwini](https://github.com/NAshwini) +- Add a warning when using windows_zipfile resource as users should migrate to archive_file (#617) - [@NAshwini](https://github.com/NAshwini) + ## 6.0.0 (2019-04-25) ### Breaking Changes diff --git a/cookbooks/windows/Gemfile b/cookbooks/windows/Gemfile index d763411a..8312beeb 100644 --- a/cookbooks/windows/Gemfile +++ b/cookbooks/windows/Gemfile @@ -1,5 +1,5 @@ # This gemfile provides additional gems for testing and releasing this cookbook -# It is meant to be installed on top of ChefDK which provides the majority +# It is meant to be installed on top of ChefDK / Chef Workstation which provide the majority # of the necessary gems for testing this cookbook # # Run 'chef exec bundle install' to install these dependencies diff --git a/cookbooks/windows/README.md b/cookbooks/windows/README.md index b849fbf3..b7e4bafc 100644 --- a/cookbooks/windows/README.md +++ b/cookbooks/windows/README.md @@ -22,7 +22,7 @@ Provides a set of Windows-specific resources to aid in the creation of cookbooks ### Deprecated Resources Note -As of Chef 14.7+ the windows_share and windows_certificate resources are now included in the Chef Client. If you are running Chef 14.7+ the resources in Chef client will take precedence over the resources in this cookbook. In November 2019 we will release a new major version of this cookbook that removes these resources. +As of Chef 14.7+ the windows_share and windows_certificate resources are now included in the Chef Client. Also the windows_zipfile resource is replaced by the new archive_file resource in Chef 15.0.293+. If you are running Chef 14.7+ the resources in Chef client will take precedence over the resources in this cookbook. In November 2019 we will release a new major version of this cookbook that removes these resources. ### windows_certificate @@ -135,6 +135,8 @@ end ### windows_dns +`Note`: This resource is now included in Chef 15 and later. If you are using newer versions of [windows](https://devblogs.microsoft.com/powershell/configuration-in-a-devops-world-windows-powershell-desired-state-configuration/) then should use the core [resource](https://github.com/chef/chef/blob/master/RELEASE_NOTES.md#windows_dns_record-resource) instead of windows_dns. + Configures A and CNAME records in Windows DNS. This requires the DNSCMD to be installed, which is done by adding the DNS role to the server or installing the Remote Server Admin Tools. #### Actions @@ -213,6 +215,20 @@ windows_http_acl 'http://+:50051/' do end ``` +### windows_schannel + +Used to configure the schannel security settings in windows, this is used by dotnet apps and powershell to be able to speak to tls 1.2 endpoints + +#### Actions + +- `configure`: Configures the setting + +#### Properties + +property | type | default | description +------------------------ | ---------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- +`use_strong_crypto` | True, False | true | Enables or disables the setting + ### windows_share `Note`: This resource is now included in Chef 14.7 and later. There is no need to depend on the Windows cookbook for this resource. @@ -345,6 +361,8 @@ SeTakeOwnershipPrivilege Take ownership of files or other objects ### windows_zipfile +`Note`: This resource has been deprecated as Chef Infra Client 15.0 shipped with a new archive_file resource, which natively handles multiple archive formats. Please update any cookbooks using this resource to instead use the `archive_file` resource: https://docs.chef.io/resource_archive_file.html + Most version of Windows do not ship with native cli utility for managing compressed files. This resource provides a pure-ruby implementation for managing zip files. Be sure to use the `not_if` or `only_if` meta parameters to guard the resource for idempotence or action will be taken every Chef run. #### Actions diff --git a/cookbooks/windows/appveyor.yml b/cookbooks/windows/appveyor.yml index 9c4a3d3b..d4b417b2 100644 --- a/cookbooks/windows/appveyor.yml +++ b/cookbooks/windows/appveyor.yml @@ -2,6 +2,7 @@ environment: machine_user: vagrant machine_pass: vagrant KITCHEN_YAML: kitchen.appveyor.yml + CHEF_LICENSE: accept branches: only: diff --git a/cookbooks/windows/kitchen.appveyor.yml b/cookbooks/windows/kitchen.appveyor.yml index 881efdaa..000e9df2 100644 --- a/cookbooks/windows/kitchen.appveyor.yml +++ b/cookbooks/windows/kitchen.appveyor.yml @@ -15,7 +15,7 @@ provisioner: name: chef_zero deprecations_as_errors: true product_name: chef - product_version: 13 + product_version: 14 platforms: - name: windows-2012R2 @@ -33,6 +33,9 @@ suites: - name: certificate run_list: - recipe[test::certificate] + - name: schannel + run_list: + - recipe[test::schannel] - name: share run_list: - recipe[test::share] diff --git a/cookbooks/windows/kitchen.yml b/cookbooks/windows/kitchen.yml index 633548cc..23cbec62 100644 --- a/cookbooks/windows/kitchen.yml +++ b/cookbooks/windows/kitchen.yml @@ -26,7 +26,7 @@ platforms: box: chef/windows-10-enterprise - name: windows-2008r2 driver: - box: tas50/windows_2008r2_updated + box: tas50/windows_2008r2 - name: windows-2012r2 driver: box: tas50/windows_2012r2 @@ -44,6 +44,9 @@ suites: - name: http_acl run_list: - recipe[test::http_acl] + - name: schannel + run_list: + - recipe[test::schannel] - name: share run_list: - recipe[test::share] diff --git a/cookbooks/windows/metadata.rb b/cookbooks/windows/metadata.rb index f65f147a..9c787e85 100644 --- a/cookbooks/windows/metadata.rb +++ b/cookbooks/windows/metadata.rb @@ -3,8 +3,7 @@ maintainer_email 'cookbooks@chef.io' license 'Apache-2.0' description 'Provides a set of useful Windows-specific primitives.' -long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) -version '6.0.0' +version '6.0.1' supports 'windows' source_url 'https://github.com/chef-cookbooks/windows' issues_url 'https://github.com/chef-cookbooks/windows/issues' diff --git a/cookbooks/windows/providers/dns.rb b/cookbooks/windows/providers/dns.rb index f6a8b31f..fae98587 100644 --- a/cookbooks/windows/providers/dns.rb +++ b/cookbooks/windows/providers/dns.rb @@ -23,11 +23,6 @@ include Windows::Helper -# Support whyrun -def whyrun_supported? - true -end - action :create do if @current_resource.exists needs_change = (@new_resource.record_type != @current_resource.record_type) || diff --git a/cookbooks/windows/resources/certificate.rb b/cookbooks/windows/resources/certificate.rb index 4003fbba..67b0a2f4 100644 --- a/cookbooks/windows/resources/certificate.rb +++ b/cookbooks/windows/resources/certificate.rb @@ -28,9 +28,9 @@ property :pfx_password, String property :private_key_acl, Array property :store_name, String, default: 'MY', equal_to: ['TRUSTEDPUBLISHER', 'TrustedPublisher', 'CLIENTAUTHISSUER', 'REMOTE DESKTOP', 'ROOT', 'TRUSTEDDEVICES', 'WEBHOSTING', 'CA', 'AUTHROOT', 'TRUSTEDPEOPLE', 'MY', 'SMARTCARDROOT', 'TRUST', 'DISALLOWED'] -property :user_store, [TrueClass, FalseClass], default: false +property :user_store, [true, false], default: false property :cert_path, String -property :sensitive, [ TrueClass, FalseClass ], default: lazy { |r| r.pfx_password ? true : false } +property :sensitive, [true, false], default: lazy { |r| r.pfx_password ? true : false } action :create do load_gem @@ -71,7 +71,6 @@ guard_script << cert_exists_script(hash) powershell_script "setting the acls on #{new_resource.source} in #{cert_location}\\#{new_resource.store_name}" do - guard_interpreter :powershell_script convert_boolean_return true code code_script only_if guard_script diff --git a/cookbooks/windows/resources/certificate_binding.rb b/cookbooks/windows/resources/certificate_binding.rb index df0aa442..5d908ecf 100644 --- a/cookbooks/windows/resources/certificate_binding.rb +++ b/cookbooks/windows/resources/certificate_binding.rb @@ -19,7 +19,6 @@ # limitations under the License. # -include Chef::Mixin::PowershellOut include Windows::Helper property :cert_name, String, name_property: true @@ -28,7 +27,7 @@ property :port, Integer, default: 443 property :app_id, String, default: '{4dc3e181-e14b-4a21-b022-59fc669b0914}' property :store_name, String, default: 'MY', equal_to: ['TRUSTEDPUBLISHER', 'CLIENTAUTHISSUER', 'REMOTE DESKTOP', 'ROOT', 'TRUSTEDDEVICES', 'WEBHOSTING', 'CA', 'AUTHROOT', 'TRUSTEDPEOPLE', 'MY', 'SMARTCARDROOT', 'TRUST'] -property :exists, [true, false], desired_state: true +property :exists, [true, false] load_current_value do |desired| mode = desired.address.match(/(\d+\.){3}\d+|\[.+\]/).nil? ? 'hostnameport' : 'ipport' diff --git a/cookbooks/windows/resources/dns.rb b/cookbooks/windows/resources/dns.rb index 35b02740..30149d42 100644 --- a/cookbooks/windows/resources/dns.rb +++ b/cookbooks/windows/resources/dns.rb @@ -1,6 +1,6 @@ # # Author:: Richard Lavey (richard.lavey@calastone.com) -# Cookbook Name:: windows +# Cookbook:: windows # Resource:: dns # # Copyright:: 2015, Calastone Ltd. @@ -18,10 +18,9 @@ # limitations under the License. # -actions :create, :delete default_action :create -attribute :host_name, kind_of: String, name_property: true, required: true +attribute :host_name, kind_of: String, required: true attribute :record_type, kind_of: String, default: 'A', regex: /^(?:A|CNAME)$/ attribute :dns_server, kind_of: String, default: '.' attribute :target, kind_of: [Array, String], required: true diff --git a/cookbooks/windows/resources/http_acl.rb b/cookbooks/windows/resources/http_acl.rb index c6750434..b78f1263 100644 --- a/cookbooks/windows/resources/http_acl.rb +++ b/cookbooks/windows/resources/http_acl.rb @@ -23,7 +23,7 @@ property :url, String, name_property: true property :user, String property :sddl, String -property :exists, [true, false], desired_state: true +property :exists, [true, false] # See https://msdn.microsoft.com/en-us/library/windows/desktop/cc307236%28v=vs.85%29.aspx for netsh info diff --git a/cookbooks/windows/resources/schannel.rb b/cookbooks/windows/resources/schannel.rb new file mode 100644 index 00000000..d6086010 --- /dev/null +++ b/cookbooks/windows/resources/schannel.rb @@ -0,0 +1,39 @@ +# +# Author:: Jason Field (jason.field@calastone.com) +# Cookbook:: windows +# Resource:: schannel +# +# Copyright:: 2019, Calastone Ltd. +# +# 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. +# + +property :use_strong_crypto, [true, false], default: true + +action :configure do + registry_key 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\.NETFramework\\v4.0.30319' do + values [{ + name: 'SchUseStrongCrypto', + type: :dword, + data: new_resource.use_strong_crypto ? 1 : 0, + }] + end + + registry_key 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\.NETFramework\\v4.0.30319' do + values [{ + name: 'SchUseStrongCrypto', + type: :dword, + data: new_resource.use_strong_crypto ? 1 : 0, + }] + end +end diff --git a/cookbooks/windows/resources/share.rb b/cookbooks/windows/resources/share.rb index 9e5196b2..a7edb26f 100644 --- a/cookbooks/windows/resources/share.rb +++ b/cookbooks/windows/resources/share.rb @@ -69,8 +69,6 @@ # Specifies which files and folders in the SMB share are visible to users. AccessBased: SMB does not the display the files and folders for a share to a user unless that user has rights to access the files and folders. By default, access-based enumeration is disabled for new SMB shares. Unrestricted: SMB displays files and folders to a user even when the user does not have permission to access the items. # property :folder_enumeration_mode, String, equal_to: %(AccessBased Unrestricted) -include Chef::Mixin::PowershellOut - load_current_value do |desired| # this command selects individual objects because EncryptData & CachingMode have underlying # types that get converted to their Integer values by ConvertTo-Json & we need to make sure diff --git a/cookbooks/windows/resources/zipfile.rb b/cookbooks/windows/resources/zipfile.rb index 424717b7..f182b5a3 100644 --- a/cookbooks/windows/resources/zipfile.rb +++ b/cookbooks/windows/resources/zipfile.rb @@ -116,6 +116,7 @@ def ensure_rubyzip_gem_installed require 'zip' + Chef::Log.warn('The windows_zipfile resource has been deprecated as Chef Infra Client 15.0 shipped with a new archive_file resource, which natively handles multiple archive formats. Please update any cookbooks using this resource to instead use the `archive_file` resource: https://docs.chef.io/resource_archive_file.html') rescue LoadError Chef::Log.info("Missing gem 'rubyzip'...installing now.") chef_gem 'rubyzip' do diff --git a/cookbooks/windows/test/cookbooks/test/recipes/certificate.rb b/cookbooks/windows/test/cookbooks/test/recipes/certificate.rb index a16ec10a..ec74d869 100644 --- a/cookbooks/windows/test/cookbooks/test/recipes/certificate.rb +++ b/cookbooks/windows/test/cookbooks/test/recipes/certificate.rb @@ -1,4 +1,4 @@ -# We don't support reading the source from the cookbook yet. So manually point us to +# We don't support reading the source from the cookbook yet. So manually point us to # the correct place in the chef file cache. directory 'C:/certs' diff --git a/cookbooks/windows/test/cookbooks/test/recipes/schannel.rb b/cookbooks/windows/test/cookbooks/test/recipes/schannel.rb new file mode 100644 index 00000000..22e2d606 --- /dev/null +++ b/cookbooks/windows/test/cookbooks/test/recipes/schannel.rb @@ -0,0 +1,2 @@ +windows_schannel 'tls 1.2' do +end diff --git a/cookbooks/windows/test/integration/schannel/schannel_spec.rb b/cookbooks/windows/test/integration/schannel/schannel_spec.rb new file mode 100644 index 00000000..d6399614 --- /dev/null +++ b/cookbooks/windows/test/integration/schannel/schannel_spec.rb @@ -0,0 +1,3 @@ +describe powershell('[Net.ServicePointManager]::SecurityProtocol') do + its('strip') { should match /Tls12/ } +end From f87c7bec89b5fafdc5514e6fcafa211984efa226 Mon Sep 17 00:00:00 2001 From: Suyash Mohan Date: Tue, 31 Mar 2020 17:43:43 +0800 Subject: [PATCH 2/5] remove github linkage --- cookbooks/windows/.delivery/project.toml | 1 - cookbooks/windows/.github/CODEOWNERS | 1 - .../.github/ISSUE_TEMPLATE/BUG_TEMPLATE.md | 26 ---------- .../ENHANCEMENT_REQUEST_TEMPLATE.md | 18 ------- .../ISSUE_TEMPLATE/SUPPORT_QUESTION.md | 13 ----- .../windows/.github/PULL_REQUEST_TEMPLATE.md | 14 ------ .../windows/.github/workflows/delivery.yml | 16 ------ cookbooks/windows/.gitignore | 49 ------------------- 8 files changed, 138 deletions(-) delete mode 100644 cookbooks/windows/.delivery/project.toml delete mode 100644 cookbooks/windows/.github/CODEOWNERS delete mode 100644 cookbooks/windows/.github/ISSUE_TEMPLATE/BUG_TEMPLATE.md delete mode 100644 cookbooks/windows/.github/ISSUE_TEMPLATE/ENHANCEMENT_REQUEST_TEMPLATE.md delete mode 100644 cookbooks/windows/.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md delete mode 100644 cookbooks/windows/.github/PULL_REQUEST_TEMPLATE.md delete mode 100644 cookbooks/windows/.github/workflows/delivery.yml delete mode 100644 cookbooks/windows/.gitignore diff --git a/cookbooks/windows/.delivery/project.toml b/cookbooks/windows/.delivery/project.toml deleted file mode 100644 index 6d5e3617..00000000 --- a/cookbooks/windows/.delivery/project.toml +++ /dev/null @@ -1 +0,0 @@ -remote_file = "https://raw.githubusercontent.com/chef-cookbooks/community_cookbook_tools/master/delivery/project.toml" diff --git a/cookbooks/windows/.github/CODEOWNERS b/cookbooks/windows/.github/CODEOWNERS deleted file mode 100644 index 8b0f7d00..00000000 --- a/cookbooks/windows/.github/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @chef-cookbooks/windows-team diff --git a/cookbooks/windows/.github/ISSUE_TEMPLATE/BUG_TEMPLATE.md b/cookbooks/windows/.github/ISSUE_TEMPLATE/BUG_TEMPLATE.md deleted file mode 100644 index e8bae1b8..00000000 --- a/cookbooks/windows/.github/ISSUE_TEMPLATE/BUG_TEMPLATE.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -name: 🐛 Bug Report -about: If something isn't working as expected 🤔. - ---- - -### Cookbook version -[Version of the cookbook where you are encountering the issue] - -### Chef-client version -[Version of chef-client in your environment] - -### Platform Details -[Operating system distribution and release version. Cloud provider if running in the cloud] - -### Scenario: -[What you are trying to achieve and you can't?] - -### Steps to Reproduce: -[If you are filing an issue what are the things we need to do in order to repro your problem? How are you using this cookbook or any resources it includes?] - -### Expected Result: -[What are you expecting to happen as the consequence of above reproduction steps?] - -### Actual Result: -[What actually happens after the reproduction steps? Include the error output or a link to a gist if possible.] diff --git a/cookbooks/windows/.github/ISSUE_TEMPLATE/ENHANCEMENT_REQUEST_TEMPLATE.md b/cookbooks/windows/.github/ISSUE_TEMPLATE/ENHANCEMENT_REQUEST_TEMPLATE.md deleted file mode 100644 index cbf9f091..00000000 --- a/cookbooks/windows/.github/ISSUE_TEMPLATE/ENHANCEMENT_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: 🚀 Enhancement Request -about: I have a suggestion (and may want to implement it 🙂)! - ---- - -### Describe the Enhancement: -[What you are trying to achieve that you can't?] - -### Describe the Need: - -[What kind of user do you believe would utilize this enhancement, and how many users might want this functionality] - -### Current Alternative -[Is there a current alternative that you can utilize to workaround the lack of this enhancement] - -### Can We Help You Implement This?: -[The best way to ensure your enhancement is built is to help implement the enhancement yourself. If you're interested in helping out we'd love to give you a hand to make this possible. Let us know if there's something you need.] diff --git a/cookbooks/windows/.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md b/cookbooks/windows/.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md deleted file mode 100644 index f5063188..00000000 --- a/cookbooks/windows/.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: 🤗 Support Question -about: If you have a question 💬, please check out our Slack! - ---- - -We use GitHub issues to track bugs and feature requests. If you need help please post to our Mailing List or join the Chef Community Slack. - - * Chef Community Slack at http://community-slack.chef.io/. - * Chef Mailing List https://discourse.chef.io/ - - - Support issues opened here will be closed and redirected to Slack or Discourse. diff --git a/cookbooks/windows/.github/PULL_REQUEST_TEMPLATE.md b/cookbooks/windows/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index b8c6d9f9..00000000 --- a/cookbooks/windows/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,14 +0,0 @@ -### Description - -[Describe what this change achieves] - -### Issues Resolved - -[List any existing issues this PR resolves] - -### Check List - -- [ ] All tests pass. See -- [ ] New functionality includes testing. -- [ ] New functionality has been documented in the README if applicable -- [ ] All commits have been signed for the Developer Certificate of Origin. See diff --git a/cookbooks/windows/.github/workflows/delivery.yml b/cookbooks/windows/.github/workflows/delivery.yml deleted file mode 100644 index 4b5c4676..00000000 --- a/cookbooks/windows/.github/workflows/delivery.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: delivery - -on: [push, pull_request] - -jobs: - delivery: - - runs-on: ubuntu-latest - - steps: - - name: Check out code - uses: actions/checkout@master - - name: Run Chef Delivery - uses: actionshub/chef-delivery@master - env: - CHEF_LICENSE: accept-no-persist \ No newline at end of file diff --git a/cookbooks/windows/.gitignore b/cookbooks/windows/.gitignore deleted file mode 100644 index 8f93e577..00000000 --- a/cookbooks/windows/.gitignore +++ /dev/null @@ -1,49 +0,0 @@ -*.rbc -.config -coverage -InstalledFiles -lib/bundler/man -pkg -rdoc -spec/reports -test/tmp -test/version_tmp -tmp -_Store -*~ -*# -.#* -\#*# -.*.sw[a-z] -*.un~ -*.tmp -*.bk -*.bkup - -# ruby/bundler files -.ruby-version -.ruby-gemset -.rvmrc -Gemfile.lock -.bundle -*.gem - -# YARD artifacts -.yardoc -_yardoc -doc/ -.idea - -# chef stuff -Berksfile.lock -.kitchen -kitchen.local.yml -vendor/ -.coverage/ -.zero-knife.rb -Policyfile.lock.json - -# vagrant stuff -.vagrant/ -.vagrant.d/ -.kitchen/ From a74114ecb73984b8c19f1d6788d466c9b647b994 Mon Sep 17 00:00:00 2001 From: Suyash Mohan Date: Tue, 31 Mar 2020 17:49:40 +0800 Subject: [PATCH 3/5] remove iis --- cookbooks/iis | 1 - 1 file changed, 1 deletion(-) delete mode 160000 cookbooks/iis diff --git a/cookbooks/iis b/cookbooks/iis deleted file mode 160000 index e19362a1..00000000 --- a/cookbooks/iis +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e19362a1ae9bfe9748ebcfde2f21951f1fd19b1b From 3abd05fad2cfd69e88c03e98b92559a5f911c06f Mon Sep 17 00:00:00 2001 From: Suyash Mohan Date: Tue, 31 Mar 2020 17:50:32 +0800 Subject: [PATCH 4/5] add iis --- cookbooks/iis/.rubocop.yml | 20 + cookbooks/iis/Berksfile | 7 + cookbooks/iis/CHANGELOG.md | 424 ++++++++++ cookbooks/iis/CONTRIBUTING.md | 2 + cookbooks/iis/Gemfile | 9 + cookbooks/iis/LICENSE | 202 +++++ cookbooks/iis/MAINTAINERS.md | 15 + cookbooks/iis/README.md | 752 ++++++++++++++++++ cookbooks/iis/TESTING.md | 2 + cookbooks/iis/appveyor.yml | 38 + cookbooks/iis/attributes/default.rb | 29 + cookbooks/iis/chefignore | 93 +++ cookbooks/iis/kitchen.appveyor.yml | 54 ++ cookbooks/iis/kitchen.yml | 72 ++ cookbooks/iis/libraries/constants.rb | 410 ++++++++++ cookbooks/iis/libraries/helper.rb | 91 +++ cookbooks/iis/libraries/processors.rb | 118 +++ cookbooks/iis/libraries/section_helper.rb | 77 ++ cookbooks/iis/metadata.rb | 11 + cookbooks/iis/recipes/default.rb | 29 + .../recipes/mod_application_initialization.rb | 23 + cookbooks/iis/recipes/mod_aspnet.rb | 28 + cookbooks/iis/recipes/mod_aspnet45.rb | 24 + cookbooks/iis/recipes/mod_auth_anonymous.rb | 26 + cookbooks/iis/recipes/mod_auth_basic.rb | 28 + cookbooks/iis/recipes/mod_auth_digest.rb | 28 + cookbooks/iis/recipes/mod_auth_windows.rb | 28 + cookbooks/iis/recipes/mod_cgi.rb | 23 + cookbooks/iis/recipes/mod_compress_dynamic.rb | 23 + cookbooks/iis/recipes/mod_compress_static.rb | 23 + cookbooks/iis/recipes/mod_ftp.rb | 23 + .../iis/recipes/mod_iis6_metabase_compat.rb | 23 + cookbooks/iis/recipes/mod_isapi.rb | 23 + cookbooks/iis/recipes/mod_logging.rb | 23 + cookbooks/iis/recipes/mod_management.rb | 26 + cookbooks/iis/recipes/mod_security.rb | 23 + cookbooks/iis/recipes/mod_tracing.rb | 23 + cookbooks/iis/recipes/remove_default_site.rb | 27 + cookbooks/iis/resources/app.rb | 144 ++++ cookbooks/iis/resources/config.rb | 42 + cookbooks/iis/resources/config_property.rb | 110 +++ cookbooks/iis/resources/install.rb | 31 + cookbooks/iis/resources/manager.rb | 74 ++ cookbooks/iis/resources/manager_permission.rb | 84 ++ cookbooks/iis/resources/module.rb | 133 ++++ cookbooks/iis/resources/pool.rb | 471 +++++++++++ cookbooks/iis/resources/root.rb | 86 ++ cookbooks/iis/resources/section.rb | 71 ++ cookbooks/iis/resources/site.rb | 228 ++++++ cookbooks/iis/resources/vdir.rb | 142 ++++ cookbooks/iis/spec/spec_helper.rb | 10 + .../iis/spec/unit/recipes/default_spec.rb | 57 ++ .../unit/recipes/remove_default_site_spec.rb | 43 + cookbooks/iis/tasks/maintainers.rb | 75 ++ cookbooks/iis/test/cookbooks/test/chefignore | 100 +++ .../F5XFFHttpModule/x64/F5XFFHttpModule.dll | Bin 0 -> 70144 bytes .../F5XFFHttpModule/x86/F5XFFHttpModule.dll | Bin 0 -> 65024 bytes cookbooks/iis/test/cookbooks/test/metadata.rb | 7 + .../iis/test/cookbooks/test/recipes/app.rb | 31 + .../iis/test/cookbooks/test/recipes/config.rb | 44 + .../cookbooks/test/recipes/config_property.rb | 74 ++ .../test/cookbooks/test/recipes/manager.rb | 7 + .../test/recipes/manager_permission.rb | 9 + .../iis/test/cookbooks/test/recipes/module.rb | 69 ++ .../iis/test/cookbooks/test/recipes/pool.rb | 92 +++ .../iis/test/cookbooks/test/recipes/root.rb | 30 + .../test/cookbooks/test/recipes/section.rb | 25 + .../iis/test/cookbooks/test/recipes/site.rb | 101 +++ .../iis/test/cookbooks/test/recipes/vdir.rb | 93 +++ cookbooks/iis/test/integration/app/README.md | 3 + .../test/integration/app/controls/app_spec.rb | 24 + cookbooks/iis/test/integration/app/inspec.yml | 6 + .../test/integration/app/libraries/.gitkeep | 0 .../test/integration/app/libraries/iis_app.rb | 124 +++ .../config_property/config_property_spec.rb | 26 + .../integration/default/spec/default_spec.rb | 30 + .../iis/test/integration/manager/manager.rb | 10 + .../manager_permission/manager_permission.rb | 9 + .../iis/test/integration/module/README.md | 3 + .../module/controls/module_spec.rb | 30 + .../iis/test/integration/module/inspec.yml | 6 + .../integration/module/libraries/.gitkeep | 0 .../module/libraries/iis_module.rb | 103 +++ cookbooks/iis/test/integration/pool/README.md | 3 + .../integration/pool/controls/pool_spec.rb | 69 ++ .../iis/test/integration/pool/inspec.yml | 8 + .../test/integration/pool/libraries/.gitkeep | 0 .../integration/pool/libraries/iis_pool.rb | 255 ++++++ cookbooks/iis/test/integration/root/README.md | 3 + .../integration/root/controls/root_spec.rb | 21 + .../iis/test/integration/root/inspec.yml | 6 + .../test/integration/root/libraries/.gitkeep | 0 .../integration/root/libraries/iis_root.rb | 91 +++ .../iis/test/integration/section/README.md | 3 + .../section/controls/section_spec.rb | 17 + .../iis/test/integration/section/inspec.yml | 6 + .../integration/section/libraries/.gitkeep | 0 .../section/libraries/iis_section.rb | 99 +++ .../iis/test/integration/site/site_spec.rb | 58 ++ cookbooks/iis/test/integration/vdir/README.md | 3 + .../integration/vdir/controls/vdir_spec.rb | 36 + .../iis/test/integration/vdir/inspec.yml | 6 + .../test/integration/vdir/libraries/.gitkeep | 0 .../integration/vdir/libraries/iis_vdir.rb | 147 ++++ 104 files changed, 6588 insertions(+) create mode 100644 cookbooks/iis/.rubocop.yml create mode 100644 cookbooks/iis/Berksfile create mode 100644 cookbooks/iis/CHANGELOG.md create mode 100644 cookbooks/iis/CONTRIBUTING.md create mode 100644 cookbooks/iis/Gemfile create mode 100644 cookbooks/iis/LICENSE create mode 100644 cookbooks/iis/MAINTAINERS.md create mode 100644 cookbooks/iis/README.md create mode 100644 cookbooks/iis/TESTING.md create mode 100644 cookbooks/iis/appveyor.yml create mode 100644 cookbooks/iis/attributes/default.rb create mode 100644 cookbooks/iis/chefignore create mode 100644 cookbooks/iis/kitchen.appveyor.yml create mode 100644 cookbooks/iis/kitchen.yml create mode 100644 cookbooks/iis/libraries/constants.rb create mode 100644 cookbooks/iis/libraries/helper.rb create mode 100644 cookbooks/iis/libraries/processors.rb create mode 100644 cookbooks/iis/libraries/section_helper.rb create mode 100644 cookbooks/iis/metadata.rb create mode 100644 cookbooks/iis/recipes/default.rb create mode 100644 cookbooks/iis/recipes/mod_application_initialization.rb create mode 100644 cookbooks/iis/recipes/mod_aspnet.rb create mode 100644 cookbooks/iis/recipes/mod_aspnet45.rb create mode 100644 cookbooks/iis/recipes/mod_auth_anonymous.rb create mode 100644 cookbooks/iis/recipes/mod_auth_basic.rb create mode 100644 cookbooks/iis/recipes/mod_auth_digest.rb create mode 100644 cookbooks/iis/recipes/mod_auth_windows.rb create mode 100644 cookbooks/iis/recipes/mod_cgi.rb create mode 100644 cookbooks/iis/recipes/mod_compress_dynamic.rb create mode 100644 cookbooks/iis/recipes/mod_compress_static.rb create mode 100644 cookbooks/iis/recipes/mod_ftp.rb create mode 100644 cookbooks/iis/recipes/mod_iis6_metabase_compat.rb create mode 100644 cookbooks/iis/recipes/mod_isapi.rb create mode 100644 cookbooks/iis/recipes/mod_logging.rb create mode 100644 cookbooks/iis/recipes/mod_management.rb create mode 100644 cookbooks/iis/recipes/mod_security.rb create mode 100644 cookbooks/iis/recipes/mod_tracing.rb create mode 100644 cookbooks/iis/recipes/remove_default_site.rb create mode 100644 cookbooks/iis/resources/app.rb create mode 100644 cookbooks/iis/resources/config.rb create mode 100644 cookbooks/iis/resources/config_property.rb create mode 100644 cookbooks/iis/resources/install.rb create mode 100644 cookbooks/iis/resources/manager.rb create mode 100644 cookbooks/iis/resources/manager_permission.rb create mode 100644 cookbooks/iis/resources/module.rb create mode 100644 cookbooks/iis/resources/pool.rb create mode 100644 cookbooks/iis/resources/root.rb create mode 100644 cookbooks/iis/resources/section.rb create mode 100644 cookbooks/iis/resources/site.rb create mode 100644 cookbooks/iis/resources/vdir.rb create mode 100644 cookbooks/iis/spec/spec_helper.rb create mode 100644 cookbooks/iis/spec/unit/recipes/default_spec.rb create mode 100644 cookbooks/iis/spec/unit/recipes/remove_default_site_spec.rb create mode 100644 cookbooks/iis/tasks/maintainers.rb create mode 100644 cookbooks/iis/test/cookbooks/test/chefignore create mode 100644 cookbooks/iis/test/cookbooks/test/files/default/F5XFFHttpModule/x64/F5XFFHttpModule.dll create mode 100644 cookbooks/iis/test/cookbooks/test/files/default/F5XFFHttpModule/x86/F5XFFHttpModule.dll create mode 100644 cookbooks/iis/test/cookbooks/test/metadata.rb create mode 100644 cookbooks/iis/test/cookbooks/test/recipes/app.rb create mode 100644 cookbooks/iis/test/cookbooks/test/recipes/config.rb create mode 100644 cookbooks/iis/test/cookbooks/test/recipes/config_property.rb create mode 100644 cookbooks/iis/test/cookbooks/test/recipes/manager.rb create mode 100644 cookbooks/iis/test/cookbooks/test/recipes/manager_permission.rb create mode 100644 cookbooks/iis/test/cookbooks/test/recipes/module.rb create mode 100644 cookbooks/iis/test/cookbooks/test/recipes/pool.rb create mode 100644 cookbooks/iis/test/cookbooks/test/recipes/root.rb create mode 100644 cookbooks/iis/test/cookbooks/test/recipes/section.rb create mode 100644 cookbooks/iis/test/cookbooks/test/recipes/site.rb create mode 100644 cookbooks/iis/test/cookbooks/test/recipes/vdir.rb create mode 100644 cookbooks/iis/test/integration/app/README.md create mode 100644 cookbooks/iis/test/integration/app/controls/app_spec.rb create mode 100644 cookbooks/iis/test/integration/app/inspec.yml create mode 100644 cookbooks/iis/test/integration/app/libraries/.gitkeep create mode 100644 cookbooks/iis/test/integration/app/libraries/iis_app.rb create mode 100644 cookbooks/iis/test/integration/config_property/config_property_spec.rb create mode 100644 cookbooks/iis/test/integration/default/spec/default_spec.rb create mode 100644 cookbooks/iis/test/integration/manager/manager.rb create mode 100644 cookbooks/iis/test/integration/manager_permission/manager_permission.rb create mode 100644 cookbooks/iis/test/integration/module/README.md create mode 100644 cookbooks/iis/test/integration/module/controls/module_spec.rb create mode 100644 cookbooks/iis/test/integration/module/inspec.yml create mode 100644 cookbooks/iis/test/integration/module/libraries/.gitkeep create mode 100644 cookbooks/iis/test/integration/module/libraries/iis_module.rb create mode 100644 cookbooks/iis/test/integration/pool/README.md create mode 100644 cookbooks/iis/test/integration/pool/controls/pool_spec.rb create mode 100644 cookbooks/iis/test/integration/pool/inspec.yml create mode 100644 cookbooks/iis/test/integration/pool/libraries/.gitkeep create mode 100644 cookbooks/iis/test/integration/pool/libraries/iis_pool.rb create mode 100644 cookbooks/iis/test/integration/root/README.md create mode 100644 cookbooks/iis/test/integration/root/controls/root_spec.rb create mode 100644 cookbooks/iis/test/integration/root/inspec.yml create mode 100644 cookbooks/iis/test/integration/root/libraries/.gitkeep create mode 100644 cookbooks/iis/test/integration/root/libraries/iis_root.rb create mode 100644 cookbooks/iis/test/integration/section/README.md create mode 100644 cookbooks/iis/test/integration/section/controls/section_spec.rb create mode 100644 cookbooks/iis/test/integration/section/inspec.yml create mode 100644 cookbooks/iis/test/integration/section/libraries/.gitkeep create mode 100644 cookbooks/iis/test/integration/section/libraries/iis_section.rb create mode 100644 cookbooks/iis/test/integration/site/site_spec.rb create mode 100644 cookbooks/iis/test/integration/vdir/README.md create mode 100644 cookbooks/iis/test/integration/vdir/controls/vdir_spec.rb create mode 100644 cookbooks/iis/test/integration/vdir/inspec.yml create mode 100644 cookbooks/iis/test/integration/vdir/libraries/.gitkeep create mode 100644 cookbooks/iis/test/integration/vdir/libraries/iis_vdir.rb diff --git a/cookbooks/iis/.rubocop.yml b/cookbooks/iis/.rubocop.yml new file mode 100644 index 00000000..22007b4a --- /dev/null +++ b/cookbooks/iis/.rubocop.yml @@ -0,0 +1,20 @@ +# rubocop todo + +Lint/ParenthesesAsGroupedExpression: + Exclude: + - 'test/**/*.rb' + +Naming/PredicateName: + Exclude: + - 'spec/**/*' + - 'test/integration/**/*' + +Style/IfUnlessModifier: + Exclude: + - 'resources/pool.rb' + - 'resources/site.rb' + +# Fix missing Carriage return error on Windows +# https://github.com/bbatsov/rubocop/issues/4293 +Layout/EndOfLine: + EnforcedStyle: lf diff --git a/cookbooks/iis/Berksfile b/cookbooks/iis/Berksfile new file mode 100644 index 00000000..5a7274b5 --- /dev/null +++ b/cookbooks/iis/Berksfile @@ -0,0 +1,7 @@ +source 'https://supermarket.chef.io' + +metadata + +group :integration do + cookbook 'test', path: 'test/cookbooks/test' +end diff --git a/cookbooks/iis/CHANGELOG.md b/cookbooks/iis/CHANGELOG.md new file mode 100644 index 00000000..69cf5a15 --- /dev/null +++ b/cookbooks/iis/CHANGELOG.md @@ -0,0 +1,424 @@ +# iis Cookbook CHANGELOG + +This file is used to list changes made in each version of the iis cookbook. + +## 7.3.0 (2020-03-06) + +- Cookstyle fixes - [@tas50](https://github.com/tas50) +- extend config_property to support setting multiple values - [@rlaveycal](https://github.com/rlaveycal) +- Remove deprecated metadata - [@tas50](https://github.com/tas50) +- Don't use node.normal in the specs - [@tas50](https://github.com/tas50) +- Adds support for configuring environment variables on app pools on IIS 10+ - [@jakauppila](https://github.com/jakauppila) + +## 7.2.0 (2019-01-02) + +- Add a new iis_manager resource to enable users to set permissions for remote management of IIS +- Resolve a deprecation warning in config_property + +## 7.1.1 (2018-10-25) + +- Fix password containing xml entities like & are set every run +- Fix passwords with quotation marks do not get set correctly +- Renamed the kitchen files and use non-private boxes + +## 7.1.0 (2018-07-19) + +- iis_pool: Updated cmd to clear out username and password when changing to a different Identity Type +- Added new config_property resource which uses powershell and is fully idempotent. + +## 7.0.0 (2018-05-29) + +### Breaking Changes + +- Removed support for Windows 2008 R1 as this is no longer supported by Microsoft or Chef +- We now require Chef 12.14 or later as we are specifying `sensitive` on password properties so these aren't sent to Chef Analytics or Automate +- Removed ChefSpec matchers that are autogenerated by ChefSpec now +- Increased the Windows cookbook requirement to version 4.1+ which fixed many bugs in feature installation and matches the code in Chef 14 +- All helper methods have been moved from Opscode::IIS to IISCookbook + +### Other Changes + +- Added a new resource to install IIS: iis_install. This makes writing your own resource driven cookbooks just a tiny bit easier +- Added a name property `:pool_name` to the pool resource to allow you to use friendly resource names and avoid resource cloning +- Added testing on Windows 2016 +- Removed unused `new_value?` and `new_or_empty_value?` helpers methods +- Fixed a bug in iis_site that stopped site from being updated on port update +- Fixed site resource defaulting the log_directory when not specified, thus no longer inheriting the server default +- Removed checks for EOL platforms to speed up runs +- Removed some Chef 11-isms from the readme +- Added tests that installs and adds an HTTP Module (#410) +- Resolved a new FC118 foodcritic warning +- Fixed the installation of HTTP Tracing in the mod_tracing recipe +- Updated .rubocop.yml file for the new Cookstyle in DK 3.0 +- Updated the maintainers list for the current maintainers + +## 6.8.1 (2018-04-03) + +- Fixed site resource defaulting the log_directory when not specified, thus no longer inheriting the server default + +## 6.8.0 (2017-10-18) + +- [Adds `periodic_restart_schedule` the ability to define multiple recycle times on an app pool](https://github.com/chef-cookbooks/iis/pull/397) + +## 6.7.3 (2017-09-08) + +- Add better documentation for the options parameter (#383) +- Resolve a Chef 14 deprecation warning + +## 6.7.2 (2017-06-21) + +- Fix FTP issue with iis_site resource + +## 6.7.1 (2017-06-09) + +- [Fix issue with guard clause missing on check](https://github.com/chef-cookbooks/iis/pull/378) + +## 6.7.0 (2017-06-09) + +- [Fix idempotency in `iis_app`, `iis_root`, and `iis_vdir`](https://github.com/chef-cookbooks/iis/pull/375) + +## 6.6.0 (2017-06-01) + +- Convert `iis_module` to a custom resource + +## 6.5.3 (2017-05-17) + +- Refactor `iis_vdir` name property to `application_name` +- Resolves a bug in iis_vdir also adds more liberty in config + +## 6.5.2 (2017-05-15) + +- [Update iis_vdir name to not require a trailing /](https://github.com/chef-cookbooks/iis/pull/363) +- [Fix iis_pool identity_type issue](https://github.com/chef-cookbooks/iis/pull/362) + +## 6.5.1 (2017-05-12) + +- [iis_pool is not Idempotent](https://github.com/chef-cookbooks/iis/issues/354) +- Fix whitespace in `iis_pool` name + +## 6.5.0 (2017-05-10) + +- Convert `iis_root` to a custom resource +- [uninitialized constant Chef::Resource::IisRoot](https://github.com/chef-cookbooks/iis/issues/333) +- [mime types are not deleted](https://github.com/chef-cookbooks/iis/issues/321) +- [iis_root errors on 'duplicate collection entry of type 'mimeMap'](https://github.com/chef-cookbooks/iis/issues/199) + +## 6.4.1 (2017-05-05) + +- [fix bug with start having ! in front](https://github.com/chef-cookbooks/iis/pull/349) + +## 6.4.0 (2017-05-04) + +- Convert `iis_section` to a custom resource +- Resolve issue with `iis_pool` + +## 6.3.1 (2017-04-26) + +- [Fix multiple issues with ~FC023](https://github.com/chef-cookbooks/iis/pull/341) + +## 6.3.0 (2017-04-24) + +- Convert `iis_pool` to a custom resource +- Convert `iis_vdir` to a custom resource +- Bug fix for `log` function change to `Chef::Log` + +## 6.2.0 (2017-04-18) + +- Convert `iis_site` to a custom resource + +## 6.1.0 (2017-04-14) + +- Convert `iis_config` to a custom resource + +## 6.0.1 (2017-04-07) + +- Fix undefined method `site_identifier` with iis_app resource. + +## 6.0.0 (2017-04-06) + +- Rewrite of `iis_app` resource to use custom resources. +- Addition of testing for `iis_app` resource. + +## 5.1.0 (2017-03-20) + +- Require at least windows 2.0 cookbook +- Run integration testing in Appveyer +- Switched testing to Inspec from pester/ServerSpec combo +- Removed the empty iis_test cookbook + +## 5.0.8 (2017-03-13) + +- [iis-root default_documents broke from last fix](#306) + +## 5.0.7 (2017-03-07) + +- [iis-root default_documents deleted every chef run](#306) + +## 5.0.6 (2017-02-24) + +- [iis_version is not evaluated properly on if statement](#308) + +## 5.0.5 (2016-11-21) + +- [Fixed no_managed_code idempotency](#301) + +## 5.0.4 (2016-10-11) + +- fixed adding an app pool to a site - This fixes a bug where adding an app pool to a site causes an error. This was using the 'add app' where we are working with a site and the syntax is slightly different according to this [documentation](https://technet.microsoft.com/en-us/library/cc732992%28v=ws.10%29.aspx). + +## 5.0.3 (2016-10-10) + +- Log event on recycle - This allows you to specify which events you want to log on recycle. This also changes this so that it defaults to the standard nothing, which means you will need to add this attribute if you are depending on it. + +## 5.0.2 (2016-10-07) + +- [Minor over oversight in IIS::mod_aspnet 5.0.1](#296) +- [IIS Pool resource thirty_two_bit false doesn't](#292) + +## 5.0.1 (2016-09-21) + +- Fix mod_management to include dependencies (#293) + +## 5.0.0 (2016-09-06) + +- Adding 2k12 version flag to the windows_feature resource (#291) +- Testing updates +- Avoid deprecation warnings in the specs +- Require Chef 12+ + +## 4.2.0 (2016-08-09) + +- Feature pool recycle virtual memory (#288) + +## v4.1.10 (2016-06-29) + +- Resolves [Issue with error 50 when installing mod_aspnet](https://github.com/chef-cookbooks/iis/issues/285) + +## v4.1.9 (2016-06-26) + +- Resolves [Add deprecation warnings for iis_config in 4.2](https://github.com/chef-cookbooks/iis/issues/284) +- Resolves [iis_pool is not idempotent when recycle_at_time is specified and is not changed](https://github.com/chef-cookbooks/iis/issues/279) + +## v4.1.8 (2016-04-15) + +- Fixed smp_processor_affinity_mask throwing deprecation warnings +- Added additional chefspec tests +- Updated testing dependencies to the latests +- Disabled FC059 rule for now + +## v4.1.7 (2016-03-25) + +- Resolves [smp_processor_affinity_mask is wrong value type](https://github.com/chef-cookbooks/iis/issues/266) +- Resolves [Not a valid unsigned integer](https://github.com/chef-cookbooks/iis/issues/261) +- Resolves [Deprecated features used](https://github.com/chef-cookbooks/iis/issues/259) +- Resolves [Deprecated feature used, fix before chef 13](https://github.com/chef-cookbooks/iis/issues/253) +- Resolves [iis_site :config action not idempotent (Windows 2012 R2/IIS 8.5)](https://github.com/chef-cookbooks/iis/issues/249) +- Resolves [Can't set recycle_at_time to default](https://github.com/chef-cookbooks/iis/issues/247) + +## v4.1.6 (2016-02-01) + +- Resolves issues with [Unable to set app pool to be "No Managed Code"](https://github.com/chef-cookbooks/iis/issues/240) +- Resolves [Add_mime_maps is throwing compile error](https://github.com/chef-cookbooks/iis/issues/238) +- Resolves [FATAL: NameError: iis_root "xxx" had an error: NameError: No resource, method, or local variable named `was _updated' for`LWRP provider iis_root from cookbook iis](https://github.com/chef-cookbooks/iis/issues/236) + +## v4.1.5 (2015-11-18) + +- Resolves issues with `iis_root` [#222](https://github.com/chef-cookbooks/iis/issues/222) + +## v4.1.4 (2015-11-2) + +- Re-added functionality for iis_pool auto_start, this was a breaking change + +## v4.1.3 (2015-10-30) + +- Resolves Robucop issues +- Bug Fix for [#217](https://github.com/chef-cookbooks/iis/issues/217) + +## v4.1.2 (2015-10-21) + +- Bug fixes for application pool provider and site provider +- Added the ability to detect the IIS Version, allowing for some properties to only exist for specific IIS versions +- Fixed issue with Win32 being required on linux +- Added support for mimeTypes and defaultDocuments on iis_sites +- Added iis config set and clear abilities + +## v4.1.1 (2015-05-07) + +- Detects changes in the physical path of apps. +- Adds support for gMSA identity. +- Performing add on a site will now reconfigure it if necessary. +- Lock and unlock commands on configuration sections now use -commit:apphost. +- Fix issue where popeline_mode was ignored during configuration of a pool. + +## v4.1.0 (2015-03-04) + +- Removed iis_pool attribute 'set_profile_environment' incompatible with < IIS-8. +- Added pester test framework. +- Condensed and fixed change-log to show public releases only. +- Fixed bug where bindings were being overwritten by :config. +- Code-cleanup and cosmetic fixes. + +## v4.0.0 (2015-02-12) + +- [#91](https://github.com/chef-cookbooks/iis/pull/91) - bulk addition of new features + + - Virtual Directory Support (allows virtual directories to be added to both websites and to webapplications under sites). + - section unlock and lock support (this is used to allow for the web.config of a site to define the authentication methods). + - fixed issue with :add on pool provider not running all config (this was a known issue and is now resolved). + - fixed issue with :config on all providers causing application pool recycles (every chef-client run). + - moved to better method for XML checking of previous settings to detect changes (changed all check to use xml searching with appcmd instead of the previous method [none]). + +- Improved pool resource with many more apppool properties that can be set. +- Fixed bug with default attribute inheritance. +- New recipe to enable ASP.NET 4.5. +- Skeleton serverspec+test-kitchen framework. +- Added Berksfile, Gemfile and .kitchen.yml to assist developers. +- Fixed issue [#107] function is_new_or_empty was returning reverse results. +- Removed dependency on "chef-client", ">= 3.7.0". +- Changed all files to UTF-8 file format. +- Fixed issue with iis_pool not putting ApplicationPoolIdentity and username/password. +- [#98] Fixed issues with bindings. +- added backwards compatibility for chef-client < 12.x.x Chef::Util::PathHelper. + +## v2.1.6 (2014-11-12) + +- [#78] Adds new_resource.updated_by_last_action calls + +## v2.1.5 (2014-09-15) + +- [#68] Add win_friendly_path to all appcmd.exe /physicalPath arguments + +## v2.1.4 (2014-09-13) + +- [#72] Adds chefspec matchers +- [#57] Fixes site_id not being updated on a :config action + +## v2.1.2 (2014-04-23) + +- [COOK-4559] Remove invalid UTF-8 characters + +## v2.1.0 (2014-03-25) + +[COOK-4426] - feature order correction for proper installation [COOK-4428] - Add IIS FTP Feature Installation + +## v2.0.4 (2014-03-18) + +- [COOK-4420] Corrected incorrect feature names for mod_security + +## v2.0.2 (2014-02-25) + +- [COOK-4108] - Add documentation for the 'bindings' attribute in 'iis_site' LWRP + +## v2.0.0 (2014-01-03) + +Major version bump + +## v1.6.6 + +Adding extra windows platform checks to helper library + +## v1.6.4 + +### Bug + +- **[COOK-4138](https://tickets.chef.io/browse/COOK-4138)** - iis cookbook won't load on non-Windows platforms + +## v1.6.2 + +### Improvement + +- **[COOK-3634](https://tickets.chef.io/browse/COOK-3634)** - provide ability to set app pool managedRuntimeVersion to "No Managed Code" + +## v1.6.0 + +### Improvement + +- **[COOK-3922](https://tickets.chef.io/browse/COOK-3922)** - refactor IIS cookbook to not require WebPI + +## v1.5.6 + +### Improvement + +- **[COOK-3770](https://tickets.chef.io/browse/COOK-3770)** - Add Enabled Protocols to IIS App Recipe + +## v1.5.4 + +### New Feature + +- **[COOK-3675](https://tickets.chef.io/browse/COOK-3675)** - Add recipe for CGI module + +## v1.5.2 + +### Bug + +- **[COOK-3232](https://tickets.chef.io/browse/COOK-3232)** - Allow `iis_app` resource `:config` action with a virtual path + +## v1.5.0 + +### Improvement + +- [COOK-2370]: add MVC2, escape `application_pool` and add options for +- recycling +- [COOK-2694]: update iis documentation to show that Windows 2012 and +- Windows 8 are supported + +### Bug + +- [COOK-2325]: `load_current_resource` does not load state of pool +- correctly, always sets running to false +- [COOK-2526]: Installing IIS after .NET framework will leave +- installation in non-working state +- [COOK-2596]: iis cookbook fails with indecipherable error if EULA +- not accepted + +## v1.4.0 + +- [COOK-2181] -Adding full module support to iis cookbook + +## v1.3.6 + +- [COOK-2084] - Add support for additional options during site creation +- [COOK-2152] - Add recipe for IIS6 metabase compatibility + +## v1.3.4 + +- [COOK-2050] - IIS cookbook does not have returns resource defined + +## v1.3.2 + +- [COOK-1251] - Fix LWRP "NotImplementedError" + +## v1.3.0 + +- [COOK-1301] - Add a recycle action to the iis_pool resource +- [COOK-1665] - app pool identity and new node[iis][component] attribute +- [COOK-1666] - Recipe to remove default site and app pool +- [COOK-1858] - Recipe misspelled + +## v1.2.0 + +- [COOK-1061] - `iis_site` doesn't allow setting the pool +- [COOK-1078] - handle advanced bindings +- [COOK-1283] - typo on pool +- [COOK-1284] - install iis application initialization +- [COOK-1285] - allow multiple host_header, port and protocol +- [COOK-1286] - allow directly setting which app pool on site creation +- [COOK-1449] - iis pool regex returns true if similar site exists +- [COOK-1647] - mod_ApplicationInitialization isn't RC + +## v1.1.0 + +- [COOK-1012] - support adding apps +- [COOK-1028] - support for config command +- [COOK-1041] - fix removal in app pools +- [COOK-835] - add app pool management +- [COOK-950] - documentation correction for version of IIS/OS + +## v1.0.2 + +- Ruby 1.9 compat fixes +- ensure carriage returns are removed before applying regex + +## v1.0.0 + +- [COOK-718] initial release diff --git a/cookbooks/iis/CONTRIBUTING.md b/cookbooks/iis/CONTRIBUTING.md new file mode 100644 index 00000000..ef2f2b80 --- /dev/null +++ b/cookbooks/iis/CONTRIBUTING.md @@ -0,0 +1,2 @@ +Please refer to +https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD diff --git a/cookbooks/iis/Gemfile b/cookbooks/iis/Gemfile new file mode 100644 index 00000000..7938c74f --- /dev/null +++ b/cookbooks/iis/Gemfile @@ -0,0 +1,9 @@ +# This gemfile provides additional gems for testing and releasing this cookbook +# It is meant to be installed on top of ChefDK / Chef Workstation which provide the majority +# of the necessary gems for testing this cookbook +# +# Run 'chef exec bundle install' to install these dependencies + +source 'https://rubygems.org' + +gem 'community_cookbook_releaser' diff --git a/cookbooks/iis/LICENSE b/cookbooks/iis/LICENSE new file mode 100644 index 00000000..8f71f43f --- /dev/null +++ b/cookbooks/iis/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. + diff --git a/cookbooks/iis/MAINTAINERS.md b/cookbooks/iis/MAINTAINERS.md new file mode 100644 index 00000000..f81f8f9a --- /dev/null +++ b/cookbooks/iis/MAINTAINERS.md @@ -0,0 +1,15 @@ + + +# Maintainers + +This file lists how this cookbook project is maintained. When making changes to the system, this file tells you who needs to review your patch - you need a review from an existing maintainer for the cookbook to provide a :+1: on your pull request. Additionally, you need to not receive a veto from a Lieutenant or the Project Lead. + +Check out [How Cookbooks are Maintained](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) for details on the process and how to become a maintainer or the project lead. + +# Project Maintainer +* [Adam Edwards](https://github.com/adamedx) + +# Maintainers +* [Stuart Preston](https://github.com/stuartpreston) +* [Justin Schuhmann](https://github.com/EasyAsABC123) +* [Tim Smith](https://github.com/tas50) \ No newline at end of file diff --git a/cookbooks/iis/README.md b/cookbooks/iis/README.md new file mode 100644 index 00000000..268366ff --- /dev/null +++ b/cookbooks/iis/README.md @@ -0,0 +1,752 @@ +# iis Cookbook + +[![Build status](https://ci.appveyor.com/api/projects/status/f4gnv54b97rw1pbg/branch/master?svg=true)](https://ci.appveyor.com/project/ChefWindowsCookbooks/iis/branch/master) [![Cookbook Version](https://img.shields.io/cookbook/v/iis.svg)](https://supermarket.chef.io/cookbooks/iis) + +Installs and configures Microsoft Internet Information Services (IIS) 7.0 and later + +## Contents + +- [Attributes](#attributes) +- [Resources](#resources) + + - [iis_root](#iis_root) Allows for easy management of the IIS Root Machine settings + - [iis_site](#iis_site) Allows for easy management of IIS virtual sites (ie vhosts). + - [iis_config](#iis_config) Runs a config command on your IIS instance. + - [iis_config_property](#iis_config_property) Sets an IIS property idempotently via PowerShell. + - [iis_pool](#iis_pool) Creates an application pool in IIS. + - [iis_app](#iis_app) Creates an application in IIS. + - [iis_vdir](#iis_vdir) Allows easy management of IIS virtual directories (i.e. vdirs). + - [iis_section](#iis_section) Allows for the locking/unlocking of application web.config sections. + - [iis_module](#iis_module) Manages modules globally or on a per site basis. + +- [Usage](#usage) + + - [default](#default) Default recipe + - [mod_*](#mod_) Recipes for installing individual IIS modules (extensions). + +- [Alternatives](#alternative-cookbooks) + +- [License and Author](#license-and-author) + +## Requirements + +### Platforms + +- Windows Server 2008 R2 +- Windows Server 2012 (R1, R2) +- Windows Server 2016 + +### Chef + +- Chef 12.14+ + +### Cookbooks + +- windows + +## Attributes + +- `node['iis']['home']` - IIS main home directory. default is `%WINDIR%\System32\inetsrv` +- `node['iis']['conf_dir']` - location where main IIS configs lives. default is `%WINDIR%\System32\inetsrv\config` +- `node['iis']['pubroot']` - . default is `%SYSTEMDRIVE%\inetpub` +- `node['iis']['docroot']` - IIS web site home directory. default is `%SYSTEMDRIVE%\inetpub\wwwroot` +- `node['iis']['cache_dir']` - location of cached data. default is `%SYSTEMDRIVE%\inetpub\temp` + +## Resources + +### iis_install + +Simple resource to install the IIS feature + +#### Actions + +- `:install` + +#### Properties + +- `source` - Optional source to install the features from (String) +- `additional_components` - Optional features of IIS to install (Array) + +### iis_root + +Allows for easy management of the IIS Root Machine settings + +#### Actions + +`default` = `:config` + +- `:add` - only does addition operations will not delete anything to an Array object +- `:delete` - only does deletion operations will not add anything to an Array object +- `:config` - does both addition and deletion make sure your Array objects contain everything you want + +#### Properties + +- `default_documents_enabled` - Enables or disables default_documents for the root machine, Valid Values: true, false default: `true` +- `default_documents` - The items you want to set as the default document collection, only used during `:config`. Array of strings, default: `['Default.htm', 'Default.asp', 'index.htm', 'index.html', 'iisstart.htm', 'default.aspx']` +- `mime_maps` - The items you want to set as the mime-maps or mime-types collection, only used during `:config`. Array of strings, default: + + ```ruby + ["fileExtension='.323',mimeType='text/h323'", "fileExtension='.3g2',mimeType='video/3gpp2'", "fileExtension='.3gp2',mimeType='video/3gpp2'", "fileExtension='.3gp',mimeType='video/3gpp'", "fileExtension='.3gpp',mimeType='video/3gpp'", "fileExtension='.aaf',mimeType='application/octet-stream'", "fileExtension='.aac',mimeType='audio/aac'", "fileExtension='.aca',mimeType='application/octet-stream'", "fileExtension='.accdb',mimeType='application/msaccess'", "fileExtension='.accde',mimeType='application/msaccess'", "fileExtension='.accdt',mimeType='application/msaccess'", "fileExtension='.acx',mimeType='application/internet-property-stream'", "fileExtension='.adt',mimeType='audio/vnd.dlna.adts'", "fileExtension='.adts',mimeType='audio/vnd.dlna.adts'", "fileExtension='.afm',mimeType='application/octet-stream'", "fileExtension='.ai',mimeType='application/postscript'", "fileExtension='.aif',mimeType='audio/x-aiff'", "fileExtension='.aifc',mimeType='audio/aiff'", "fileExtension='.aiff',mimeType='audio/aiff'", "fileExtension='.application',mimeType='application/x-ms-application'", "fileExtension='.art',mimeType='image/x-jg'", "fileExtension='.asd',mimeType='application/octet-stream'", "fileExtension='.asf',mimeType='video/x-ms-asf'", "fileExtension='.asi',mimeType='application/octet-stream'", "fileExtension='.asm',mimeType='text/plain'", "fileExtension='.asr',mimeType='video/x-ms-asf'", "fileExtension='.asx',mimeType='video/x-ms-asf'", "fileExtension='.atom',mimeType='application/atom+xml'", "fileExtension='.au',mimeType='audio/basic'", "fileExtension='.avi',mimeType='video/avi'", "fileExtension='.axs',mimeType='application/olescript'", "fileExtension='.bas',mimeType='text/plain'", "fileExtension='.bcpio',mimeType='application/x-bcpio'", "fileExtension='.bin',mimeType='application/octet-stream'", "fileExtension='.bmp',mimeType='image/bmp'", "fileExtension='.c',mimeType='text/plain'", "fileExtension='.cab',mimeType='application/vnd.ms-cab-compressed'", "fileExtension='.calx',mimeType='application/vnd.ms-office.calx'", "fileExtension='.cat',mimeType='application/vnd.ms-pki.seccat'", "fileExtension='.cdf',mimeType='application/x-cdf'", "fileExtension='.chm',mimeType='application/octet-stream'", "fileExtension='.class',mimeType='application/x-java-applet'", "fileExtension='.clp',mimeType='application/x-msclip'", "fileExtension='.cmx',mimeType='image/x-cmx'", "fileExtension='.cnf',mimeType='text/plain'", "fileExtension='.cod',mimeType='image/cis-cod'", "fileExtension='.cpio',mimeType='application/x-cpio'", "fileExtension='.cpp',mimeType='text/plain'", "fileExtension='.crd',mimeType='application/x-mscardfile'", "fileExtension='.crl',mimeType='application/pkix-crl'", "fileExtension='.crt',mimeType='application/x-x509-ca-cert'", "fileExtension='.csh',mimeType='application/x-csh'", "fileExtension='.css',mimeType='text/css'", "fileExtension='.csv',mimeType='application/octet-stream'", "fileExtension='.cur',mimeType='application/octet-stream'", "fileExtension='.dcr',mimeType='application/x-director'", "fileExtension='.deploy',mimeType='application/octet-stream'", "fileExtension='.der',mimeType='application/x-x509-ca-cert'", "fileExtension='.dib',mimeType='image/bmp'", "fileExtension='.dir',mimeType='application/x-director'", "fileExtension='.disco',mimeType='text/xml'", "fileExtension='.dll',mimeType='application/x-msdownload'", "fileExtension='.dll.config',mimeType='text/xml'", "fileExtension='.dlm',mimeType='text/dlm'", "fileExtension='.doc',mimeType='application/msword'", "fileExtension='.docm',mimeType='application/vnd.ms-word.document.macroEnabled.12'", "fileExtension='.docx',mimeType='application/vnd.openxmlformats-officedocument.wordprocessingml.document'", "fileExtension='.dot',mimeType='application/msword'", "fileExtension='.dotm',mimeType='application/vnd.ms-word.template.macroEnabled.12'", "fileExtension='.dotx',mimeType='application/vnd.openxmlformats-officedocument.wordprocessingml.template'", "fileExtension='.dsp',mimeType='application/octet-stream'", "fileExtension='.dtd',mimeType='text/xml'", "fileExtension='.dvi',mimeType='application/x-dvi'", "fileExtension='.dvr-ms',mimeType='video/x-ms-dvr'", "fileExtension='.dwf',mimeType='drawing/x-dwf'", "fileExtension='.dwp',mimeType='application/octet-stream'", "fileExtension='.dxr',mimeType='application/x-director'", "fileExtension='.eml',mimeType='message/rfc822'", "fileExtension='.emz',mimeType='application/octet-stream'", "fileExtension='.eot',mimeType='application/vnd.ms-fontobject'", "fileExtension='.eps',mimeType='application/postscript'", "fileExtension='.etx',mimeType='text/x-setext'", "fileExtension='.evy',mimeType='application/envoy'", "fileExtension='.exe',mimeType='application/octet-stream'", "fileExtension='.exe.config',mimeType='text/xml'", "fileExtension='.fdf',mimeType='application/vnd.fdf'", "fileExtension='.fif',mimeType='application/fractals'", "fileExtension='.fla',mimeType='application/octet-stream'", "fileExtension='.flr',mimeType='x-world/x-vrml'", "fileExtension='.flv',mimeType='video/x-flv'", "fileExtension='.gif',mimeType='image/gif'", "fileExtension='.gtar',mimeType='application/x-gtar'", "fileExtension='.gz',mimeType='application/x-gzip'", "fileExtension='.h',mimeType='text/plain'", "fileExtension='.hdf',mimeType='application/x-hdf'", "fileExtension='.hdml',mimeType='text/x-hdml'", "fileExtension='.hhc',mimeType='application/x-oleobject'", "fileExtension='.hhk',mimeType='application/octet-stream'", "fileExtension='.hhp',mimeType='application/octet-stream'", "fileExtension='.hlp',mimeType='application/winhlp'", "fileExtension='.hqx',mimeType='application/mac-binhex40'", "fileExtension='.hta',mimeType='application/hta'", "fileExtension='.htc',mimeType='text/x-component'", "fileExtension='.htm',mimeType='text/html'", "fileExtension='.html',mimeType='text/html'", "fileExtension='.htt',mimeType='text/webviewhtml'", "fileExtension='.hxt',mimeType='text/html'", "fileExtension='.ico',mimeType='image/x-icon'", "fileExtension='.ics',mimeType='text/calendar'", "fileExtension='.ief',mimeType='image/ief'", "fileExtension='.iii',mimeType='application/x-iphone'", "fileExtension='.inf',mimeType='application/octet-stream'", "fileExtension='.ins',mimeType='application/x-internet-signup'", "fileExtension='.isp',mimeType='application/x-internet-signup'", "fileExtension='.IVF',mimeType='video/x-ivf'", "fileExtension='.jar',mimeType='application/java-archive'", "fileExtension='.java',mimeType='application/octet-stream'", "fileExtension='.jck',mimeType='application/liquidmotion'", "fileExtension='.jcz',mimeType='application/liquidmotion'", "fileExtension='.jfif',mimeType='image/pjpeg'", "fileExtension='.jpb',mimeType='application/octet-stream'", "fileExtension='.jpe',mimeType='image/jpeg'", "fileExtension='.jpeg',mimeType='image/jpeg'", "fileExtension='.jpg',mimeType='image/jpeg'", "fileExtension='.js',mimeType='application/javascript'", "fileExtension='.json',mimeType='application/json'", "fileExtension='.jsx',mimeType='text/jscript'", "fileExtension='.latex',mimeType='application/x-latex'", "fileExtension='.lit',mimeType='application/x-ms-reader'", "fileExtension='.lpk',mimeType='application/octet-stream'", "fileExtension='.lsf',mimeType='video/x-la-asf'", "fileExtension='.lsx',mimeType='video/x-la-asf'", "fileExtension='.lzh',mimeType='application/octet-stream'", "fileExtension='.m13',mimeType='application/x-msmediaview'", "fileExtension='.m14',mimeType='application/x-msmediaview'", "fileExtension='.m1v',mimeType='video/mpeg'", "fileExtension='.m2ts',mimeType='video/vnd.dlna.mpeg-tts'", "fileExtension='.m3u',mimeType='audio/x-mpegurl'", "fileExtension='.m4a',mimeType='audio/mp4'", "fileExtension='.m4v',mimeType='video/mp4'", "fileExtension='.man',mimeType='application/x-troff-man'", "fileExtension='.manifest',mimeType='application/x-ms-manifest'", "fileExtension='.map',mimeType='text/plain'", "fileExtension='.mdb',mimeType='application/x-msaccess'", "fileExtension='.mdp',mimeType='application/octet-stream'", "fileExtension='.me',mimeType='application/x-troff-me'", "fileExtension='.mht',mimeType='message/rfc822'", "fileExtension='.mhtml',mimeType='message/rfc822'", "fileExtension='.mid',mimeType='audio/mid'", "fileExtension='.midi',mimeType='audio/mid'", "fileExtension='.mix',mimeType='application/octet-stream'", "fileExtension='.mmf',mimeType='application/x-smaf'", "fileExtension='.mno',mimeType='text/xml'", "fileExtension='.mny',mimeType='application/x-msmoney'", "fileExtension='.mov',mimeType='video/quicktime'", "fileExtension='.movie',mimeType='video/x-sgi-movie'", "fileExtension='.mp2',mimeType='video/mpeg'", "fileExtension='.mp3',mimeType='audio/mpeg'", "fileExtension='.mp4',mimeType='video/mp4'", "fileExtension='.mp4v',mimeType='video/mp4'", "fileExtension='.mpa',mimeType='video/mpeg'", "fileExtension='.mpe',mimeType='video/mpeg'", "fileExtension='.mpeg',mimeType='video/mpeg'", "fileExtension='.mpg',mimeType='video/mpeg'", "fileExtension='.mpp',mimeType='application/vnd.ms-project'", "fileExtension='.mpv2',mimeType='video/mpeg'", "fileExtension='.ms',mimeType='application/x-troff-ms'", "fileExtension='.msi',mimeType='application/octet-stream'", "fileExtension='.mso',mimeType='application/octet-stream'", "fileExtension='.mvb',mimeType='application/x-msmediaview'", "fileExtension='.mvc',mimeType='application/x-miva-compiled'", "fileExtension='.nc',mimeType='application/x-netcdf'", "fileExtension='.nsc',mimeType='video/x-ms-asf'", "fileExtension='.nws',mimeType='message/rfc822'", "fileExtension='.ocx',mimeType='application/octet-stream'", "fileExtension='.oda',mimeType='application/oda'", "fileExtension='.odc',mimeType='text/x-ms-odc'", "fileExtension='.ods',mimeType='application/oleobject'", "fileExtension='.oga',mimeType='audio/ogg'", "fileExtension='.ogg',mimeType='video/ogg'", "fileExtension='.ogv',mimeType='video/ogg'", "fileExtension='.one',mimeType='application/onenote'", "fileExtension='.onea',mimeType='application/onenote'", "fileExtension='.onetoc',mimeType='application/onenote'", "fileExtension='.onetoc2',mimeType='application/onenote'", "fileExtension='.onetmp',mimeType='application/onenote'", "fileExtension='.onepkg',mimeType='application/onenote'", "fileExtension='.osdx',mimeType='application/opensearchdescription+xml'", "fileExtension='.otf',mimeType='font/otf'", "fileExtension='.p10',mimeType='application/pkcs10'", "fileExtension='.p12',mimeType='application/x-pkcs12'", "fileExtension='.p7b',mimeType='application/x-pkcs7-certificates'", "fileExtension='.p7c',mimeType='application/pkcs7-mime'", "fileExtension='.p7m',mimeType='application/pkcs7-mime'", "fileExtension='.p7r',mimeType='application/x-pkcs7-certreqresp'", "fileExtension='.p7s',mimeType='application/pkcs7-signature'", "fileExtension='.pbm',mimeType='image/x-portable-bitmap'", "fileExtension='.pcx',mimeType='application/octet-stream'", "fileExtension='.pcz',mimeType='application/octet-stream'", "fileExtension='.pdf',mimeType='application/pdf'", "fileExtension='.pfb',mimeType='application/octet-stream'", "fileExtension='.pfm',mimeType='application/octet-stream'", "fileExtension='.pfx',mimeType='application/x-pkcs12'", "fileExtension='.pgm',mimeType='image/x-portable-graymap'", "fileExtension='.pko',mimeType='application/vnd.ms-pki.pko'", "fileExtension='.pma',mimeType='application/x-perfmon'", "fileExtension='.pmc',mimeType='application/x-perfmon'", "fileExtension='.pml',mimeType='application/x-perfmon'", "fileExtension='.pmr',mimeType='application/x-perfmon'", "fileExtension='.pmw',mimeType='application/x-perfmon'", "fileExtension='.png',mimeType='image/png'", "fileExtension='.pnm',mimeType='image/x-portable-anymap'", "fileExtension='.pnz',mimeType='image/png'", "fileExtension='.pot',mimeType='application/vnd.ms-powerpoint'", "fileExtension='.potm',mimeType='application/vnd.ms-powerpoint.template.macroEnabled.12'", "fileExtension='.potx',mimeType='application/vnd.openxmlformats-officedocument.presentationml.template'", "fileExtension='.ppam',mimeType='application/vnd.ms-powerpoint.addin.macroEnabled.12'", "fileExtension='.ppm',mimeType='image/x-portable-pixmap'", "fileExtension='.pps',mimeType='application/vnd.ms-powerpoint'", "fileExtension='.ppsm',mimeType='application/vnd.ms-powerpoint.slideshow.macroEnabled.12'", "fileExtension='.ppsx',mimeType='application/vnd.openxmlformats-officedocument.presentationml.slideshow'", "fileExtension='.ppt',mimeType='application/vnd.ms-powerpoint'", "fileExtension='.pptm',mimeType='application/vnd.ms-powerpoint.presentation.macroEnabled.12'", "fileExtension='.pptx',mimeType='application/vnd.openxmlformats-officedocument.presentationml.presentation'", "fileExtension='.prf',mimeType='application/pics-rules'", "fileExtension='.prm',mimeType='application/octet-stream'", "fileExtension='.prx',mimeType='application/octet-stream'", "fileExtension='.ps',mimeType='application/postscript'", "fileExtension='.psd',mimeType='application/octet-stream'", "fileExtension='.psm',mimeType='application/octet-stream'", "fileExtension='.psp',mimeType='application/octet-stream'", "fileExtension='.pub',mimeType='application/x-mspublisher'", "fileExtension='.qt',mimeType='video/quicktime'", "fileExtension='.qtl',mimeType='application/x-quicktimeplayer'", "fileExtension='.qxd',mimeType='application/octet-stream'", "fileExtension='.ra',mimeType='audio/x-pn-realaudio'", "fileExtension='.ram',mimeType='audio/x-pn-realaudio'", "fileExtension='.rar',mimeType='application/octet-stream'", "fileExtension='.ras',mimeType='image/x-cmu-raster'", "fileExtension='.rf',mimeType='image/vnd.rn-realflash'", "fileExtension='.rgb',mimeType='image/x-rgb'", "fileExtension='.rm',mimeType='application/vnd.rn-realmedia'", "fileExtension='.rmi',mimeType='audio/mid'", "fileExtension='.roff',mimeType='application/x-troff'", "fileExtension='.rpm',mimeType='audio/x-pn-realaudio-plugin'", "fileExtension='.rtf',mimeType='application/rtf'", "fileExtension='.rtx',mimeType='text/richtext'", "fileExtension='.scd',mimeType='application/x-msschedule'", "fileExtension='.sct',mimeType='text/scriptlet'", "fileExtension='.sea',mimeType='application/octet-stream'", "fileExtension='.setpay',mimeType='application/set-payment-initiation'", "fileExtension='.setreg',mimeType='application/set-registration-initiation'", "fileExtension='.sgml',mimeType='text/sgml'", "fileExtension='.sh',mimeType='application/x-sh'", "fileExtension='.shar',mimeType='application/x-shar'", "fileExtension='.sit',mimeType='application/x-stuffit'", "fileExtension='.sldm',mimeType='application/vnd.ms-powerpoint.slide.macroEnabled.12'", "fileExtension='.sldx',mimeType='application/vnd.openxmlformats-officedocument.presentationml.slide'", "fileExtension='.smd',mimeType='audio/x-smd'", "fileExtension='.smi',mimeType='application/octet-stream'", "fileExtension='.smx',mimeType='audio/x-smd'", "fileExtension='.smz',mimeType='audio/x-smd'", "fileExtension='.snd',mimeType='audio/basic'", "fileExtension='.snp',mimeType='application/octet-stream'", "fileExtension='.spc',mimeType='application/x-pkcs7-certificates'", "fileExtension='.spl',mimeType='application/futuresplash'", "fileExtension='.spx',mimeType='audio/ogg'", "fileExtension='.src',mimeType='application/x-wais-source'", "fileExtension='.ssm',mimeType='application/streamingmedia'", "fileExtension='.sst',mimeType='application/vnd.ms-pki.certstore'", "fileExtension='.stl',mimeType='application/vnd.ms-pki.stl'", "fileExtension='.sv4cpio',mimeType='application/x-sv4cpio'", "fileExtension='.sv4crc',mimeType='application/x-sv4crc'", "fileExtension='.svg',mimeType='image/svg+xml'", "fileExtension='.svgz',mimeType='image/svg+xml'", "fileExtension='.swf',mimeType='application/x-shockwave-flash'", "fileExtension='.t',mimeType='application/x-troff'", "fileExtension='.tar',mimeType='application/x-tar'", "fileExtension='.tcl',mimeType='application/x-tcl'", "fileExtension='.tex',mimeType='application/x-tex'", "fileExtension='.texi',mimeType='application/x-texinfo'", "fileExtension='.texinfo',mimeType='application/x-texinfo'", "fileExtension='.tgz',mimeType='application/x-compressed'", "fileExtension='.thmx',mimeType='application/vnd.ms-officetheme'", "fileExtension='.thn',mimeType='application/octet-stream'", "fileExtension='.tif',mimeType='image/tiff'", "fileExtension='.tiff',mimeType='image/tiff'", "fileExtension='.toc',mimeType='application/octet-stream'", "fileExtension='.tr',mimeType='application/x-troff'", "fileExtension='.trm',mimeType='application/x-msterminal'", "fileExtension='.ts',mimeType='video/vnd.dlna.mpeg-tts'", "fileExtension='.tsv',mimeType='text/tab-separated-values'", "fileExtension='.ttf',mimeType='application/octet-stream'", "fileExtension='.tts',mimeType='video/vnd.dlna.mpeg-tts'", "fileExtension='.txt',mimeType='text/plain'", "fileExtension='.u32',mimeType='application/octet-stream'", "fileExtension='.uls',mimeType='text/iuls'", "fileExtension='.ustar',mimeType='application/x-ustar'", "fileExtension='.vbs',mimeType='text/vbscript'", "fileExtension='.vcf',mimeType='text/x-vcard'", "fileExtension='.vcs',mimeType='text/plain'", "fileExtension='.vdx',mimeType='application/vnd.ms-visio.viewer'", "fileExtension='.vml',mimeType='text/xml'", "fileExtension='.vsd',mimeType='application/vnd.visio'", "fileExtension='.vss',mimeType='application/vnd.visio'", "fileExtension='.vst',mimeType='application/vnd.visio'", "fileExtension='.vsto',mimeType='application/x-ms-vsto'", "fileExtension='.vsw',mimeType='application/vnd.visio'", "fileExtension='.vsx',mimeType='application/vnd.visio'", "fileExtension='.vtx',mimeType='application/vnd.visio'", "fileExtension='.wav',mimeType='audio/wav'", "fileExtension='.wax',mimeType='audio/x-ms-wax'", "fileExtension='.wbmp',mimeType='image/vnd.wap.wbmp'", "fileExtension='.wcm',mimeType='application/vnd.ms-works'", "fileExtension='.wdb',mimeType='application/vnd.ms-works'", "fileExtension='.webm',mimeType='video/webm'", "fileExtension='.wks',mimeType='application/vnd.ms-works'", "fileExtension='.wm',mimeType='video/x-ms-wm'", "fileExtension='.wma',mimeType='audio/x-ms-wma'", "fileExtension='.wmd',mimeType='application/x-ms-wmd'", "fileExtension='.wmf',mimeType='application/x-msmetafile'", "fileExtension='.wml',mimeType='text/vnd.wap.wml'", "fileExtension='.wmlc',mimeType='application/vnd.wap.wmlc'", "fileExtension='.wmls',mimeType='text/vnd.wap.wmlscript'", "fileExtension='.wmlsc',mimeType='application/vnd.wap.wmlscriptc'", "fileExtension='.wmp',mimeType='video/x-ms-wmp'", "fileExtension='.wmv',mimeType='video/x-ms-wmv'", "fileExtension='.wmx',mimeType='video/x-ms-wmx'", "fileExtension='.wmz',mimeType='application/x-ms-wmz'", "fileExtension='.woff',mimeType='font/x-woff'", "fileExtension='.wps',mimeType='application/vnd.ms-works'", "fileExtension='.wri',mimeType='application/x-mswrite'", "fileExtension='.wrl',mimeType='x-world/x-vrml'", "fileExtension='.wrz',mimeType='x-world/x-vrml'", "fileExtension='.wsdl',mimeType='text/xml'", "fileExtension='.wtv',mimeType='video/x-ms-wtv'", "fileExtension='.wvx',mimeType='video/x-ms-wvx'", "fileExtension='.x',mimeType='application/directx'", "fileExtension='.xaf',mimeType='x-world/x-vrml'", "fileExtension='.xaml',mimeType='application/xaml+xml'", "fileExtension='.xap',mimeType='application/x-silverlight-app'", "fileExtension='.xbap',mimeType='application/x-ms-xbap'", "fileExtension='.xbm',mimeType='image/x-xbitmap'", "fileExtension='.xdr',mimeType='text/plain'", "fileExtension='.xht',mimeType='application/xhtml+xml'", "fileExtension='.xhtml',mimeType='application/xhtml+xml'", "fileExtension='.xla',mimeType='application/vnd.ms-excel'", "fileExtension='.xlam',mimeType='application/vnd.ms-excel.addin.macroEnabled.12'", "fileExtension='.xlc',mimeType='application/vnd.ms-excel'", "fileExtension='.xlm',mimeType='application/vnd.ms-excel'", "fileExtension='.xls',mimeType='application/vnd.ms-excel'", "fileExtension='.xlsb',mimeType='application/vnd.ms-excel.sheet.binary.macroEnabled.12'", "fileExtension='.xlsm',mimeType='application/vnd.ms-excel.sheet.macroEnabled.12'", "fileExtension='.xlsx',mimeType='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'", "fileExtension='.xlt',mimeType='application/vnd.ms-excel'", "fileExtension='.xltm',mimeType='application/vnd.ms-excel.template.macroEnabled.12'", "fileExtension='.xltx',mimeType='application/vnd.openxmlformats-officedocument.spreadsheetml.template'", "fileExtension='.xlw',mimeType='application/vnd.ms-excel'", "fileExtension='.xml',mimeType='text/xml'", "fileExtension='.xof',mimeType='x-world/x-vrml'", "fileExtension='.xpm',mimeType='image/x-xpixmap'", "fileExtension='.xps',mimeType='application/vnd.ms-xpsdocument'", "fileExtension='.xsd',mimeType='text/xml'", "fileExtension='.xsf',mimeType='text/xml'", "fileExtension='.xsl',mimeType='text/xml'", "fileExtension='.xslt',mimeType='text/xml'", "fileExtension='.xsn',mimeType='application/octet-stream'", "fileExtension='.xtp',mimeType='application/octet-stream'", "fileExtension='.xwd',mimeType='image/x-xwindowdump'", "fileExtension='.z',mimeType='application/x-compress'", "fileExtension='.zip',mimeType='application/x-zip-compressed'"] + ``` + +- `add_default_documents` - The items you want to add to the default document collection, only used during `:add`. Array of strings, default: `[]` + +- `add_mime_maps` - The items you want to add to the mime-map/mime-type collection, only used during `:add`. Array of strings, default: `[]` + +- `delete_default_documents` - The items you want to delete from the default document collection, only used during `:delete`. Array of strings, default: `[]` + +- `delete_mime_maps` - The items you want to delete from the mime-map/mime-type collection, only used during `:delete`. Array of strings, default: `[]` + +#### Examples + +```ruby +# Add foo.html to default documents, and add '.dmg' as mime type extension at root level +iis_root 'add stuff' do + add_default_documents ['foo.html'] + add_mime_maps ["fileExtension='.dmg',mimeType='application/octet-stream'"] + action :add +end +``` + +```ruby +# Remove index.html from default document and .323 as a mime type at root level +iis_root 'delete stuff' do + delete_default_documents ['index.html'] + delete_mime_maps ["fileExtension='.323',mimeType='text/h323'"] + action :delete +end +``` + +### iis_site + +Allows for easy management of IIS virtual sites (ie vhosts). + +#### Actions + +- `:add` - add a new virtual site +- `:config` - apply configuration to an existing virtual site +- `:delete` - delete an existing virtual site +- `:start` - start a virtual site +- `:stop` - stop a virtual site +- `:restart` - restart a virtual site + +#### Properties + +- `site_name` - specify the name of the site. Unless specified we use the name of the resource instead. +- `site_id` - if not given IIS generates a unique ID for the site +- `path` - IIS will create a root application and a root virtual directory mapped to this specified local path +- `protocol` - http protocol type the site should respond to. valid values are :http, :https. default is :http +- `port` - port site will listen on. default is 80 +- `host_header` - host header (also known as domains or host names) the site should map to. default is all host headers +- `bindings` - Advanced options to configure the information required for requests to communicate with a Web site. See for parameter format. When binding is used, port protocol and host_header should not be used. +- `application_pool` - set the application pool of the site +- `options` - additional options to configure the site. Such as `"-logDir"`, `"-limits"`, `"-ftpServer"`, `"-applicationDefaults.preloadEnabled:True"`. This can be anything that you would normally add to a appcmd, so if you want to find out the possible values google "appcmd iis site ". This only runs during `add` since it isn't idempotent. +- `log_directory` - specifies the logging directory, where the log file and logging-related support files are stored. +- `log_period` - specifies how often iis creates a new log file +- `log_truncsize` - specifies the maximum size of the log file (in bytes) after which to create a new log file. + +#### Examples + +```ruby +# stop and delete the default site +iis_site 'Default Web Site' do + action [:stop, :delete] +end +``` + +```ruby +# create and start a new site that maps to +# the physical location C:\inetpub\wwwroot\testfu +# first the physical location must exist +directory "#{node['iis']['docroot']}/testfu" do + action :create +end + +# now create and start the site (note this will use the default application pool which must exist) +iis_site 'Testfu Site' do + protocol :http + port 80 + path "#{node['iis']['docroot']}/testfu" + action [:add,:start] +end +``` + +```ruby +# do the same but map to testfu.chef.io domain +# first the physical location must exist +directory "#{node['iis']['docroot']}/testfu" do + action :create +end + +# now create and start the site (note this will use the default application pool which must exist) +iis_site 'Testfu Site' do + protocol :http + port 80 + path "#{node['iis']['docroot']}/testfu" + host_header "testfu.chef.io" + action [:add,:start] +end +``` + +```ruby +# create and start a new site that maps to +# the physical C:\inetpub\wwwroot\testfu +# first the physical location must exist +directory "#{node['iis']['docroot']}/testfu" do + action :create +end + +# also adds bindings to http and https +# binding http to the ip address 10.12.0.136, +# the port 80, and the host header www.domain.com +# also binding https to any ip address, +# the port 443, and the host header www.domain.com +# now create and start the site (note this will use the default application pool which must exist) +iis_site 'FooBar Site' do + bindings "http/10.12.0.136:80:www.domain.com,https/*:443:www.domain.com + path "#{node['iis']['docroot']}/testfu" + action [:add,:start] +end +``` + +```ruby +# create a site with preloadEnabled enabled +iis_site 'mysite.com' do + protocol :http + port 80 + path "#{node['iis']['docroot']}\dataverify" + application_pool 'dataverify.com' + options "-applicationDefaults.preloadEnabled:True" + action [:add, :start, :config] +end +``` + +### iis_config + +Runs a config command on your IIS instance. + +#### Actions + +- `:set` - Edit configuration section (appcmd set config) +- `:clear` - Clear the section configuration (appcmd clear config) + +#### Properties + +- `cfg_cmd` - name property. What ever command you would pass in after "appcmd.exe set config" We use the resource name if this isn't specified here. + +#### Example + +```ruby +# Sets up logging +iis_config "/section:system.applicationHost/sites /siteDefaults.logfile.directory:\"D:\\logs\"" do + action :set +end +``` + +```ruby +# Increase file upload size for 'MySite' +iis_config "\"MySite\" /section:requestfiltering /requestlimits.maxallowedcontentlength:50000000" do + action :set +end +``` + +```ruby +# Set IUSR username and password authentication +iis_config "\"MyWebsite/aSite\" -section:system.webServer/security/authentication/anonymousAuthentication /enabled:\"True\" /userName:\"IUSR_foobar\" /password:\"p@assword\" /commit:apphost" do + action :set +end +``` + +```ruby +# Authenticate with application pool +iis_config "\"MyWebsite/aSite\" -section:system.webServer/security/authentication/anonymousAuthentication /enabled:\"True\" /userName:\"\" /commit:apphost" do + action :set +end +``` + +```ruby +# Loads an array of commands from the node +cfg_cmds = node['iis']['cfg_cmd'] +cfg_cmds.each do |cmd| + iis_config "#{cmd}" do + action :set + end +end +``` + +```ruby +# Add static machine key at site level +iis_config "MySite /commit:site /section:machineKey /validation:AES /validationKey:AAAAAA /decryptionKey:ZZZZZ" do + action :set +end +``` + +```ruby +# Remove machine key +iis_config "MySite /commit:site /section:machineKey" do + action :clear +end +``` + +### iis_config_property + +Sets an IIS configuration property. Idempotent. Uses Powershell [Set-WebConfigurationProperty](https://technet.microsoft.com/en-us/library/ee807821.aspx) rather than appcmd. + +#### Actions + +- `:set` : Sets the property to the given value if it is not already set. +- `:add` : Adds an item to a collection if one doesn't already exist. `filter` should define a collection element. An item will be added if there is no member with a `property` value of `value`. +- `:remove` : Removes a item from a collection if it already exists. `filter` should define a collection element. The item will be removed if there is a member with a `property` value of `value`. + +#### Properties + +- `property` : The property to be set. Defaults from name. +- `ps_path` : Specifies the configuration path. This can be either an IIS configuration path in the format `computer name/webroot/apphost`, or the IIS module path in this format `IIS:\sites\Default Web Site`. +- `location` : Optional. The location of the configuration setting. Location tags are frequently used for configuration settings that must be set more precisely than per application or per virtual directory. For example, a setting for a particular file or directory could use a location tag. Location tags are also used if a particular section is locked. In such an instance, the configuration system would have to use a location tag in one of the parent configuration files. +- `filter` : Specifies the IIS configuration section or an XPath query that returns a configuration element. +- `value` : The value to set the property to. Either a string or an integer. +- `extra_add_values` : Optional. If the `add` action requires additional values to be set at creation then supply them in this hash. This property is not idempotent. It is only used when the configuration is created. + +#### Example + +```ruby +# Sets up logging +iis_config_property 'directory' do + ps_path 'MACHINE/WEBROOT/APPHOST' + filter 'system.applicationHost/sites/siteDefaults/logfile' + value 'D:\\logs' +end +``` + +```ruby +# Set XSS-Protection header on all sites +iis_config_property 'Add X-Xss-Protection' do + ps_path 'MACHINE/WEBROOT/APPHOST' + filter 'system.webServer/httpProtocol/customHeaders' + property 'name' + value 'X-Xss-Protection' + action :add +end +iis_config_property 'Set X-Xss-Protection' do + ps_path 'MACHINE/WEBROOT/APPHOST' + filter "system.webServer/httpProtocol/customHeaders/add[@name='X-Xss-Protection']" + property 'value' + value '1; mode=block' +end +``` + +```ruby +# Set environment variable ASPNETCORE_ENVIRONMENT to Test +# Note we still need to maintain the value via a Set resource +iis_config_property 'Add login/ASPNETCORE_ENVIRONMENT' do + ps_path 'MACHINE/WEBROOT/APPHOST' + location 'Default Web site' + filter 'system.webServer/aspNetCore/environmentVariables' + property 'name' + value 'ASPNETCORE_ENVIRONMENT' + extra_add_values value: 'Test' + action :add +end +iis_config_property 'Set login/ASPNETCORE_ENVIRONMENT' do + ps_path 'MACHINE/WEBROOT/APPHOST' + location 'Default Web site' + filter "system.webServer/aspNetCore/environmentVariables/environmentVariable[@name='ASPNETCORE_ENVIRONMENT']" + property 'value' + value 'Test' +end +``` + +## iis_manager + +Configures the IIS Manager service + +#### Actions + +- `:config` - Change the configuration of the service. Restarts as necessary and sets the service to be automatic and running. + + +#### Properties + +- `port` : The port the service listens on. Default is 8172 +- `enable_remote_management` : If remote access allowed. Default `true` +- `log_directory` : Optional. The directory to write log files to. + +#### Example + +```ruby +iis_manager 'IIS Manager' do + port 9090 + enable_remote_management true + log_directory "C:\\CustomPath" +end +``` + +## iis_manager_permission + +Requires: Server 2016+ + +Set the permissions for user access to the IIS Manager + +#### Actions + +- `config` : Configure the given path to allow only the defined users and groups access. Removes any other principals. This is an idempotent action. + + +#### Properties + +- `config_path` : The IIS Manager path to be configured. Usually just the site name. Taken from the `name` attribute if not set, The config_path takes the form of _site_name_/_application_/_application_ (where applications are optional) +- `users` : Optional. Array of users to be allowed access +- `groups` : Optional. Array of groups to be allowed access + + + +### iis_pool + +Creates an application pool in IIS. + +#### Actions + +- `:add` - add a new application pool +- `:config` - apply configuration to an existing application pool +- `:delete` - delete an existing application pool +- `:start` - start a application pool +- `:stop` - stop a application pool +- `:restart` - restart a application pool +- `:recycle` - recycle an application pool + +#### Properties + +##### Root Items + +- `pool_name` - name property. Specifies the name of the pool to create. We use the resource name if this isn't specified here. +- `runtime_version` - specifies what .NET version of the runtime to use. +- `pipeline_mode` - specifies what pipeline mode to create the pool with, valid values are :Integrated or :Classic, the default is :Integrated +- `no_managed_code` - allow Unmanaged Code in setting up IIS app pools is shutting down. - default is true - optional + +##### Add Items + +- `start_mode` - Specifies the startup type for the application pool - default :OnDemand (:OnDemand, :AlwaysRunning) - optional +- `auto_start` - When true, indicates to the World Wide Web Publishing Service (W3SVC) that the application pool should be automatically started when it is created or when IIS is started. - boolean: default true - optional +- `queue_length` - Indicates to HTTP.sys how many requests to queue for an application pool before rejecting future requests. - default is 1000 - optional +- `thirty_two_bit` - set the pool to run in 32 bit mode, valid values are true or false, default is false - optional + +##### Process Model Items + +- `max_processes` - specifies the number of worker processes associated with the pool. +- `load_user_profile` - This property is used only when a service starts in a named user account. - Default is false - optional +- `identity_type` - the account identity that they app pool will run as, valid values are :SpecificUser, :NetworkService, :LocalService, :LocalSystem, :ApplicationPoolIdentity +- `username` - username for the identity for the application pool +- `password` password for the identity for the application pool is started. Default is true - optional +- `logon_type` - Specifies the logon type for the process identity. (For additional information about [logon types](http://msdn.microsoft.com/en-us/library/aa378184%28VS.85%29.aspx), see the LogonUser Function topic on Microsoft's MSDN Web site.) - Available [:LogonBatch, :LogonService] - default is :LogonBatch - optional +- `manual_group_membership` - Specifies whether the IIS_IUSRS group Security Identifier (SID) is added to the worker process token. When false, IIS automatically uses an application pool identity as though it were a member of the built-in IIS_IUSRS group, which has access to necessary file and system resources. When true, an application pool identity must be explicitly added to all resources that a worker process requires at runtime. - default is false - optional +- `idle_timeout` - Specifies how long (in minutes) a worker process should run idle if no new requests are received and the worker process is not processing requests. After the allocated time passes, the worker process should request that it be shut down by the WWW service. - default is '00:20:00' - optional +- `idle_timeout_action` - Specifies the option of suspending an idle worker process rather than terminating it. Valid values are :Terminate and :Suspend - optional +- `shutdown_time_limit` - Specifies the time that the W3SVC service waits after it initiated a recycle. If the worker process does not shut down within the shutdownTimeLimit, it will be terminated by the W3SVC service. - default is '00:01:30' - optional +- `startup_time_limit` - Specifies the time that IIS waits for an application pool to start. If the application pool does not startup within the startupTimeLimit, the worker process is terminated and the rapid-fail protection count is incremented. - default is '00:01:30' - optional +- `pinging_enabled` - Specifies whether pinging is enabled for the worker process. - default is true - optional +- `ping_interval` - Specifies the time between health-monitoring pings that the WWW service sends to a worker process - default is '00:00:30' - optional +- `ping_response_time` - Specifies the time that a worker process is given to respond to a health-monitoring ping. After the time limit is exceeded, the WWW service terminates the worker process - default is '00:01:30' - optional + +##### Recycling Items + +- `disallow_rotation_on_config_change` - The DisallowRotationOnConfigChange property specifies whether or not the World Wide Web Publishing Service (WWW Service) should rotate worker processes in an application pool when the configuration has changed. - Default is false - optional +- `disallow_overlapping_rotation` - Specifies whether the WWW Service should start another worker process to replace the existing worker process while that process +- `log_event_on_recycle` - configure IIS to log an event when one or more of the following configured events cause an application pool to recycle (for additional information about [logging events] (). - default is 'Time, Requests, Schedule, Memory, IsapiUnhealthy, OnDemand, ConfigChange, PrivateMemory' - optional +- `recycle_schedule_clear` - specifies a pool to clear all scheduled recycle times, [true,false] Default is false - optional +- `recycle_after_time` - specifies a pool to recycle at regular time intervals, d.hh:mm:ss, d optional +- `periodic_restart_schedule` - schedule a pool to recycle at specific times. Single value or array accepted. `hh:mm:ss` or `['hh:mm:ss','hh:mm:ss']`, optional +- `private_memory` - specifies the amount of private memory (in kilobytes) after which you want the pool to recycle +- `virtual_memory` - specifies the amount of virtual memory (in kilobytes) after which you want the pool to recycle + +#### Failure Items + +- `load_balancer_capabilities` - Specifies behavior when a worker process cannot be started, such as when the request queue is full or an application pool is in rapid-fail protection. - default is :HttpLevel - optional +- `orphan_worker_process` - Specifies whether to assign a worker process to an orphan state instead of terminating it when an application pool fails. - default is false - optional +- `orphan_action_exe` - Specifies an executable to run when the WWW service orphans a worker process (if the orphanWorkerProcess attribute is set to true). You can use the orphanActionParams attribute to send parameters to the executable. - optional +- `orphan_action_params` - Indicates command-line parameters for the executable named by the orphanActionExe attribute. To specify the process ID of the orphaned process, use %1%. - optional +- `rapid_fail_protection` - Setting to true instructs the WWW service to remove from service all applications that are in an application pool - default is true - optional +- `rapid_fail_protection_interval` - Specifies the number of minutes before the failure count for a process is reset. - default is '00:05:00' - optional +- `rapid_fail_protection_max_crashes` - Specifies the maximum number of failures that are allowed within the number of minutes specified by the rapidFailProtectionInterval attribute. - default is 5 - optional +- `auto_shutdown_exe` - Specifies an executable to run when the WWW service shuts down an application pool. - optional +- `auto_shutdown_params` - Specifies command-line parameters for the executable that is specified in the autoShutdownExe attribute. - optional + +##### CPU Items + +- `cpu_action` - Configures the action that IIS takes when a worker process exceeds its configured CPU limit. The action attribute is configured on a per-application pool basis. - Available options [:NoAction, :KillW3wp, :Throttle, :ThrottleUnderLoad] - default is :NoAction - optional +- `cpu_limit` - Configures the maximum percentage of CPU time (in 1/1000ths of one percent) that the worker processes in an application pool are allowed to consume over a period of time as indicated by the resetInterval attribute. If the limit set by the limit attribute is exceeded, an event is written to the event log and an optional set of events can be triggered. These optional events are determined by the action attribute. - default is 0 - optional +- `cpu_reset_interval` - Specifies the reset period (in minutes) for CPU monitoring and throttling limits on an application pool. When the number of minutes elapsed since the last process accounting reset equals the number specified by this property, IIS resets the CPU timers for both the logging and limit intervals. - default is '00:05:00' - optional +- `cpu_smp_affinitized` - Specifies whether a particular worker process assigned to an application pool should also be assigned to a given CPU. - default is false - optional +- `smp_processor_affinity_mask` - Specifies the hexadecimal processor mask for multi-processor computers, which indicates to which CPU the worker processes in an application pool should be bound. Before this property takes effect, the smpAffinitized attribute must be set to true for the application pool. - default is 4294967295 - optional +- `smp_processor_affinity_mask_2` - Specifies the high-order DWORD hexadecimal processor mask for 64-bit multi-processor computers, which indicates to which CPU the worker processes in an application pool should be bound. Before this property takes effect, the smpAffinitized attribute must be set to true for the application pool. - default is 4294967295 - optional + +##### Environment Variables +- `environment_variables` - Specifies a list of environment variables that will be passed to a worker process when an application is launched. Single value or array accepted. `FOO=BAR` or `['FOO=BAR','HELLO=WORLD']`, optional + +#### Example + +```ruby +# creates a new app pool +iis_pool 'myAppPool_v1_1' do + runtime_version "2.0" + pipeline_mode :Classic + action :add +end +``` + +### iis_app + +Creates an application in IIS. + +#### Actions + +- `:add` - add a new application pool +- `:delete` - delete an existing application pool +- `:config` - configures an existing application pool + +#### Properties + +- `site_name` - name property. The name of the site to add this app to. We use the resource name if this isn't specified here. +- `path` -The virtual path for this application +- `application_pool` - The pool this application belongs to +- `physical_path` - The physical path where this app resides. +- `enabled_protocols` - The enabled protocols that this app provides (http, https, net.pipe, net.tcp, etc) + +#### Example + +```ruby +# creates a new app +iis_app 'myApp' do + path '/v1_1' + application_pool 'myAppPool_v1_1' + physical_path "#{node['iis']['docroot']}/testfu/v1_1" + enabled_protocols 'http,net.pipe' + action :add +end +``` + +### iis_vdir + +Allows easy management of IIS virtual directories (i.e. vdirs). + +#### Actions + +- :add: - add a new virtual directory +- :delete: - delete an existing virtual directory +- :config: - configure a virtual directory + +#### Properties + +- `application_name`: name property. This is the name of the website or site + application you are adding it to. We use the resource name if this isn't specified here. +- `path`: The virtual directory path on the site. +- `physical_path`: The physical path of the virtual directory on the disk. +- `username`: (optional) The username required to logon to the physical_path. If set to "" will clear username and password. +- `password`: (optional) The password required to logon to the physical_path +- `logon_method`: (optional, default: :ClearText) The method used to logon (:Interactive, :Batch, :Network, :ClearText). For more information on these types, see "LogonUser Function", Read more at [MSDN](http://msdn2.microsoft.com/en-us/library/aa378184.aspx) +- `allow_sub_dir_config`: (optional, default: true) Boolean that specifies whether or not the Web server will look for configuration files located in the subdirectories of this virtual directory. Setting this to false can improve performance on servers with very large numbers of web.config files, but doing so prevents IIS configuration from being read in subdirectories. + +#### Examples + +```ruby +# add a virtual directory to default application +iis_vdir 'Default Web Site/' do + action :add + path '/Content/Test' + physical_path 'C:\wwwroot\shared\test' +end +``` + +```ruby +# add a virtual directory to an application under a site +iis_vdir 'Default Web Site/my application' do + action :add + path '/Content/Test' + physical_path 'C:\wwwroot\shared\test' +end +``` + +```ruby +# adds a virtual directory to default application which points to a smb share. (Remember to escape the "\"'s) +iis_vdir 'Default Web Site/' do + action :add + path '/Content/Test' + physical_path '\\\\sharename\\sharefolder\\1' +end +``` + +```ruby +# configure a virtual directory to have a username and password +iis_vdir 'Default Web Site/' do + action :config + path '/Content/Test' + username 'domain\myspecialuser' + password 'myspecialpassword' +end +``` + +```ruby +# delete a virtual directory from the default application +iis_vdir 'Default Web Site/' do + action :delete + path '/Content/Test' +end +``` + +### iis_section + +Allows for the locking/unlocking of sections ([listed here](http://www.iis.net/configreference) or via the command `appcmd list config \"\" /config:* /xml`) + +This is valuable to allow the `web.config` of an individual application/website control it's own settings. + +#### Actions + +- `:lock`: - locks the `section` passed +- `:unlock`: - unlocks the `section` passed + +#### Properties + +- `section`: The name of the section to lock. +- `site`: The name of the site you want to lock or unlock a section for. +- `application_path`: The path to the application you want to lock or unlock a section for. +- `returns`: The result of the `shell_out` command. + +#### Examples + +```ruby +# Sets the IIS global windows authentication to be locked globally +iis_section 'locks global configuration of windows auth' do + section 'system.webServer/security/authentication/windowsAuthentication' + action :lock +end +``` + +```ruby +# Sets the IIS global Basic authentication to be locked globally +iis_section 'locks global configuration of Basic auth' do + section 'system.webServer/security/authentication/basicAuthentication' + action :lock +end +``` + +```ruby +# Sets the IIS global windows authentication to be unlocked globally +iis_section 'unlocked web.config globally for windows auth' do + action :unlock + section 'system.webServer/security/authentication/windowsAuthentication' +end +``` + +```ruby +# Sets the IIS global Basic authentication to be unlocked globally +iis_section 'unlocked web.config globally for Basic auth' do + action :unlock + section 'system.webServer/security/authentication/basicAuthentication' +end +``` + +```ruby +# Sets the static content section for default web site and root to unlocked +iis_section 'unlock staticContent of default web site' do + section 'system.webServer/staticContent' + site 'Default Web Site' + action :unlock +end +``` + +```ruby +# Sets the static content section for test_app under default website and root to be unlocked +iis_section 'unlock staticContent of default web site' do + section 'system.webServer/staticContent' + site 'Default Web Site' + application_path '/test_app' + action :unlock +end +``` + +### iis_module + +Manages modules globally or on a per site basis. + +#### Actions + +- `:add` - add a new module +- `:delete` - delete a module +- `:install` - install a native module from the filesystem (.dll) +- `:uninstall` - uninstall a native module + +#### Properties + +- `module_name` - The name of the module to add or delete +- `type` - The type of module +- `precondition` - precondition for module +- `application` - The application or site to add the module to +- `add` - Whether the module you install has to be globally added +- `image` - Location of the DLL of the module to install + +#### Example + +```ruby +# Adds a module called "My 3rd Party Module" to mySite/ +iis_module "My 3rd Party Module" do + application "mySite/" + precondition "bitness64" + action :add +end +``` + +```ruby +# Adds a module called "MyModule" to all IIS sites on the server +iis_module "MyModule" +``` + +## Usage + +### default recipe + +Installs and configures IIS 7.0/7.5/8.0 using the default configuration. + +### mod_* recipes + +This cookbook also contains recipes for installing individual IIS modules (extensions). These recipes can be included in a node's run_list to build the minimal desired custom IIS installation. + +- `mod_aspnet` - installs ASP.NET runtime components +- `mod_aspnet45` - installs ASP.NET 4.5 runtime components +- `mod_auth_basic` - installs Basic Authentication support +- `mod_auth_windows` - installs Windows Authentication (authenticate clients by using NTLM or Kerberos) support +- `mod_compress_dynamic` - installs dynamic content compression support. _PLEASE NOTE_ - enabling dynamic compression always gives you more efficient use of bandwidth, but if your server's processor utilization is already very high, the CPU load imposed by dynamic compression might make your site perform more slowly. +- `mod_compress_static` - installs static content compression support +- `mod_ftp` - installs FTP service +- `mod_iis6_metabase_compat` - installs IIS 6 Metabase Compatibility component. +- `mod_isapi` - installs ISAPI (Internet Server Application Programming Interface) extension and filter support. +- `mod_logging` - installs and enables HTTP Logging (logging of Web site activity), Logging Tools (logging tools and scripts) and Custom Logging (log any of the HTTP request/response headers, IIS server variables, and client-side fields with simple configuration) support +- `mod_management` - installs Web server Management Console which supports management of local and remote Web servers +- `mod_security` - installs URL Authorization (Authorizes client access to the URLs that comprise a Web application), Request Filtering (configures rules to block selected client requests) and IP Security (allows or denies content access based on IP address or domain name) support. +- `mod_tracing` - installs support for tracing ASP.NET applications and failed requests. + +Note: Not every possible IIS module has a corresponding recipe. The foregoing recipes are included for convenience, but users may also place additional IIS modules that are installable as Windows features into the `node['iis']['components']` array. + +## Alternative Cookbooks + +- [Powershell based IIS Cookbook (Pre-DSC)](https://github.com/ebsco/iisposh) +- DSC Based- [CWebAdministration](https://github.com/PowerShellOrg/cWebAdministration) / [XWebadministration](https://github.com/PowerShell/xWebAdministration) Powershell Module(s) + +## License and Author + +- Author:: Seth Chisamore ([schisamo@chef.io](mailto:schisamo@chef.io)) +- Author:: Julian Dunn ([jdunn@chef.io](mailto:jdunn@chef.io)) +- Author:: Justin Schuhmann ([jmschu02@gmail.com](mailto:jmschu02@gmail.com)) + +```text +Copyright 2011-2016, 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. +``` diff --git a/cookbooks/iis/TESTING.md b/cookbooks/iis/TESTING.md new file mode 100644 index 00000000..ca524abe --- /dev/null +++ b/cookbooks/iis/TESTING.md @@ -0,0 +1,2 @@ +Please refer to +https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/TESTING.MD diff --git a/cookbooks/iis/appveyor.yml b/cookbooks/iis/appveyor.yml new file mode 100644 index 00000000..93040981 --- /dev/null +++ b/cookbooks/iis/appveyor.yml @@ -0,0 +1,38 @@ +environment: + machine_user: vagrant + machine_pass: vagrant + KITCHEN_YAML: kitchen.appveyor.yml + CHEF_LICENSE: accept + +branches: + only: + - master + +# Do not build on tags (GitHub only) +skip_tags: true + +#faster cloning +clone_depth: 1 + +# Install the latest nightly of ChefDK +install: + - ps: (& cmd /c); iex (irm https://omnitruck.chef.io/install.ps1); Install-Project -Project chefdk -channel stable + - ps: 'Get-CimInstance win32_operatingsystem -Property Caption, OSArchitecture, Version | fl Caption, OSArchitecture, Version' + - ps: $PSVersionTable + - c:\opscode\chefdk\bin\chef.bat exec ruby --version + - ps: secedit /export /cfg $env:temp/export.cfg + - ps: ((get-content $env:temp/export.cfg) -replace ('PasswordComplexity = 1', 'PasswordComplexity = 0')) | Out-File $env:temp/export.cfg + - ps: ((get-content $env:temp/export.cfg) -replace ('MinimumPasswordLength = 8', 'MinimumPasswordLength = 0')) | Out-File $env:temp/export.cfg + - ps: secedit /configure /db $env:windir/security/new.sdb /cfg $env:temp/export.cfg /areas SECURITYPOLICY + - ps: net user /add $env:machine_user $env:machine_pass + - ps: net localgroup administrators $env:machine_user /add + +build_script: + - ps: c:\opscode\chefdk\bin\chef.bat shell-init powershell | iex; cmd /c c:\opscode\chefdk\bin\chef.bat --version + +test_script: + - c:\opscode\chefdk\bin\cookstyle --version + - c:\opscode\chefdk\bin\chef.bat exec delivery local all + - c:\opscode\chefdk\bin\chef.bat exec kitchen verify + +deploy: off diff --git a/cookbooks/iis/attributes/default.rb b/cookbooks/iis/attributes/default.rb new file mode 100644 index 00000000..aa2e948d --- /dev/null +++ b/cookbooks/iis/attributes/default.rb @@ -0,0 +1,29 @@ +# +# Cookbook:: iis +# Attribute:: default +# +# Copyright:: 2011-2019, 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. +# + +default['iis']['home'] = "#{ENV['WINDIR']}\\System32\\inetsrv" +default['iis']['conf_dir'] = "#{ENV['WINDIR']}\\System32\\inetsrv\\config" +default['iis']['pubroot'] = "#{ENV['SYSTEMDRIVE']}\\inetpub" +default['iis']['docroot'] = "#{ENV['SYSTEMDRIVE']}\\inetpub\\wwwroot" +default['iis']['cache_dir'] = "#{ENV['SYSTEMDRIVE']}\\inetpub\\temp" +default['iis']['components'] = [] + +default['iis']['source'] = nil + +default['iis']['recycle']['log_events'] = 'Time, Requests, Schedule, Memory, IsapiUnhealthy, OnDemand, ConfigChange, PrivateMemory' diff --git a/cookbooks/iis/chefignore b/cookbooks/iis/chefignore new file mode 100644 index 00000000..b2065c33 --- /dev/null +++ b/cookbooks/iis/chefignore @@ -0,0 +1,93 @@ +# Put files/directories that should be ignored in this file when uploading +# to a chef-server or supermarket. +# Lines that start with '# ' are comments. + +# OS generated files # +###################### +.DS_Store +Icon? +nohup.out +ehthumbs.db +Thumbs.db + +# SASS # +######## +.sass-cache + +# EDITORS # +########### +\#* +.#* +*~ +*.sw[a-z] +*.bak +REVISION +TAGS* +tmtags +*_flymake.* +*_flymake +*.tmproj +.project +.settings +mkmf.log + +## COMPILED ## +############## +a.out +*.o +*.pyc +*.so +*.com +*.class +*.dll +*.exe +*/rdoc/ + +# Testing # +########### +.rspec +spec/* +spec/fixtures/* +test/* +features/* +examples/* +Procfile +kitchen* +.kitchen* +.rubocop.yml +spec/* +.travis.yml +.foodcritic +appveyor.yml + +# SCM # +####### +.git +*/.git +.gitignore +.gitmodules +.gitconfig +.gitattributes +.svn +*/.bzr/* +*/.hg/* +*/.svn/* + +# Berkshelf # +############# +Berksfile +Berksfile.lock +cookbooks/* +tmp + +# Policyfile # +############## +Policyfile.rb +Policyfile.lock.json + +# Cookbooks # +############# +CONTRIBUTING* +CHANGELOG* +TESTING* + diff --git a/cookbooks/iis/kitchen.appveyor.yml b/cookbooks/iis/kitchen.appveyor.yml new file mode 100644 index 00000000..abef846e --- /dev/null +++ b/cookbooks/iis/kitchen.appveyor.yml @@ -0,0 +1,54 @@ +--- +driver: + name: proxy + host: localhost + reset_command: "exit 0" + port: 5985 + username: <%= ENV["machine_user"] %> + password: <%= ENV["machine_pass"] %> + +transport: + name: winrm + elevated: true + +provisioner: + name: chef_zero + deprecations_as_errors: true + product_name: chef + channel: stable + chef_license: accept + +platforms: + - name: windows-2012R2 + +verifier: + name: inspec + +suites: + - name: app + run_list: + - recipe[test::app] + - name: config_property + run_list: + - recipe[test::config_property] + - name: manager + run_list: + - recipe[test::manager] + - name: module + run_list: + - recipe[test::module] + - name: pool + run_list: + - recipe[test::pool] + - name: root + run_list: + - recipe[test::root] + - name: section + run_list: + - recipe[test::section] + - name: site + run_list: + - recipe[test::site] + - name: vdir + run_list: + - recipe[test::vdir] diff --git a/cookbooks/iis/kitchen.yml b/cookbooks/iis/kitchen.yml new file mode 100644 index 00000000..b4ed9df7 --- /dev/null +++ b/cookbooks/iis/kitchen.yml @@ -0,0 +1,72 @@ +driver: + name: vagrant + customize: + cpus: 2 + memory: 4096 + +transport: + name: winrm + elevated: true + +provisioner: + name: chef_zero + deprecations_as_errors: true + product_name: chef + channel: stable + chef_license: accept + +verifier: + name: inspec + +platforms: + - name: windows-2008r2 + driver_config: + box: tas50/windows_2008r2 + - name: windows-2012r2 + driver_config: + box: tas50/windows_2012r2 + - name: windows-2016-chef-12 + driver_config: + box: tas50/windows_2016 + provisioner: + require_chef_omnibus: 12.14.89 + +suites: + - name: default + run_list: + - recipe[iis::default] + - name: disable_default + run_list: + - recipe[iis::default] + - recipe[iis::remove_default_site] + - name: app + run_list: + - recipe[test::app] + - name: config_property + run_list: + - recipe[test::config_property] + - name: manager + run_list: + - recipe[test::manager] + - name: manager_permission + run_list: + - recipe[test::manager_permission] + excludes: ["windows-2008r2", "windows-2012r2"] + - name: module + run_list: + - recipe[test::module] + - name: pool + run_list: + - recipe[test::pool] + - name: root + run_list: + - recipe[test::root] + - name: section + run_list: + - recipe[test::section] + - name: site + run_list: + - recipe[test::site] + - name: vdir + run_list: + - recipe[test::vdir] diff --git a/cookbooks/iis/libraries/constants.rb b/cookbooks/iis/libraries/constants.rb new file mode 100644 index 00000000..0257b827 --- /dev/null +++ b/cookbooks/iis/libraries/constants.rb @@ -0,0 +1,410 @@ +# +# Cookbook:: iis +# Library:: constants +# +# Copyright:: 2013-2019, 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. +# + +module IISCookbook + # Contains functions that are used throughout this cookbook + module Constants + def self.default_documents + %w( + Default.htm + Default.asp + index.htm + index.html + iisstart.htm + default.aspx + ) + end + + def self.default_mime_types + %w( + fileExtension='.323',mimeType='text/h323' + fileExtension='.3g2',mimeType='video/3gpp2' + fileExtension='.3gp2',mimeType='video/3gpp2' + fileExtension='.3gp',mimeType='video/3gpp' + fileExtension='.3gpp',mimeType='video/3gpp' + fileExtension='.aaf',mimeType='application/octet-stream' + fileExtension='.aac',mimeType='audio/aac' + fileExtension='.aca',mimeType='application/octet-stream' + fileExtension='.accdb',mimeType='application/msaccess' + fileExtension='.accde',mimeType='application/msaccess' + fileExtension='.accdt',mimeType='application/msaccess' + fileExtension='.acx',mimeType='application/internet-property-stream' + fileExtension='.adt',mimeType='audio/vnd.dlna.adts' + fileExtension='.adts',mimeType='audio/vnd.dlna.adts' + fileExtension='.afm',mimeType='application/octet-stream' + fileExtension='.ai',mimeType='application/postscript' + fileExtension='.aif',mimeType='audio/x-aiff' + fileExtension='.aifc',mimeType='audio/aiff' + fileExtension='.aiff',mimeType='audio/aiff' + fileExtension='.application',mimeType='application/x-ms-application' + fileExtension='.art',mimeType='image/x-jg' + fileExtension='.asd',mimeType='application/octet-stream' + fileExtension='.asf',mimeType='video/x-ms-asf' + fileExtension='.asi',mimeType='application/octet-stream' + fileExtension='.asm',mimeType='text/plain' + fileExtension='.asr',mimeType='video/x-ms-asf' + fileExtension='.asx',mimeType='video/x-ms-asf' + fileExtension='.atom',mimeType='application/atom+xml' + fileExtension='.au',mimeType='audio/basic' + fileExtension='.avi',mimeType='video/avi' + fileExtension='.axs',mimeType='application/olescript' + fileExtension='.bas',mimeType='text/plain' + fileExtension='.bcpio',mimeType='application/x-bcpio' + fileExtension='.bin',mimeType='application/octet-stream' + fileExtension='.bmp',mimeType='image/bmp' + fileExtension='.c',mimeType='text/plain' + fileExtension='.cab',mimeType='application/vnd.ms-cab-compressed' + fileExtension='.calx',mimeType='application/vnd.ms-office.calx' + fileExtension='.cat',mimeType='application/vnd.ms-pki.seccat' + fileExtension='.cdf',mimeType='application/x-cdf' + fileExtension='.chm',mimeType='application/octet-stream' + fileExtension='.class',mimeType='application/x-java-applet' + fileExtension='.clp',mimeType='application/x-msclip' + fileExtension='.cmx',mimeType='image/x-cmx' + fileExtension='.cnf',mimeType='text/plain' + fileExtension='.cod',mimeType='image/cis-cod' + fileExtension='.cpio',mimeType='application/x-cpio' + fileExtension='.cpp',mimeType='text/plain' + fileExtension='.crd',mimeType='application/x-mscardfile' + fileExtension='.crl',mimeType='application/pkix-crl' + fileExtension='.crt',mimeType='application/x-x509-ca-cert' + fileExtension='.csh',mimeType='application/x-csh' + fileExtension='.css',mimeType='text/css' + fileExtension='.csv',mimeType='application/octet-stream' + fileExtension='.cur',mimeType='application/octet-stream' + fileExtension='.dcr',mimeType='application/x-director' + fileExtension='.deploy',mimeType='application/octet-stream' + fileExtension='.der',mimeType='application/x-x509-ca-cert' + fileExtension='.dib',mimeType='image/bmp' + fileExtension='.dir',mimeType='application/x-director' + fileExtension='.disco',mimeType='text/xml' + fileExtension='.dll',mimeType='application/x-msdownload' + fileExtension='.dll.config',mimeType='text/xml' + fileExtension='.dlm',mimeType='text/dlm' + fileExtension='.doc',mimeType='application/msword' + fileExtension='.docm',mimeType='application/vnd.ms-word.document.macroEnabled.12' + fileExtension='.docx',mimeType='application/vnd.openxmlformats-officedocument.wordprocessingml.document' + fileExtension='.dot',mimeType='application/msword' + fileExtension='.dotm',mimeType='application/vnd.ms-word.template.macroEnabled.12' + fileExtension='.dotx',mimeType='application/vnd.openxmlformats-officedocument.wordprocessingml.template' + fileExtension='.dsp',mimeType='application/octet-stream' + fileExtension='.dtd',mimeType='text/xml' + fileExtension='.dvi',mimeType='application/x-dvi' + fileExtension='.dvr-ms',mimeType='video/x-ms-dvr' + fileExtension='.dwf',mimeType='drawing/x-dwf' + fileExtension='.dwp',mimeType='application/octet-stream' + fileExtension='.dxr',mimeType='application/x-director' + fileExtension='.eml',mimeType='message/rfc822' + fileExtension='.emz',mimeType='application/octet-stream' + fileExtension='.eot',mimeType='application/vnd.ms-fontobject' + fileExtension='.eps',mimeType='application/postscript' + fileExtension='.etx',mimeType='text/x-setext' + fileExtension='.evy',mimeType='application/envoy' + fileExtension='.exe',mimeType='application/octet-stream' + fileExtension='.exe.config',mimeType='text/xml' + fileExtension='.fdf',mimeType='application/vnd.fdf' + fileExtension='.fif',mimeType='application/fractals' + fileExtension='.fla',mimeType='application/octet-stream' + fileExtension='.flr',mimeType='x-world/x-vrml' + fileExtension='.flv',mimeType='video/x-flv' + fileExtension='.gif',mimeType='image/gif' + fileExtension='.gtar',mimeType='application/x-gtar' + fileExtension='.gz',mimeType='application/x-gzip' + fileExtension='.h',mimeType='text/plain' + fileExtension='.hdf',mimeType='application/x-hdf' + fileExtension='.hdml',mimeType='text/x-hdml' + fileExtension='.hhc',mimeType='application/x-oleobject' + fileExtension='.hhk',mimeType='application/octet-stream' + fileExtension='.hhp',mimeType='application/octet-stream' + fileExtension='.hlp',mimeType='application/winhlp' + fileExtension='.hqx',mimeType='application/mac-binhex40' + fileExtension='.hta',mimeType='application/hta' + fileExtension='.htc',mimeType='text/x-component' + fileExtension='.htm',mimeType='text/html' + fileExtension='.html',mimeType='text/html' + fileExtension='.htt',mimeType='text/webviewhtml' + fileExtension='.hxt',mimeType='text/html' + fileExtension='.ico',mimeType='image/x-icon' + fileExtension='.ics',mimeType='text/calendar' + fileExtension='.ief',mimeType='image/ief' + fileExtension='.iii',mimeType='application/x-iphone' + fileExtension='.inf',mimeType='application/octet-stream' + fileExtension='.ins',mimeType='application/x-internet-signup' + fileExtension='.isp',mimeType='application/x-internet-signup' + fileExtension='.IVF',mimeType='video/x-ivf' + fileExtension='.jar',mimeType='application/java-archive' + fileExtension='.java',mimeType='application/octet-stream' + fileExtension='.jck',mimeType='application/liquidmotion' + fileExtension='.jcz',mimeType='application/liquidmotion' + fileExtension='.jfif',mimeType='image/pjpeg' + fileExtension='.jpb',mimeType='application/octet-stream' + fileExtension='.jpe',mimeType='image/jpeg' + fileExtension='.jpeg',mimeType='image/jpeg' + fileExtension='.jpg',mimeType='image/jpeg' + fileExtension='.js',mimeType='application/javascript' + fileExtension='.json',mimeType='application/json' + fileExtension='.jsx',mimeType='text/jscript' + fileExtension='.latex',mimeType='application/x-latex' + fileExtension='.lit',mimeType='application/x-ms-reader' + fileExtension='.lpk',mimeType='application/octet-stream' + fileExtension='.lsf',mimeType='video/x-la-asf' + fileExtension='.lsx',mimeType='video/x-la-asf' + fileExtension='.lzh',mimeType='application/octet-stream' + fileExtension='.m13',mimeType='application/x-msmediaview' + fileExtension='.m14',mimeType='application/x-msmediaview' + fileExtension='.m1v',mimeType='video/mpeg' + fileExtension='.m2ts',mimeType='video/vnd.dlna.mpeg-tts' + fileExtension='.m3u',mimeType='audio/x-mpegurl' + fileExtension='.m4a',mimeType='audio/mp4' + fileExtension='.m4v',mimeType='video/mp4' + fileExtension='.man',mimeType='application/x-troff-man' + fileExtension='.manifest',mimeType='application/x-ms-manifest' + fileExtension='.map',mimeType='text/plain' + fileExtension='.mdb',mimeType='application/x-msaccess' + fileExtension='.mdp',mimeType='application/octet-stream' + fileExtension='.me',mimeType='application/x-troff-me' + fileExtension='.mht',mimeType='message/rfc822' + fileExtension='.mhtml',mimeType='message/rfc822' + fileExtension='.mid',mimeType='audio/mid' + fileExtension='.midi',mimeType='audio/mid' + fileExtension='.mix',mimeType='application/octet-stream' + fileExtension='.mmf',mimeType='application/x-smaf' + fileExtension='.mno',mimeType='text/xml' + fileExtension='.mny',mimeType='application/x-msmoney' + fileExtension='.mov',mimeType='video/quicktime' + fileExtension='.movie',mimeType='video/x-sgi-movie' + fileExtension='.mp2',mimeType='video/mpeg' + fileExtension='.mp3',mimeType='audio/mpeg' + fileExtension='.mp4',mimeType='video/mp4' + fileExtension='.mp4v',mimeType='video/mp4' + fileExtension='.mpa',mimeType='video/mpeg' + fileExtension='.mpe',mimeType='video/mpeg' + fileExtension='.mpeg',mimeType='video/mpeg' + fileExtension='.mpg',mimeType='video/mpeg' + fileExtension='.mpp',mimeType='application/vnd.ms-project' + fileExtension='.mpv2',mimeType='video/mpeg' + fileExtension='.ms',mimeType='application/x-troff-ms' + fileExtension='.msi',mimeType='application/octet-stream' + fileExtension='.mso',mimeType='application/octet-stream' + fileExtension='.mvb',mimeType='application/x-msmediaview' + fileExtension='.mvc',mimeType='application/x-miva-compiled' + fileExtension='.nc',mimeType='application/x-netcdf' + fileExtension='.nsc',mimeType='video/x-ms-asf' + fileExtension='.nws',mimeType='message/rfc822' + fileExtension='.ocx',mimeType='application/octet-stream' + fileExtension='.oda',mimeType='application/oda' + fileExtension='.odc',mimeType='text/x-ms-odc' + fileExtension='.ods',mimeType='application/oleobject' + fileExtension='.oga',mimeType='audio/ogg' + fileExtension='.ogg',mimeType='video/ogg' + fileExtension='.ogv',mimeType='video/ogg' + fileExtension='.one',mimeType='application/onenote' + fileExtension='.onea',mimeType='application/onenote' + fileExtension='.onetoc',mimeType='application/onenote' + fileExtension='.onetoc2',mimeType='application/onenote' + fileExtension='.onetmp',mimeType='application/onenote' + fileExtension='.onepkg',mimeType='application/onenote' + fileExtension='.osdx',mimeType='application/opensearchdescription+xml' + fileExtension='.otf',mimeType='font/otf' + fileExtension='.p10',mimeType='application/pkcs10' + fileExtension='.p12',mimeType='application/x-pkcs12' + fileExtension='.p7b',mimeType='application/x-pkcs7-certificates' + fileExtension='.p7c',mimeType='application/pkcs7-mime' + fileExtension='.p7m',mimeType='application/pkcs7-mime' + fileExtension='.p7r',mimeType='application/x-pkcs7-certreqresp' + fileExtension='.p7s',mimeType='application/pkcs7-signature' + fileExtension='.pbm',mimeType='image/x-portable-bitmap' + fileExtension='.pcx',mimeType='application/octet-stream' + fileExtension='.pcz',mimeType='application/octet-stream' + fileExtension='.pdf',mimeType='application/pdf' + fileExtension='.pfb',mimeType='application/octet-stream' + fileExtension='.pfm',mimeType='application/octet-stream' + fileExtension='.pfx',mimeType='application/x-pkcs12' + fileExtension='.pgm',mimeType='image/x-portable-graymap' + fileExtension='.pko',mimeType='application/vnd.ms-pki.pko' + fileExtension='.pma',mimeType='application/x-perfmon' + fileExtension='.pmc',mimeType='application/x-perfmon' + fileExtension='.pml',mimeType='application/x-perfmon' + fileExtension='.pmr',mimeType='application/x-perfmon' + fileExtension='.pmw',mimeType='application/x-perfmon' + fileExtension='.png',mimeType='image/png' + fileExtension='.pnm',mimeType='image/x-portable-anymap' + fileExtension='.pnz',mimeType='image/png' + fileExtension='.pot',mimeType='application/vnd.ms-powerpoint' + fileExtension='.potm',mimeType='application/vnd.ms-powerpoint.template.macroEnabled.12' + fileExtension='.potx',mimeType='application/vnd.openxmlformats-officedocument.presentationml.template' + fileExtension='.ppam',mimeType='application/vnd.ms-powerpoint.addin.macroEnabled.12' + fileExtension='.ppm',mimeType='image/x-portable-pixmap' + fileExtension='.pps',mimeType='application/vnd.ms-powerpoint' + fileExtension='.ppsm',mimeType='application/vnd.ms-powerpoint.slideshow.macroEnabled.12' + fileExtension='.ppsx',mimeType='application/vnd.openxmlformats-officedocument.presentationml.slideshow' + fileExtension='.ppt',mimeType='application/vnd.ms-powerpoint' + fileExtension='.pptm',mimeType='application/vnd.ms-powerpoint.presentation.macroEnabled.12' + fileExtension='.pptx',mimeType='application/vnd.openxmlformats-officedocument.presentationml.presentation' + fileExtension='.prf',mimeType='application/pics-rules' + fileExtension='.prm',mimeType='application/octet-stream' + fileExtension='.prx',mimeType='application/octet-stream' + fileExtension='.ps',mimeType='application/postscript' + fileExtension='.psd',mimeType='application/octet-stream' + fileExtension='.psm',mimeType='application/octet-stream' + fileExtension='.psp',mimeType='application/octet-stream' + fileExtension='.pub',mimeType='application/x-mspublisher' + fileExtension='.qt',mimeType='video/quicktime' + fileExtension='.qtl',mimeType='application/x-quicktimeplayer' + fileExtension='.qxd',mimeType='application/octet-stream' + fileExtension='.ra',mimeType='audio/x-pn-realaudio' + fileExtension='.ram',mimeType='audio/x-pn-realaudio' + fileExtension='.rar',mimeType='application/octet-stream' + fileExtension='.ras',mimeType='image/x-cmu-raster' + fileExtension='.rf',mimeType='image/vnd.rn-realflash' + fileExtension='.rgb',mimeType='image/x-rgb' + fileExtension='.rm',mimeType='application/vnd.rn-realmedia' + fileExtension='.rmi',mimeType='audio/mid' + fileExtension='.roff',mimeType='application/x-troff' + fileExtension='.rpm',mimeType='audio/x-pn-realaudio-plugin' + fileExtension='.rtf',mimeType='application/rtf' + fileExtension='.rtx',mimeType='text/richtext' + fileExtension='.scd',mimeType='application/x-msschedule' + fileExtension='.sct',mimeType='text/scriptlet' + fileExtension='.sea',mimeType='application/octet-stream' + fileExtension='.setpay',mimeType='application/set-payment-initiation' + fileExtension='.setreg',mimeType='application/set-registration-initiation' + fileExtension='.sgml',mimeType='text/sgml' + fileExtension='.sh',mimeType='application/x-sh' + fileExtension='.shar',mimeType='application/x-shar' + fileExtension='.sit',mimeType='application/x-stuffit' + fileExtension='.sldm',mimeType='application/vnd.ms-powerpoint.slide.macroEnabled.12' + fileExtension='.sldx',mimeType='application/vnd.openxmlformats-officedocument.presentationml.slide' + fileExtension='.smd',mimeType='audio/x-smd' + fileExtension='.smi',mimeType='application/octet-stream' + fileExtension='.smx',mimeType='audio/x-smd' + fileExtension='.smz',mimeType='audio/x-smd' + fileExtension='.snd',mimeType='audio/basic' + fileExtension='.snp',mimeType='application/octet-stream' + fileExtension='.spc',mimeType='application/x-pkcs7-certificates' + fileExtension='.spl',mimeType='application/futuresplash' + fileExtension='.spx',mimeType='audio/ogg' + fileExtension='.src',mimeType='application/x-wais-source' + fileExtension='.ssm',mimeType='application/streamingmedia' + fileExtension='.sst',mimeType='application/vnd.ms-pki.certstore' + fileExtension='.stl',mimeType='application/vnd.ms-pki.stl' + fileExtension='.sv4cpio',mimeType='application/x-sv4cpio' + fileExtension='.sv4crc',mimeType='application/x-sv4crc' + fileExtension='.svg',mimeType='image/svg+xml' + fileExtension='.svgz',mimeType='image/svg+xml' + fileExtension='.swf',mimeType='application/x-shockwave-flash' + fileExtension='.t',mimeType='application/x-troff' + fileExtension='.tar',mimeType='application/x-tar' + fileExtension='.tcl',mimeType='application/x-tcl' + fileExtension='.tex',mimeType='application/x-tex' + fileExtension='.texi',mimeType='application/x-texinfo' + fileExtension='.texinfo',mimeType='application/x-texinfo' + fileExtension='.tgz',mimeType='application/x-compressed' + fileExtension='.thmx',mimeType='application/vnd.ms-officetheme' + fileExtension='.thn',mimeType='application/octet-stream' + fileExtension='.tif',mimeType='image/tiff' + fileExtension='.tiff',mimeType='image/tiff' + fileExtension='.toc',mimeType='application/octet-stream' + fileExtension='.tr',mimeType='application/x-troff' + fileExtension='.trm',mimeType='application/x-msterminal' + fileExtension='.ts',mimeType='video/vnd.dlna.mpeg-tts' + fileExtension='.tsv',mimeType='text/tab-separated-values' + fileExtension='.ttf',mimeType='application/octet-stream' + fileExtension='.tts',mimeType='video/vnd.dlna.mpeg-tts' + fileExtension='.txt',mimeType='text/plain' + fileExtension='.u32',mimeType='application/octet-stream' + fileExtension='.uls',mimeType='text/iuls' + fileExtension='.ustar',mimeType='application/x-ustar' + fileExtension='.vbs',mimeType='text/vbscript' + fileExtension='.vcf',mimeType='text/x-vcard' + fileExtension='.vcs',mimeType='text/plain' + fileExtension='.vdx',mimeType='application/vnd.ms-visio.viewer' + fileExtension='.vml',mimeType='text/xml' + fileExtension='.vsd',mimeType='application/vnd.visio' + fileExtension='.vss',mimeType='application/vnd.visio' + fileExtension='.vst',mimeType='application/vnd.visio' + fileExtension='.vsto',mimeType='application/x-ms-vsto' + fileExtension='.vsw',mimeType='application/vnd.visio' + fileExtension='.vsx',mimeType='application/vnd.visio' + fileExtension='.vtx',mimeType='application/vnd.visio' + fileExtension='.wav',mimeType='audio/wav' + fileExtension='.wax',mimeType='audio/x-ms-wax' + fileExtension='.wbmp',mimeType='image/vnd.wap.wbmp' + fileExtension='.wcm',mimeType='application/vnd.ms-works' + fileExtension='.wdb',mimeType='application/vnd.ms-works' + fileExtension='.webm',mimeType='video/webm' + fileExtension='.wks',mimeType='application/vnd.ms-works' + fileExtension='.wm',mimeType='video/x-ms-wm' + fileExtension='.wma',mimeType='audio/x-ms-wma' + fileExtension='.wmd',mimeType='application/x-ms-wmd' + fileExtension='.wmf',mimeType='application/x-msmetafile' + fileExtension='.wml',mimeType='text/vnd.wap.wml' + fileExtension='.wmlc',mimeType='application/vnd.wap.wmlc' + fileExtension='.wmls',mimeType='text/vnd.wap.wmlscript' + fileExtension='.wmlsc',mimeType='application/vnd.wap.wmlscriptc' + fileExtension='.wmp',mimeType='video/x-ms-wmp' + fileExtension='.wmv',mimeType='video/x-ms-wmv' + fileExtension='.wmx',mimeType='video/x-ms-wmx' + fileExtension='.wmz',mimeType='application/x-ms-wmz' + fileExtension='.woff',mimeType='font/x-woff' + fileExtension='.wps',mimeType='application/vnd.ms-works' + fileExtension='.wri',mimeType='application/x-mswrite' + fileExtension='.wrl',mimeType='x-world/x-vrml' + fileExtension='.wrz',mimeType='x-world/x-vrml' + fileExtension='.wsdl',mimeType='text/xml' + fileExtension='.wtv',mimeType='video/x-ms-wtv' + fileExtension='.wvx',mimeType='video/x-ms-wvx' + fileExtension='.x',mimeType='application/directx' + fileExtension='.xaf',mimeType='x-world/x-vrml' + fileExtension='.xaml',mimeType='application/xaml+xml' + fileExtension='.xap',mimeType='application/x-silverlight-app' + fileExtension='.xbap',mimeType='application/x-ms-xbap' + fileExtension='.xbm',mimeType='image/x-xbitmap' + fileExtension='.xdr',mimeType='text/plain' + fileExtension='.xht',mimeType='application/xhtml+xml' + fileExtension='.xhtml',mimeType='application/xhtml+xml' + fileExtension='.xla',mimeType='application/vnd.ms-excel' + fileExtension='.xlam',mimeType='application/vnd.ms-excel.addin.macroEnabled.12' + fileExtension='.xlc',mimeType='application/vnd.ms-excel' + fileExtension='.xlm',mimeType='application/vnd.ms-excel' + fileExtension='.xls',mimeType='application/vnd.ms-excel' + fileExtension='.xlsb',mimeType='application/vnd.ms-excel.sheet.binary.macroEnabled.12' + fileExtension='.xlsm',mimeType='application/vnd.ms-excel.sheet.macroEnabled.12' + fileExtension='.xlsx',mimeType='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + fileExtension='.xlt',mimeType='application/vnd.ms-excel' + fileExtension='.xltm',mimeType='application/vnd.ms-excel.template.macroEnabled.12' + fileExtension='.xltx',mimeType='application/vnd.openxmlformats-officedocument.spreadsheetml.template' + fileExtension='.xlw',mimeType='application/vnd.ms-excel' + fileExtension='.xml',mimeType='text/xml' + fileExtension='.xof',mimeType='x-world/x-vrml' + fileExtension='.xpm',mimeType='image/x-xpixmap' + fileExtension='.xps',mimeType='application/vnd.ms-xpsdocument' + fileExtension='.xsd',mimeType='text/xml' + fileExtension='.xsf',mimeType='text/xml' + fileExtension='.xsl',mimeType='text/xml' + fileExtension='.xslt',mimeType='text/xml' + fileExtension='.xsn',mimeType='application/octet-stream' + fileExtension='.xtp',mimeType='application/octet-stream' + fileExtension='.xwd',mimeType='image/x-xwindowdump' + fileExtension='.z',mimeType='application/x-compress' + fileExtension='.zip',mimeType='application/x-zip-compressed + ) + end + end +end diff --git a/cookbooks/iis/libraries/helper.rb b/cookbooks/iis/libraries/helper.rb new file mode 100644 index 00000000..553f8cbd --- /dev/null +++ b/cookbooks/iis/libraries/helper.rb @@ -0,0 +1,91 @@ +# +# Cookbook:: iis +# Library:: helper +# +# Copyright:: 2017-2019, 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. +# + +module IISCookbook + # Contains functions that are used throughout this cookbook + module Helper + @iis_version = nil + + if RUBY_PLATFORM =~ /mswin|mingw32|windows/ + require 'chef/win32/version' + require 'win32/registry' + end + + require 'rexml/document' + require 'chef/mixin/shell_out' + + include Chef::Mixin::ShellOut + include REXML + include Windows::Helper + + def self.older_than_windows2012? + if RUBY_PLATFORM =~ /mswin|mingw32|windows/ + win_version = Chef::ReservedNames::Win32::Version.new + win_version.windows_7? || win_version.windows_server_2008_r2? + end + end + + def windows_cleanpath(path) + path = if defined?(Chef::Util::PathHelper.cleanpath).nil? + win_friendly_path(path) + else + Chef::Util::PathHelper.cleanpath(path) + end + # Remove any trailing slashes to prevent them from accidentally escaping any quotes. + path.tr('/', '\\') + end + + def application_cleanname(application_name) + if application_name.count('/') == 0 + "#{application_name}/" + elsif application_name.count('/') > 1 + application_name.chomp('/') + else + application_name + end + end + + def value(document, xpath) + Text.unnormalize(XPath.first(document, xpath).to_s) + end + + def get_value(document, xpath) + XPath.match(document, xpath) + end + + def bool(value) + value == 'true' + end + + def appcmd(node) + @appcmd ||= begin + "#{node['iis']['home']}\\appcmd.exe" + end + end + + def iis_version + if @iis_version.nil? + version_string = Win32::Registry::HKEY_LOCAL_MACHINE.open('SOFTWARE\Microsoft\InetStp').read('VersionString')[1] + version_string.slice! 'Version ' + @iis_version = version_string + end + @iis_version.to_f + end + end +end diff --git a/cookbooks/iis/libraries/processors.rb b/cookbooks/iis/libraries/processors.rb new file mode 100644 index 00000000..2f6f2b20 --- /dev/null +++ b/cookbooks/iis/libraries/processors.rb @@ -0,0 +1,118 @@ +# +# Cookbook:: iis +# Library:: processors +# +# Copyright:: 2017-2019, 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. +# + +module IISCookbook + # Contains functions that are used throughout this cookbook + module Processors + def current_default_documents_config(specifier = '') + cmd = shell_out! get_default_documents_command specifier + return unless cmd.stderr.empty? + xml = cmd.stdout + doc = REXML::Document.new xml + + { + default_documents_enabled: value(doc.root, 'CONFIG/system.webServer-defaultDocument/@enabled'), + default_documents: REXML::XPath.match(doc.root, 'CONFIG/system.webServer-defaultDocument/files/add/@value').map(&:value), + } + end + + def current_mime_maps_config(specifier = '') + # handles mime maps + cmd = shell_out! get_mime_map_command specifier + return unless cmd.stderr.empty? + xml = cmd.stdout + doc = REXML::Document.new xml + + REXML::XPath.match(doc.root, 'CONFIG/system.webServer-staticContent/mimeMap').map { |x| "fileExtension='#{x.attribute 'fileExtension'}',mimeType='#{x.attribute 'mimeType'}'" } + end + + def set_default_documents_enabled(value, specifier = '') + cmd = default_documents_command specifier + cmd << " /enabled:#{value}" + shell_out! cmd + end + + def set_default_documents(desired_default_documents, current_default_documents, add = true, remove = true, specifier = '') + cmd = default_documents_command specifier + Chef::Log.warn("new #{desired_default_documents} --- old #{current_default_documents}") + if add + (desired_default_documents - current_default_documents).each do |document| + cmd << " /+files.[value='#{document}']" + end + end + if remove && !add + (desired_default_documents - current_default_documents).each do |document| + cmd << " /-files.[value='#{document}']" + end + end + if remove && add + (current_default_documents - desired_default_documents).each do |document| + cmd << " /-files.[value='#{document}']" + end + end + + Chef::Log.warn("before cmd -- #{cmd}") + + return unless cmd != default_documents_command(specifier) + Chef::Log.warn("after cmd -- #{cmd}") + shell_out! cmd + end + + def set_mime_maps(desired_mime_maps, current_mime_maps, add = true, remove = true, specifier = '') + cmd = mime_map_command specifier + + if add + (desired_mime_maps - current_mime_maps).each do |mime_map| + cmd << " /+\"[#{mime_map}]\"" + end + end + if remove && !add + (desired_mime_maps - current_mime_maps).each do |mime_map| + cmd << " /-\"[#{mime_map}]\"" + end + end + if remove && add + (current_mime_maps - desired_mime_maps).each do |mime_map| + cmd << " /-\"[#{mime_map}]\"" + end + end + + return unless cmd != mime_map_command(specifier) + shell_out! cmd + end + + private + + def get_default_documents_command(specifier = '') + "#{appcmd(node)} list config #{specifier} /section:defaultDocument /config:* /xml" + end + + def default_documents_command(specifier = '') + "#{appcmd(node)} set config #{specifier} /section:defaultDocument" + end + + def get_mime_map_command(specifier = '') + "#{appcmd(node)} list config #{specifier} /section:staticContent /config:* /xml" + end + + def mime_map_command(specifier = '') + "#{appcmd(node)} set config #{specifier} /section:staticContent" + end + end +end diff --git a/cookbooks/iis/libraries/section_helper.rb b/cookbooks/iis/libraries/section_helper.rb new file mode 100644 index 00000000..22b72e04 --- /dev/null +++ b/cookbooks/iis/libraries/section_helper.rb @@ -0,0 +1,77 @@ +# +# Cookbook:: iis +# Library:: section-helper +# +# Copyright:: 2017-2019, 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. +# + +module IISCookbook + # Contains functions that are used throughout this cookbook + module SectionHelper + require 'rexml/document' + include REXML + + def lock(node, section, location = '', returns = [0]) + cmd_list_section node, :lock, section, location, returns + end + + def unlock(node, section, location = '', returns = [0]) + cmd_list_section node, :unlock, section, location, returns + end + + def override_mode(node, action, section, location = '', returns = [0]) + cmd_list_section(node, action, section, location, returns) + end + + def get_current_lock(node, section, location = '') + command_path = 'MACHINE/WEBROOT/APPHOST' + command_path << "/#{location}" if location + cmd = "#{appcmd(node)} list config \"#{command_path}}\"" + cmd << " -section:#{section} -commit:apphost /config:* /xml" + result = shell_out cmd + if result.stderr.empty? + xml = result.stdout + doc = Document.new xml + value(doc.root, 'CONFIG/@overrideMode') + else + Chef::Log.info(result.stderr) + end + + nil + end + + def cmd_section(node, check, section, location, returns) + cmd = "#{appcmd(node)} set config \"MACHINE/WEBROOT/APPHOST/#{location}\"" + cmd << " -section:\"#{section}\" -overrideMode:#{check}" + cmd << ' -commit:apphost' + Chef::Log.debug(cmd) + shell_out!(cmd, returns: returns) + + return unless location + cmd = "#{appcmd(node)} set config \"MACHINE/WEBROOT/APPHOST/#{location}\"" + cmd << " -section:\"#{section}\" -overrideMode:#{check}" + Chef::Log.debug(cmd) + shell_out!(cmd, returns: returns) + end + + def cmd_list_section(node, action, section, location, returns) + current_lock = get_current_lock(node, section, location) + check = action if action == 'Inherit' + check = (action == :lock ? 'Deny' : 'Allow') if action != 'Inherit' + + cmd_section node, check, section, location, returns unless current_lock == check + end + end +end diff --git a/cookbooks/iis/metadata.rb b/cookbooks/iis/metadata.rb new file mode 100644 index 00000000..86cddcac --- /dev/null +++ b/cookbooks/iis/metadata.rb @@ -0,0 +1,11 @@ +name 'iis' +maintainer 'Chef Software, Inc.' +maintainer_email 'cookbooks@chef.io' +license 'Apache-2.0' +description 'Installs/Configures Microsoft Internet Information Services' +version '7.3.0' +supports 'windows' +depends 'windows', '>= 4.1.0' +source_url 'https://github.com/chef-cookbooks/iis' +issues_url 'https://github.com/chef-cookbooks/iis/issues' +chef_version '>= 12.14' diff --git a/cookbooks/iis/recipes/default.rb b/cookbooks/iis/recipes/default.rb new file mode 100644 index 00000000..4c2d7041 --- /dev/null +++ b/cookbooks/iis/recipes/default.rb @@ -0,0 +1,29 @@ +# +# Author:: Seth Chisamore () +# Cookbook:: iis +# Recipe:: default +# +# Copyright:: 2011-2019, 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. +# + +iis_install 'install IIS' do + additional_components node['iis']['components'] + source node['iis']['source'] +end + +service 'iis' do + service_name 'W3SVC' + action [:enable, :start] +end diff --git a/cookbooks/iis/recipes/mod_application_initialization.rb b/cookbooks/iis/recipes/mod_application_initialization.rb new file mode 100644 index 00000000..c98e39de --- /dev/null +++ b/cookbooks/iis/recipes/mod_application_initialization.rb @@ -0,0 +1,23 @@ +# +# Author:: Seth Chisamore () +# Cookbook:: iis +# Recipe:: mod_application_initialization +# +# Copyright:: 2011-2019, 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. +# + +include_recipe 'iis' + +windows_feature 'IIS-ApplicationInit' diff --git a/cookbooks/iis/recipes/mod_aspnet.rb b/cookbooks/iis/recipes/mod_aspnet.rb new file mode 100644 index 00000000..f085bd18 --- /dev/null +++ b/cookbooks/iis/recipes/mod_aspnet.rb @@ -0,0 +1,28 @@ +# +# Author:: Seth Chisamore () +# Cookbook:: iis +# Recipe:: mod_aspnet +# +# Copyright:: 2011-2019, 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. +# + +include_recipe 'iis' +include_recipe 'iis::mod_isapi' + +windows_feature %w(IIS-NetFxExtensibility IIS-ASPNET) do + action :install + all !IISCookbook::Helper.older_than_windows2012? + source node['iis']['source'] unless node['iis']['source'].nil? +end diff --git a/cookbooks/iis/recipes/mod_aspnet45.rb b/cookbooks/iis/recipes/mod_aspnet45.rb new file mode 100644 index 00000000..6a3e7dbf --- /dev/null +++ b/cookbooks/iis/recipes/mod_aspnet45.rb @@ -0,0 +1,24 @@ +# +# Author:: Blair Hamilton () +# Cookbook:: iis +# Recipe:: mod_aspnet45 +# +# Copyright:: 2011-2019, 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. +# + +include_recipe 'iis' +include_recipe 'iis::mod_isapi' + +windows_feature %w(NetFx4Extended-ASPNET45 IIS-NetFxExtensibility45 IIS-ASPNET45) diff --git a/cookbooks/iis/recipes/mod_auth_anonymous.rb b/cookbooks/iis/recipes/mod_auth_anonymous.rb new file mode 100644 index 00000000..55c66570 --- /dev/null +++ b/cookbooks/iis/recipes/mod_auth_anonymous.rb @@ -0,0 +1,26 @@ +# +# Author:: Justin Schuhmann +# Cookbook:: iis +# Recipe:: mod_auth_basic +# +# Copyright:: 2016, Justin Schuhmann +# +# 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. +# + +include_recipe 'iis' + +iis_section 'unlocks anonymous authentication control in web.config' do + section 'system.webServer/security/authentication/anonymousAuthentication' + action :unlock +end diff --git a/cookbooks/iis/recipes/mod_auth_basic.rb b/cookbooks/iis/recipes/mod_auth_basic.rb new file mode 100644 index 00000000..032aedbb --- /dev/null +++ b/cookbooks/iis/recipes/mod_auth_basic.rb @@ -0,0 +1,28 @@ +# +# Author:: Seth Chisamore () +# Cookbook:: iis +# Recipe:: mod_auth_basic +# +# Copyright:: 2011-2019, 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. +# + +include_recipe 'iis' + +windows_feature 'IIS-BasicAuthentication' + +iis_section 'unlocks basic authentication control in web.config' do + section 'system.webServer/security/authentication/basicAuthentication' + action :unlock +end diff --git a/cookbooks/iis/recipes/mod_auth_digest.rb b/cookbooks/iis/recipes/mod_auth_digest.rb new file mode 100644 index 00000000..517a36e2 --- /dev/null +++ b/cookbooks/iis/recipes/mod_auth_digest.rb @@ -0,0 +1,28 @@ +# +# Author:: Justin Schuhmann +# Cookbook:: iis +# Recipe:: mod_auth_basic +# +# Copyright:: 2016, Justin Schuhmann +# +# 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. +# + +include_recipe 'iis' + +windows_feature 'IIS-DigestAuthentication' + +iis_section 'unlocks digest authentication control in web.config' do + section 'system.webServer/security/authentication/digestAuthentication' + action :unlock +end diff --git a/cookbooks/iis/recipes/mod_auth_windows.rb b/cookbooks/iis/recipes/mod_auth_windows.rb new file mode 100644 index 00000000..cba02fe9 --- /dev/null +++ b/cookbooks/iis/recipes/mod_auth_windows.rb @@ -0,0 +1,28 @@ +# +# Author:: Seth Chisamore () +# Cookbook:: iis +# Recipe:: mod_auth_windows +# +# Copyright:: 2011-2019, 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. +# + +include_recipe 'iis' + +windows_feature 'IIS-WindowsAuthentication' + +iis_section 'unlocks windows authentication control in web.config' do + section 'system.webServer/security/authentication/windowsAuthentication' + action :unlock +end diff --git a/cookbooks/iis/recipes/mod_cgi.rb b/cookbooks/iis/recipes/mod_cgi.rb new file mode 100644 index 00000000..a29b7628 --- /dev/null +++ b/cookbooks/iis/recipes/mod_cgi.rb @@ -0,0 +1,23 @@ +# +# Author:: Richard Downer () +# Cookbook:: iis +# Recipe:: mod_cgi +# +# Copyright:: 2013-2016, Cloudsoft Corporation +# +# 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. +# + +include_recipe 'iis' + +windows_feature 'IIS-CGI' diff --git a/cookbooks/iis/recipes/mod_compress_dynamic.rb b/cookbooks/iis/recipes/mod_compress_dynamic.rb new file mode 100644 index 00000000..991e86aa --- /dev/null +++ b/cookbooks/iis/recipes/mod_compress_dynamic.rb @@ -0,0 +1,23 @@ +# +# Author:: Seth Chisamore () +# Cookbook:: iis +# Recipe:: mod_compress_dynamic +# +# Copyright:: 2011-2019, 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. +# + +include_recipe 'iis' + +windows_feature 'IIS-HttpCompressionDynamic' diff --git a/cookbooks/iis/recipes/mod_compress_static.rb b/cookbooks/iis/recipes/mod_compress_static.rb new file mode 100644 index 00000000..725fd17c --- /dev/null +++ b/cookbooks/iis/recipes/mod_compress_static.rb @@ -0,0 +1,23 @@ +# +# Author:: Seth Chisamore () +# Cookbook:: iis +# Recipe:: mod_compress_static +# +# Copyright:: 2011-2019, 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. +# + +include_recipe 'iis' + +windows_feature 'IIS-HttpCompressionStatic' diff --git a/cookbooks/iis/recipes/mod_ftp.rb b/cookbooks/iis/recipes/mod_ftp.rb new file mode 100644 index 00000000..7c2161d2 --- /dev/null +++ b/cookbooks/iis/recipes/mod_ftp.rb @@ -0,0 +1,23 @@ +# +# Author:: Kevin Rivers () +# Cookbook:: iis +# Recipe:: mod_ftp +# +# Copyright:: 2014-2016, Kevin Rivers +# +# 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. +# + +include_recipe 'iis' + +windows_feature %w(IIS-FTPServer IIS-FTPSvc IIS-FTPExtensibility) diff --git a/cookbooks/iis/recipes/mod_iis6_metabase_compat.rb b/cookbooks/iis/recipes/mod_iis6_metabase_compat.rb new file mode 100644 index 00000000..b1df7e62 --- /dev/null +++ b/cookbooks/iis/recipes/mod_iis6_metabase_compat.rb @@ -0,0 +1,23 @@ +# +# Author:: Kristian Vlaardingerbroek () +# Cookbook:: iis +# Recipe:: mod_iis6_metabase_compat +# +# Copyright:: 2013-2016, Schuberg Philis B.V. +# +# 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. +# + +include_recipe 'iis' + +windows_feature %w(IIS-IIS6ManagementCompatibility IIS-Metabase) diff --git a/cookbooks/iis/recipes/mod_isapi.rb b/cookbooks/iis/recipes/mod_isapi.rb new file mode 100644 index 00000000..bffffd4c --- /dev/null +++ b/cookbooks/iis/recipes/mod_isapi.rb @@ -0,0 +1,23 @@ +# +# Author:: Seth Chisamore () +# Cookbook:: iis +# Recipe:: mod_isapi +# +# Copyright:: 2011-2019, 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. +# + +include_recipe 'iis' + +windows_feature %w(IIS-ISAPIFilter IIS-ISAPIExtensions) diff --git a/cookbooks/iis/recipes/mod_logging.rb b/cookbooks/iis/recipes/mod_logging.rb new file mode 100644 index 00000000..ba2d46c2 --- /dev/null +++ b/cookbooks/iis/recipes/mod_logging.rb @@ -0,0 +1,23 @@ +# +# Author:: Seth Chisamore () +# Cookbook:: iis +# Recipe:: mod_logging +# +# Copyright:: 2011-2019, 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. +# + +include_recipe 'iis' + +windows_feature 'IIS-CustomLogging' diff --git a/cookbooks/iis/recipes/mod_management.rb b/cookbooks/iis/recipes/mod_management.rb new file mode 100644 index 00000000..7bcc9f3f --- /dev/null +++ b/cookbooks/iis/recipes/mod_management.rb @@ -0,0 +1,26 @@ +# +# Author:: Seth Chisamore () +# Cookbook:: iis +# Recipe:: mod_management +# +# Copyright:: 2011-2019, 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. +# + +include_recipe 'iis' + +windows_feature %w(IIS-ManagementConsole IIS-ManagementService) do + action :install + all !IISCookbook::Helper.older_than_windows2012? +end diff --git a/cookbooks/iis/recipes/mod_security.rb b/cookbooks/iis/recipes/mod_security.rb new file mode 100644 index 00000000..959a6c67 --- /dev/null +++ b/cookbooks/iis/recipes/mod_security.rb @@ -0,0 +1,23 @@ +# +# Author:: Seth Chisamore () +# Cookbook:: iis +# Recipe:: mod_security +# +# Copyright:: 2011-2019, 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. +# + +include_recipe 'iis' + +windows_feature %w(IIS-URLAuthorization IIS-RequestFiltering IIS-IPSecurity) diff --git a/cookbooks/iis/recipes/mod_tracing.rb b/cookbooks/iis/recipes/mod_tracing.rb new file mode 100644 index 00000000..6d35b595 --- /dev/null +++ b/cookbooks/iis/recipes/mod_tracing.rb @@ -0,0 +1,23 @@ +# +# Author:: Seth Chisamore () +# Cookbook:: iis +# Recipe:: mod_diagnostics +# +# Copyright:: 2011-2019, 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. +# + +include_recipe 'iis' + +windows_feature 'IIS-HttpTracing' diff --git a/cookbooks/iis/recipes/remove_default_site.rb b/cookbooks/iis/recipes/remove_default_site.rb new file mode 100644 index 00000000..24866813 --- /dev/null +++ b/cookbooks/iis/recipes/remove_default_site.rb @@ -0,0 +1,27 @@ +# +# Author:: Kendrick Martin () +# Cookbook:: iis +# Recipe:: remove_default_site +# +# Copyright:: 2012-2018, Webtrends, 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. +# + +iis_site 'Default Web Site' do + action [:stop, :delete] +end + +iis_pool 'DefaultAppPool' do + action [:stop, :delete] +end diff --git a/cookbooks/iis/resources/app.rb b/cookbooks/iis/resources/app.rb new file mode 100644 index 00000000..ae09d9b7 --- /dev/null +++ b/cookbooks/iis/resources/app.rb @@ -0,0 +1,144 @@ +# +# Cookbook:: iis +# Resource:: app +# +# Copyright:: 2011-2019, 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. +# + +require 'rexml/document' + +include REXML +include IISCookbook::Helper + +property :site_name, String, name_property: true +property :path, String, default: '/' +property :application_pool, String +property :physical_path, String +property :enabled_protocols, String + +load_current_value do |desired| + site_name desired.site_name + # Sanitize physical path + desired.physical_path = windows_cleanpath(desired.physical_path) if desired.physical_path + cmd = shell_out("#{appcmd(node)} list app \"#{desired.site_name}#{desired.path}\"") + Chef::Log.debug("#{appcmd(node)} list app command output: #{cmd.stdout}") + if cmd.stderr.empty? + Chef::Log.debug('Running regex') + regex = /^APP\s\"#{desired.site_name}#{desired.path}\"/ + result = cmd.stdout.match(regex) + Chef::Log.debug("#{desired} current_resource match output: #{result}") + if !result.nil? + cmd_current_values = "#{appcmd(node)} list app \"#{desired.site_name}#{desired.path}\" /config:* /xml" + Chef::Log.debug(cmd_current_values) + cmd_current_values = shell_out(cmd_current_values) + if cmd_current_values.stderr.empty? + xml = cmd_current_values.stdout + doc = Document.new(xml) + path value doc.root, 'APP/application/@path' + application_pool value doc.root, 'APP/application/@applicationPool' + enabled_protocols value doc.root, 'APP/application/@enabledProtocols' + physical_path windows_cleanpath(value(doc.root, 'APP/application/virtualDirectory/@physicalPath')) + end + else + path '' + end + else + Chef::Log.warn "Failed to run iis_app action :load_current_resource, #{cmd_current_values.stderr}" + end +end + +action :add do + if exists + Chef::Log.debug("#{new_resource.inspect} app already exists - nothing to do") + else + converge_by "Creating the Application - \"#{new_resource}\"" do + cmd = "#{appcmd(node)} add app /site.name:\"#{new_resource.site_name}\"" + cmd << " /path:\"#{new_resource.path}\"" + cmd << " /applicationPool:\"#{new_resource.application_pool}\"" if new_resource.application_pool + cmd << " /physicalPath:\"#{new_resource.physical_path}\"" if new_resource.physical_path + cmd << " /enabledProtocols:\"#{new_resource.enabled_protocols}\"" if new_resource.enabled_protocols + cmd << ' /commit:\"MACHINE/WEBROOT/APPHOST\"' + Chef::Log.debug(cmd) + shell_out!(cmd) + end + end +end + +action :config do + if exists + # only get the beginning of the command if there is something that changes + cmd = cmd_set_app + converge_if_changed :path do + # adds path to the cmd + cmd << " /path:\"#{new_resource.path}\"" if new_resource.path + end + converge_if_changed :application_pool do + # adds applicationPool to the cmd + cmd << " /applicationPool:\"#{new_resource.application_pool}\"" if new_resource.application_pool + end + converge_if_changed :enabled_protocols do + # adds enabledProtocols to the cmd + cmd << " /enabledProtocols:\"#{new_resource.enabled_protocols}\"" if new_resource.enabled_protocols + end + Chef::Log.debug(cmd) + + if cmd == cmd_set_app + Chef::Log.debug("#{new_resource.inspect} application - nothing to do") + else + converge_by "Updating the Application - \"#{new_resource}\"" do + shell_out!(cmd) + end + end + + converge_if_changed :physical_path do + cmd = "#{appcmd(node)} set vdir /vdir.name:\"#{vdir_identifier}\"" + cmd << " /physicalPath:\"#{new_resource.physical_path}\"" + Chef::Log.debug(cmd) + shell_out!(cmd) + end + else + Chef::Log.debug("#{new_resource.inspect} app needs to be added - cannot configure non-existent items") + end +end + +action :delete do + if exists + converge_by "Deleting the Application - \"#{new_resource}\"" do + shell_out!("#{appcmd(node)} delete app \"#{site_identifier}\"") + Chef::Log.info("#{new_resource} deleted") + end + else + Chef::Log.debug("#{new_resource.inspect} app does not exist - nothing to do") + end +end + +action_class.class_eval do + def exists + !current_resource.path.empty? + end + + def cmd_set_app + "#{appcmd(node)} set app \"#{site_identifier}\"" + end + + def site_identifier + "#{new_resource.site_name}#{new_resource.path}" + end + + # Ensure VDIR identifier has a trailing slash + def vdir_identifier + site_identifier.end_with?('/') ? site_identifier : site_identifier + '/' + end +end diff --git a/cookbooks/iis/resources/config.rb b/cookbooks/iis/resources/config.rb new file mode 100644 index 00000000..d4e5e6f2 --- /dev/null +++ b/cookbooks/iis/resources/config.rb @@ -0,0 +1,42 @@ +# +# Cookbook:: iis +# Resource:: config +# +# Copyright:: 2017-2019, 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. +# + +include IISCookbook::Helper +include IISCookbook::Processors + +property :cfg_cmd, String, name_property: true +property :returns, [Integer, Array], default: 0 + +action :set do + config +end + +action :clear do + config(:clear) +end + +action_class.class_eval do + def config(action = :set) + converge_by "Executing IIS Config #{action}" do + cmd = "#{appcmd(node)} #{action} config #{new_resource.cfg_cmd}" + Chef::Log.debug(cmd) + shell_out!(cmd, returns: new_resource.returns) + end + end +end diff --git a/cookbooks/iis/resources/config_property.rb b/cookbooks/iis/resources/config_property.rb new file mode 100644 index 00000000..e352519e --- /dev/null +++ b/cookbooks/iis/resources/config_property.rb @@ -0,0 +1,110 @@ +# +# Cookbook:: iis +# Resource:: config_property +# +# Copyright:: 2018, Calastone Ltd. +# +# 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. +# +# Configures an IIS property (using powershell for idempotence) + +property :property, String, name_property: true +property :ps_path, String, required: true +property :location, String +property :filter, String, required: true +property :value, [String, Integer], required: true +property :extra_add_values, Hash + +action :set do + location_param = "-location \"#{new_resource.location}\"" if + property_is_set?(:location) + + # powershell doesn't like { or } in xpath values (e.g. server variables) + escaped_filter = new_resource.filter.gsub('{', '{{').gsub('}', '}}') + + property_value = if new_resource.value.is_a?(Integer) + new_resource.value.to_s + else + "\"#{new_resource.value}\"" + end + powershell_script "Set #{new_resource.ps_path}#{new_resource.location}\ +/#{escaped_filter}/#{new_resource.property}" do + code <<-EOH + Set-WebConfigurationProperty -pspath "#{new_resource.ps_path}" \ + #{location_param} -filter "#{escaped_filter}" \ + -name "#{new_resource.property}" \ + -value #{property_value} -ErrorAction Stop + EOH + only_if <<-EOH + (Get-WebConfigurationProperty -pspath "#{new_resource.ps_path}" \ + #{location_param} -filter "#{escaped_filter}" \ + -name "#{new_resource.property}" -ErrorAction Stop) -ne #{property_value} + EOH + end +end + +action :add do + location_param = "-location \"#{new_resource.location}\"" if + property_is_set?(:location) + + # powershell doesn't like { or } in xpath values (e.g. server variables) + escaped_value = new_resource.value.gsub('{', '{{').gsub('}', '}}') + escaped_filter = new_resource.filter.gsub('{', '{{').gsub('}', '}}') + extra_values = new_resource.extra_add_values.map do |n, v| + property_value = if v.is_a?(Integer) + v.to_s + else + "'#{v}'" + end + "#{n} = #{property_value}" + end.join(';') if property_is_set?(:extra_add_values) + + powershell_script "Set #{new_resource.ps_path}#{new_resource.location}\ +/#{escaped_filter}/#{new_resource.property}" do + code <<-EOH + Add-WebConfigurationProperty -pspath "#{new_resource.ps_path}" \ + #{location_param} -filter "#{escaped_filter}" \ + -name "." -value @{ #{new_resource.property} = '#{new_resource.value}'; #{extra_values} } \ + -ErrorAction Stop + EOH + only_if <<-EOH + (Get-WebConfiguration -pspath "#{new_resource.ps_path}" #{location_param} \ + -filter "#{escaped_filter}/*[@#{new_resource.property}='#{escaped_value}']" \ + -ErrorAction Stop) -eq $null + EOH + end +end + +action :remove do + location_param = "-location \"#{new_resource.location}\"" if + property_is_set?(:location) + + # powershell doesn't like { or } in xpath values (e.g. server variables) + escaped_value = new_resource.value.gsub('{', '{{').gsub('}', '}}') + escaped_filter = new_resource.filter.gsub('{', '{{').gsub('}', '}}') + + powershell_script "Set #{new_resource.ps_path}#{new_resource.location}\ +/#{escaped_filter}/#{new_resource.property}" do + code <<-EOH + Remove-WebConfigurationProperty -pspath "#{new_resource.ps_path}" \ + #{location_param} -filter "#{escaped_filter}" \ + -name "." -AtElement @{ #{new_resource.property} = \ + '#{new_resource.value}'; } -ErrorAction Stop + EOH + only_if <<-EOH + (Get-WebConfiguration -pspath "#{new_resource.ps_path}" #{location_param} \ + -filter "#{escaped_filter}/*[@#{new_resource.property}='#{escaped_value}']" \ + -ErrorAction Stop) -ne $null + EOH + end +end diff --git a/cookbooks/iis/resources/install.rb b/cookbooks/iis/resources/install.rb new file mode 100644 index 00000000..bbd82da3 --- /dev/null +++ b/cookbooks/iis/resources/install.rb @@ -0,0 +1,31 @@ +# +# Cookbook:: iis +# Resource:: install +# +# Copyright:: 2018-2019, 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. +# + +include IISCookbook::Helper + +property :source, String +property :additional_components, Array, default: [] + +action :install do + windows_feature ['IIS-WebServerRole'] + new_resource.additional_components do + action :install + all !IISCookbook::Helper.older_than_windows2012? + source new_resource.source unless new_resource.source.nil? + end +end diff --git a/cookbooks/iis/resources/manager.rb b/cookbooks/iis/resources/manager.rb new file mode 100644 index 00000000..cddef217 --- /dev/null +++ b/cookbooks/iis/resources/manager.rb @@ -0,0 +1,74 @@ +# +# Author:: Jason Field +# Cookbook:: iis +# Resource:: manager +# +# Copyright:: 2018, Calastone Ltd. +# +# 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. +# +# Configures IIS Manager + +property :enable_remote_management, [true, false], default: true +property :log_directory, String +property :port, Integer, default: 8172 + +action :config do + iis_install 'Web-Mgmt-Service' do + additional_components ['IIS-ManagementService'] + end + + # properties stored in the registry + reg_values = [{ + name: 'EnableRemoteManagement', + type: :dword, + data: new_resource.enable_remote_management ? 1 : 0, + }, { + name: 'Port', + type: :dword, + data: new_resource.port, + }] + + if property_is_set?(:log_directory) + directory new_resource.log_directory do + recursive true + end + + reg_values.push( + name: 'LoggingDirectory', + type: :string, + data: new_resource.log_directory + ) + end + + registry_key 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WebManagement\Server' do + values reg_values + notifies :restart, 'service[WMSVC]', :delayed + end + + # if using a custom port then we need to allow the service account to listen on it + if property_is_set?(:port) + windows_http_acl "https://*:#{new_resource.port}/" do + user 'NT SERVICE\WMSvc' + end + # WMSVC is the self signed cert auto generated by windows + windows_certificate_binding 'WMSVC' do + port new_resource.port + app_id '{d7d72267-fcf9-4424-9eec-7e1d8dcec9a9}' + end + end + + service 'WMSVC' do + action [:enable, :start] + end +end diff --git a/cookbooks/iis/resources/manager_permission.rb b/cookbooks/iis/resources/manager_permission.rb new file mode 100644 index 00000000..f6a010ff --- /dev/null +++ b/cookbooks/iis/resources/manager_permission.rb @@ -0,0 +1,84 @@ +# +# Author:: Jason Field +# Cookbook:: iis +# Resource:: manager_permissions +# +# Copyright:: 2018, Calastone Ltd. +# +# 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. +# +# Grants access to IIS manager against a site or application + +property :config_path, String, name_property: true +property :users, Array, default: [] +property :groups, Array, default: [] + +action :config do + # This only works on 2016 + servers, Server 2012r2 does not dispose + # of com objects when called from a cmd style script for IIS User + # https://serverfault.com/questions/587305/powershell-has-stopped-working-on-ps-exit-after-creating-iis-user + if node['os_version'].to_f < 10.0 + Chef::Log.warn('IIS Manager Permission requires Windows 2016 or newer, Skipping') + return + end + # user permissions are accessed by .Net API + all_users = (new_resource.users + new_resource.groups).map { |i| "\"#{i}\"" }.join ',' + + unless new_resource.users.count == 0 + set_users = <<-EOH + foreach ($principal in #{new_resource.users.map { |i| "\"#{i}\"" }.join ','}) + { + if (($current | Where-Object { $_.Name -eq $principal -and -not $_.IsRole }) -eq $null) + { + [Microsoft.Web.Management.Server.ManagementAuthorization]::Grant($principal, "#{new_resource.config_path}", $false) + } + } + EOH + end + + unless new_resource.groups.count == 0 + set_groups = <<-EOH + foreach ($principal in #{new_resource.groups.map { |i| "\"#{i}\"" }.join ','}) + { + if (($current | Where-Object { $_.Name -eq $principal -and $_.IsRole }) -eq $null) + { + [Microsoft.Web.Management.Server.ManagementAuthorization]::Grant($principal, "#{new_resource.config_path}", $true) + } + } + EOH + end + + powershell_script "Set permissions for Path #{new_resource.config_path}" do + code <<-EOH + [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Management") | Out-Null + $current = [Microsoft.Web.Management.Server.ManagementAuthorization]::GetAuthorizedUsers("#{new_resource.config_path}", $false, 0, 1000) + + #{set_users} + #{set_groups} + + # Delete entries not in current definition + $current | Where-Object { $_.Name -notin #{all_users} } | ` + Foreach-Object { [Microsoft.Web.Management.Server.ManagementAuthorization]::Revoke($_.Name, "#{new_resource.config_path}") } + EOH + only_if <<-EOH + [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Management") | Out-Null + $current = [Microsoft.Web.Management.Server.ManagementAuthorization]::GetAuthorizedUsers("#{new_resource.config_path}", $false, 0, 1000) + $current.Count -ne #{new_resource.users.count + new_resource.groups.count} -or ($current | Where-Object { $_.Name -in #{all_users} }).Count -ne #{new_resource.users.count + new_resource.groups.count} + EOH + notifies :restart, 'service[WMSVC]', :delayed + end + + service 'WMSVC' do + action :nothing + end +end diff --git a/cookbooks/iis/resources/module.rb b/cookbooks/iis/resources/module.rb new file mode 100644 index 00000000..56ea0b32 --- /dev/null +++ b/cookbooks/iis/resources/module.rb @@ -0,0 +1,133 @@ +# +# Cookbook:: iis +# Resource:: module +# +# Copyright:: 2017-2019, 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. +# + +include IISCookbook::Helper +include IISCookbook::Processors +include IISCookbook::SectionHelper + +property :module_name, String, name_property: true +property :type, String +property :add, [true, false], default: false +property :image, String +property :precondition, String +property :application, String +property :previous_lock, String + +load_current_value do |desired| + module_name desired.module_name + application desired.application if desired.application + # Sanitize Image Path (file system path) + desired.image = windows_cleanpath(desired.image) if desired.image + cmd = "#{appcmd(node)} list module /module.name:\"#{desired.module_name}\"" + cmd << " /app.name:\"#{desired.application}\"" if desired.application + + cmd_result = shell_out cmd + # 'MODULE "Module Name" ( type:module.type, preCondition:condition )' + # 'MODULE "Module Name" ( native, preCondition:condition )' + + Chef::Log.debug("#{desired.name} list module command output: #{cmd_result.stdout}") + unless cmd_result.stdout.empty? + previous_lock get_current_lock(node, 'system.webServer/modules', desired.application) + cmd = "#{appcmd(node)} list module /module.name:\"#{desired.module_name}\"" + cmd << " /app.name:\"#{desired.application}\"" if desired.application + cmd << ' /config:* /xml' + cmd_result = shell_out cmd + if cmd_result.stderr.empty? + xml = cmd_result.stdout + doc = Document.new(xml) + type value doc.root, 'MODULE/@type' + precondition value doc.root, 'MODULE/@preCondition' + end + end +end + +# appcmd syntax for adding modules +# appcmd add module /name:string /type:string /preCondition:string +action :add do + if exists + Chef::Log.debug("#{new_resource} module already exists - nothing to do") + else + converge_by("add IIS module #{new_resource.module_name}") do + unlock(node, 'system.webServer/modules', new_resource.application) + cmd = "#{appcmd(node)} add module /module.name:\"#{new_resource.module_name}\"" + cmd << " /app.name:\"#{new_resource.application}\"" if new_resource.application + cmd << " /type:\"#{new_resource.type}\"" if new_resource.type + cmd << " /preCondition:\"#{new_resource.precondition}\"" if new_resource.precondition + + shell_out!(cmd, returns: [0, 42]) + override_mode(node, current_resource.previous_lock, 'system.webServer/modules', new_resource.application) + end + end +end + +action :delete do + if exists + converge_by("delete IIS module #{new_resource.module_name}") do + unlock(node, 'system.webServer/modules', new_resource.application) + cmd = "#{appcmd(node)} delete module /module.name:\"#{new_resource.module_name}\"" + cmd << " /app.name:\"#{new_resource.application}\"" if new_resource.application + + shell_out!(cmd, returns: [0, 42]) + override_mode(node, current_resource.previous_lock, 'system.webServer/modules', new_resource.application) + end + else + Chef::Log.debug("#{new_resource} module does not exist - nothing to do") + end +end + +# appcmd syntax for installing native modules +# appcmd install module /name:string /add:string(true|false) /image:string +action :install do + if exists + Chef::Log.debug("#{new_resource} module already exists - nothing to do") + else + converge_by("install IIS module #{new_resource.module_name}") do + unlock(node, 'system.webServer/modules', new_resource.application) + cmd = "#{appcmd(node)} install module /name:\"#{new_resource.module_name}\"" + cmd << " /add:\"#{new_resource.add}\"" unless new_resource.add.nil? + cmd << " /image:\"#{new_resource.image}\"" if new_resource.image + cmd << " /preCondition:\"#{new_resource.precondition}\"" if new_resource.precondition + + shell_out!(cmd, returns: [0, 42]) + override_mode(node, current_resource.previous_lock, 'system.webServer/modules', new_resource.application) + end + end +end + +# appcmd syntax for uninstalling native modules +# appcmd uninstall module +action :uninstall do + if exists + converge_by("uninstall IIS module #{new_resource.module_name}") do + unlock(node, 'system.webServer/modules', new_resource.application) + cmd = "#{appcmd(node)} uninstall module \"#{new_resource.module_name}\"" + + shell_out!(cmd, returns: [0, 42]) + override_mode(node, current_resource.previous_lock, 'system.webServer/modules', new_resource.application) + end + else + Chef::Log.debug("#{new_resource} module does not exists - nothing to do") + end +end + +action_class.class_eval do + def exists + current_resource.type ? true : false + end +end diff --git a/cookbooks/iis/resources/pool.rb b/cookbooks/iis/resources/pool.rb new file mode 100644 index 00000000..7967e764 --- /dev/null +++ b/cookbooks/iis/resources/pool.rb @@ -0,0 +1,471 @@ +# +# Cookbook:: iis +# Resource:: pool +# +# Copyright:: 2017-2019, 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. +# + +require 'rexml/document' + +include REXML +include IISCookbook::Helper +include IISCookbook::Processors + +property :pool_name, String, name_property: true + +# root +property :no_managed_code, [true, false], default: false +property :pipeline_mode, [Symbol, String], equal_to: [:Integrated, :Classic], coerce: proc { |v| v.to_sym } +property :runtime_version, String + +# add items +property :start_mode, [Symbol, String], equal_to: [:AlwaysRunning, :OnDemand], default: :OnDemand, coerce: proc { |v| v.to_sym } +property :auto_start, [true, false], default: true +property :queue_length, Integer, default: 1000, coerce: proc { |v| v.to_i } +property :thirty_two_bit, [true, false], default: false + +# processModel items +property :max_processes, Integer, coerce: proc { |v| v.to_i } +property :load_user_profile, [true, false], default: false +property :identity_type, [Symbol, String], equal_to: [:SpecificUser, :NetworkService, :LocalService, :LocalSystem, :ApplicationPoolIdentity], default: :ApplicationPoolIdentity, coerce: proc { |v| v.to_sym } +property :username, String +property :password, String, sensitive: true +property :logon_type, [Symbol, String], equal_to: [:LogonBatch, :LogonService], default: :LogonBatch, coerce: proc { |v| v.to_sym } +property :manual_group_membership, [true, false], default: false +property :idle_timeout, String, default: '00:20:00' +property :idle_timeout_action, [Symbol, String], equal_to: [:Terminate, :Suspend], default: :Terminate, coerce: proc { |v| v.to_sym } +property :shutdown_time_limit, String, default: '00:01:30' +property :startup_time_limit, String, default: '00:01:30' +property :pinging_enabled, [true, false], default: true +property :ping_interval, String, default: '00:00:30' +property :ping_response_time, String, default: '00:01:30' + +# recycling items +property :disallow_rotation_on_config_change, [true, false], default: false +property :disallow_overlapping_rotation, [true, false], default: false +property :recycle_schedule_clear, [true, false], default: false +property :log_event_on_recycle, String, default: node['iis']['recycle']['log_events'] +property :recycle_after_time, String +property :periodic_restart_schedule, [Array, String], default: [], coerce: proc { |v| [*v].sort } +property :private_memory, Integer, coerce: proc { |v| v.to_i } +property :virtual_memory, Integer, coerce: proc { |v| v.to_i } + +# failure items +property :load_balancer_capabilities, [Symbol, String], equal_to: [:HttpLevel, :TcpLevel], default: :HttpLevel, coerce: proc { |v| v.to_sym } +property :orphan_worker_process, [true, false], default: false +property :orphan_action_exe, String +property :orphan_action_params, String +property :rapid_fail_protection, [true, false], default: true +property :rapid_fail_protection_interval, String, default: '00:05:00' +property :rapid_fail_protection_max_crashes, Integer, default: 5, coerce: proc { |v| v.to_i } +property :auto_shutdown_exe, String +property :auto_shutdown_params, String + +# cpu items +property :cpu_action, [Symbol, String], equal_to: [:NoAction, :KillW3wp, :Throttle, :ThrottleUnderLoad], default: :NoAction, coerce: proc { |v| v.to_sym } +property :cpu_limit, Integer, default: 0, coerce: proc { |v| v.to_i } +property :cpu_reset_interval, String, default: '00:05:00' +property :cpu_smp_affinitized, [true, false], default: false +property :smp_processor_affinity_mask, Float, default: 4_294_967_295.0, coerce: proc { |v| v.to_f } +property :smp_processor_affinity_mask_2, Float, default: 4_294_967_295.0, coerce: proc { |v| v.to_f } + +# environment variables +property :environment_variables, [Array, String], coerce: proc { |v| [*v].sort } + +# internally used for the state of the pool [Starting, Started, Stopping, Stopped, Unknown, Undefined value] +property :running, [true, false] + +# Alias property until the next major release +alias_method :recycle_at_time, :periodic_restart_schedule + +load_current_value do |desired| + cmd = shell_out("#{appcmd(node)} list apppool \"#{desired.pool_name}\"") + # APPPOOL "DefaultAppPool" (MgdVersion:v2.0,MgdMode:Integrated,state:Started) + Chef::Log.debug("#{desired} list apppool command output: #{cmd.stdout}") + unless cmd.stderr.empty? + Chef::Log.warn "Failed to run iis_pool action :load_current_resource, #{cmd.stderr}" + return + end + + result = cmd.stdout.gsub(/\r\n?/, "\n") # ensure we have no carriage returns + result = result.match(/^APPPOOL\s\"(#{desired.pool_name})\"\s\(MgdVersion:(.*),MgdMode:(.*),state:(.*)\)$/i) + Chef::Log.debug("#{desired} current_resource match output: #{result}") + unless result + running false + return + end + + running result[4] =~ /Started/ ? true : false + cmd_current_values = "#{appcmd(node)} list apppool \"#{desired.pool_name}\" /config:* /xml" + Chef::Log.debug(cmd_current_values) + cmd_current_values = shell_out(cmd_current_values) + if cmd_current_values.stderr.empty? + xml = cmd_current_values.stdout + doc = Document.new(xml) + + # root items + runtime_version value(doc.root, 'APPPOOL/@RuntimeVersion').gsub(/^v/, '') + pipeline_mode value(doc.root, 'APPPOOL/@PipelineMode').to_sym + + # add items + auto_start bool(value(doc.root, 'APPPOOL/add/@autoStart')) if iis_version >= 7.0 + start_mode value(doc.root, 'APPPOOL/add/@startMode').to_sym if iis_version > 7.0 + queue_length value(doc.root, 'APPPOOL/add/@queueLength').to_i + thirty_two_bit bool(value(doc.root, 'APPPOOL/add/@enable32BitAppOnWin64')) + + # processModel items + max_processes value(doc.root, 'APPPOOL/add/processModel/@maxProcesses').to_i + load_user_profile bool(value(doc.root, 'APPPOOL/add/processModel/@loadUserProfile')) + identity_type value(doc.root, 'APPPOOL/add/processModel/@identityType').to_sym if iis_version > 7.0 + username value doc.root, 'APPPOOL/add/processModel/@userName' + unless username.nil? || desired.username.nil? + Chef::Log.info('username: ' + username + ' -> ' + desired.username) + end + password value doc.root, 'APPPOOL/add/processModel/@password' + logon_type value(doc.root, 'APPPOOL/add/processModel/@logonType').to_sym if iis_version > 7.0 + manual_group_membership bool(value(doc.root, 'APPPOOL/add/processModel/@manualGroupMembership')) + idle_timeout value doc.root, 'APPPOOL/add/processModel/@idleTimeout' + idle_timeout_action value(doc.root, 'APPPOOL/add/processModel/@idleTimeoutAction').to_sym if iis_version >= 8.5 + shutdown_time_limit value doc.root, 'APPPOOL/add/processModel/@shutdownTimeLimit' + startup_time_limit value doc.root, 'APPPOOL/add/processModel/@startupTimeLimit' + pinging_enabled bool(value(doc.root, 'APPPOOL/add/processModel/@pingingEnabled')) + ping_interval value doc.root, 'APPPOOL/add/processModel/@pingInterval' + ping_response_time value doc.root, 'APPPOOL/add/processModel/@pingResponseTime' + + # recycling items + disallow_overlapping_rotation bool(value(doc.root, 'APPPOOL/add/recycling/@disallowOverlappingRotation')) + disallow_rotation_on_config_change bool(value(doc.root, 'APPPOOL/add/recycling/@disallowRotationOnConfigChange')) + recycle_after_time value doc.root, 'APPPOOL/add/recycling/periodicRestart/@time' + periodic_restart_schedule get_value(doc.root, 'APPPOOL/add/recycling/periodicRestart/schedule/add/@value').map(&:value) + private_memory value(doc.root, 'APPPOOL/add/recycling/periodicRestart/@privateMemory').to_i + virtual_memory value(doc.root, 'APPPOOL/add/recycling/periodicRestart/@memory').to_i + log_event_on_recycle value doc.root, 'APPPOOL/add/recycling/@logEventOnRecycle' + + # failure items + load_balancer_capabilities value(doc.root, 'APPPOOL/add/failure/@loadBalancerCapabilities').to_sym + orphan_worker_process bool(value(doc.root, 'APPPOOL/add/failure/@orphanWorkerProcess')) + orphan_action_exe value doc.root, 'APPPOOL/add/failure/@orphanActionExe' + orphan_action_params value doc.root, 'APPPOOL/add/failure/@orphanActionParams' + rapid_fail_protection bool(value(doc.root, 'APPPOOL/add/failure/@rapidFailProtection')) + rapid_fail_protection_interval value doc.root, 'APPPOOL/add/failure/@rapidFailProtectionInterval' + rapid_fail_protection_max_crashes value(doc.root, 'APPPOOL/add/failure/@rapidFailProtectionMaxCrashes').to_i + auto_shutdown_exe value doc.root, 'APPPOOL/add/failure/@autoShutdownExe' + auto_shutdown_params value doc.root, 'APPPOOL/add/failure/@autoShutdownParams' + + # cpu items + cpu_action value(doc.root, 'APPPOOL/add/cpu/@action').to_sym + cpu_limit value(doc.root, 'APPPOOL/add/cpu/@limit').to_i + cpu_smp_affinitized bool(value(doc.root, 'APPPOOL/add/cpu/@smpAffinitized')) + cpu_reset_interval value doc.root, 'APPPOOL/add/cpu/@resetInterval' + smp_processor_affinity_mask value(doc.root, 'APPPOOL/add/cpu/@smpProcessorAffinityMask').to_f + smp_processor_affinity_mask_2 value(doc.root, 'APPPOOL/add/cpu/@smpProcessorAffinityMask2').to_f + + # environment variables + environment_variables get_value(doc.root, 'APPPOOL/add/environmentVariables/add').map { |x| "#{value(x, '@name')}=#{value(x, '@value')}" } if iis_version >= 10 + + @node_array = XPath.match(doc.root, 'APPPOOL/add/recycling/periodicRestart/schedule/add') + end +end + +action :add do + if exists + Chef::Log.debug("#{new_resource} pool already exists - nothing to do") + else + converge_by "Created Application Pool \"#{new_resource}\"" do + cmd = "#{appcmd(node)} add apppool /name:\"#{new_resource.pool_name}\"" + if new_resource.no_managed_code + cmd << ' /managedRuntimeVersion:' + elsif new_resource.runtime_version + cmd << " /managedRuntimeVersion:v#{new_resource.runtime_version}" + end + cmd << " /managedPipelineMode:#{new_resource.pipeline_mode.capitalize}" if new_resource.pipeline_mode + cmd << ' /commit:\"MACHINE/WEBROOT/APPHOST\"' + Chef::Log.debug(cmd) + shell_out!(cmd) + configure + end + end +end + +action :config do + configure if exists +end + +action :delete do + if exists + converge_by "Deleted Application Pool \"#{new_resource}\"" do + shell_out!("#{appcmd(node)} delete apppool \"#{new_resource.pool_name}\"") + end + else + Chef::Log.debug("#{new_resource} pool does not exist - nothing to do") + end +end + +action :start do + if exists && !current_resource.running + converge_by "Started Application Pool \"#{new_resource}\"" do + shell_out!("#{appcmd(node)} start apppool \"#{new_resource.pool_name}\"") + end + else + Chef::Log.debug("#{new_resource} already running - nothing to do") + end +end + +action :stop do + if exists && current_resource.running + converge_by "Stopped Application Pool \"#{new_resource}\"" do + shell_out!("#{appcmd(node)} stop apppool \"#{new_resource.pool_name}\"") + end + else + Chef::Log.debug("#{new_resource} already stopped - nothing to do") + end +end + +action :restart do + if exists + converge_by "Restarted Application Pool \"#{new_resource}\"" do + shell_out!("#{appcmd(node)} stop APPPOOL \"#{new_resource.pool_name}\"") if current_resource.running + sleep 2 + shell_out!("#{appcmd(node)} start APPPOOL \"#{new_resource.pool_name}\"") + end + end +end + +action :recycle do + if exists + converge_by "Recycled Application Pool \"#{new_resource}\"" do + shell_out!("#{appcmd(node)} recycle APPPOOL \"#{new_resource.pool_name}\"") if current_resource.running + end + end +end + +action_class.class_eval do + def exists + current_resource.runtime_version ? true : false + end + + def configure + # Application Pool Config + cmd = "#{appcmd(node)} set config /section:applicationPools" + + # root items + if iis_version >= 7.0 + converge_if_changed :auto_start do + cmd << configure_application_pool("autoStart:#{new_resource.auto_start}") + end + end + + if iis_version >= 7.5 + converge_if_changed :start_mode do + cmd << configure_application_pool("startMode:#{new_resource.start_mode}") + end + end + + if new_resource.no_managed_code + converge_if_changed :runtime_version do + cmd << configure_application_pool('managedRuntimeVersion:') + end + else + converge_if_changed :runtime_version do + cmd << configure_application_pool("managedRuntimeVersion:v#{new_resource.runtime_version}") + end + end + + converge_if_changed :pipeline_mode do + cmd << configure_application_pool("managedPipelineMode:#{new_resource.pipeline_mode}") + end + converge_if_changed :thirty_two_bit do + cmd << configure_application_pool("enable32BitAppOnWin64:#{new_resource.thirty_two_bit}") + end + converge_if_changed :queue_length do + cmd << configure_application_pool("queueLength:#{new_resource.queue_length}") + end + + # processModel items + converge_if_changed :max_processes do + cmd << configure_application_pool("processModel.maxProcesses:#{new_resource.max_processes}") + end + converge_if_changed :load_user_profile do + cmd << configure_application_pool("processModel.loadUserProfile:#{new_resource.load_user_profile}") + end + converge_if_changed :logon_type do + cmd << configure_application_pool("processModel.logonType:#{new_resource.logon_type}") + end + converge_if_changed :manual_group_membership do + cmd << configure_application_pool("processModel.manualGroupMembership:#{new_resource.manual_group_membership}") + end + converge_if_changed :idle_timeout do + cmd << configure_application_pool("processModel.idleTimeout:#{new_resource.idle_timeout}") + end + if iis_version >= 8.5 + converge_if_changed :idle_timeout_action do + cmd << configure_application_pool("processModel.idleTimeoutAction:#{new_resource.idle_timeout_action}") + end + end + converge_if_changed :shutdown_time_limit do + cmd << configure_application_pool("processModel.shutdownTimeLimit:#{new_resource.shutdown_time_limit}") + end + converge_if_changed :startup_time_limit do + cmd << configure_application_pool("processModel.startupTimeLimit:#{new_resource.startup_time_limit}") + end + converge_if_changed :pinging_enabled do + cmd << configure_application_pool("processModel.pingingEnabled:#{new_resource.pinging_enabled}") + end + converge_if_changed :ping_interval do + cmd << configure_application_pool("processModel.pingInterval:#{new_resource.ping_interval}") + end + converge_if_changed :ping_response_time do + cmd << configure_application_pool("processModel.pingResponseTime:#{new_resource.ping_response_time}") + end + + converge_if_changed :periodic_restart_schedule do + # Remove the values that are no longer required + ([*current_resource.periodic_restart_schedule] - [*new_resource.periodic_restart_schedule]).each do |periodic_restart| + cmd << configure_application_pool("recycling.periodicRestart.schedule.[value='#{periodic_restart}']", '-') + end + + # Add the new values + ([*new_resource.periodic_restart_schedule] - [*current_resource.periodic_restart_schedule]).each do |periodic_restart| + cmd << configure_application_pool("recycling.periodicRestart.schedule.[value='#{periodic_restart}']", '+') + end + end + + converge_if_changed :recycle_after_time do + cmd << configure_application_pool("recycling.periodicRestart.time:#{new_resource.recycle_after_time}") + end + + converge_if_changed :log_event_on_recycle do + cmd << configure_application_pool("recycling.logEventOnRecycle:#{new_resource.log_event_on_recycle}") + end + converge_if_changed :private_memory do + cmd << configure_application_pool("recycling.periodicRestart.privateMemory:#{new_resource.private_memory}") + end + converge_if_changed :virtual_memory do + cmd << configure_application_pool("recycling.periodicRestart.memory:#{new_resource.virtual_memory}") + end + converge_if_changed :disallow_rotation_on_config_change do + cmd << configure_application_pool("recycling.disallowRotationOnConfigChange:#{new_resource.disallow_rotation_on_config_change}") + end + converge_if_changed :disallow_overlapping_rotation do + cmd << configure_application_pool("recycling.disallowOverlappingRotation:#{new_resource.disallow_overlapping_rotation}") + end + + # failure items + converge_if_changed :load_balancer_capabilities do + cmd << configure_application_pool("failure.loadBalancerCapabilities:#{new_resource.load_balancer_capabilities}") + end + converge_if_changed :orphan_worker_process do + cmd << configure_application_pool("failure.orphanWorkerProcess:#{new_resource.orphan_worker_process}") + end + converge_if_changed :orphan_action_exe do + cmd << configure_application_pool("failure.orphanActionExe:#{new_resource.orphan_action_exe}") + end + converge_if_changed :orphan_action_params do + cmd << configure_application_pool("failure.orphanActionParams:#{new_resource.orphan_action_params}") + end + converge_if_changed :rapid_fail_protection do + cmd << configure_application_pool("failure.rapidFailProtection:#{new_resource.rapid_fail_protection}") + end + converge_if_changed :rapid_fail_protection_interval do + cmd << configure_application_pool("failure.rapidFailProtectionInterval:#{new_resource.rapid_fail_protection_interval}") + end + converge_if_changed :rapid_fail_protection_max_crashes do + cmd << configure_application_pool("failure.rapidFailProtectionMaxCrashes:#{new_resource.rapid_fail_protection_max_crashes}") + end + converge_if_changed :auto_shutdown_exe do + cmd << configure_application_pool("failure.autoShutdownExe:#{new_resource.auto_shutdown_exe}") + end + converge_if_changed :auto_shutdown_params do + cmd << configure_application_pool("failure.autoShutdownParams:#{new_resource.auto_shutdown_params}") + end + + # cpu items + converge_if_changed :cpu_action do + cmd << configure_application_pool("cpu.action:#{new_resource.cpu_action}") + end + converge_if_changed :cpu_limit do + cmd << configure_application_pool("cpu.limit:#{new_resource.cpu_limit}") + end + converge_if_changed :cpu_reset_interval do + cmd << configure_application_pool("cpu.resetInterval:#{new_resource.cpu_reset_interval}") + end + converge_if_changed :cpu_smp_affinitized do + cmd << configure_application_pool("cpu.smpAffinitized:#{new_resource.cpu_smp_affinitized}") + end + converge_if_changed :smp_processor_affinity_mask do + cmd << configure_application_pool("cpu.smpProcessorAffinityMask:#{new_resource.smp_processor_affinity_mask.floor}") + end + converge_if_changed :smp_processor_affinity_mask_2 do + cmd << configure_application_pool("cpu.smpProcessorAffinityMask2:#{new_resource.smp_processor_affinity_mask_2.floor}") + end + + # environment variables + if iis_version >= 10 + converge_if_changed :environment_variables do + # Remove the values that are no longer required + ([*current_resource.environment_variables] - [*new_resource.environment_variables]).each do |environment_variable| + cmd << configure_application_pool("environmentVariables.[name='#{environment_variable.split('=', 2)[0]}',value='#{environment_variable.split('=', 2)[1]}']", '-') + end + + # Add the new values + ([*new_resource.environment_variables] - [*current_resource.environment_variables]).each do |environment_variable| + cmd << configure_application_pool("environmentVariables.[name='#{environment_variable.split('=', 2)[0]}',value='#{environment_variable.split('=', 2)[1]}']", '+') + end + end + end + + unless current_resource.runtime_version && cmd == "#{appcmd(node)} set config /section:applicationPools" + converge_by "Configured Application Pool \"#{new_resource}\"" do + Chef::Log.debug(cmd) + shell_out!(cmd) + end + end + + # Application Pool Identity Settings + if new_resource.username && new_resource.username != '' + cmd = default_app_pool_user + converge_if_changed :username do + cmd << " \"/[name='#{new_resource.pool_name}'].processModel.userName:#{new_resource.username}\"" + end + converge_if_changed :password do + cmd << " \"/[name='#{new_resource.pool_name}'].processModel.password:#{new_resource.password.gsub(/\"/, '\\\"')}\"" + end + if cmd != default_app_pool_user + converge_by "Configured Application Pool Identity Settings \"#{new_resource}\"" do + Chef::Log.debug(cmd) + shell_out!(cmd) + end + end + elsif new_resource.identity_type != 'SpecificUser' + converge_if_changed :identity_type do + cmd = "#{appcmd(node)} set config /section:applicationPools" + cmd << " \"/[name='#{new_resource.pool_name}'].processModel.identityType:#{new_resource.identity_type}\"" + cmd << " \"/[name='#{new_resource.name}'].processModel.userName:\"" + cmd << " \"/[name='#{new_resource.name}'].processModel.password:\"" + Chef::Log.debug(cmd) + shell_out!(cmd) + end + end + end + + def default_app_pool_user + cmd_default = "#{appcmd(node)} set config /section:applicationPools" + cmd_default << " \"/[name='#{new_resource.pool_name}'].processModel.identityType:SpecificUser\"" + end + + def configure_application_pool(config, add_remove = '') + " \"/#{add_remove}[name='#{new_resource.pool_name}'].#{config}\"" + end +end diff --git a/cookbooks/iis/resources/root.rb b/cookbooks/iis/resources/root.rb new file mode 100644 index 00000000..22b37788 --- /dev/null +++ b/cookbooks/iis/resources/root.rb @@ -0,0 +1,86 @@ +# +# Cookbook:: iis +# Resource:: root +# +# Copyright:: 2017-2019, 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. +# + +include IISCookbook::Constants +include IISCookbook::Helper +include IISCookbook::Processors + +property :default_documents_enabled, [true, false], default: true +property :default_documents, Array, default: IISCookbook::Constants.default_documents +property :mime_maps, Array, default: IISCookbook::Constants.default_mime_types +property :add_default_documents, Array, default: [] +property :add_mime_maps, Array, default: [] +property :delete_default_documents, Array, default: [] +property :delete_mime_maps, Array, default: [] + +load_current_value do |desired| + current_default_documents_object = current_default_documents_config + return unless current_default_documents_object + + current_mime_maps = current_mime_maps_config + return unless current_mime_maps_config + + default_documents_enabled bool(current_default_documents_object[:default_documents_enabled]) + default_documents current_default_documents_object[:default_documents] + mime_maps current_mime_maps + + current_add_default_documents = desired.add_default_documents - current_default_documents_object[:default_documents] + add_default_documents desired.add_default_documents - current_add_default_documents + + delete_default_documents desired.delete_default_documents - current_default_documents_object[:default_documents] + + current_add_mime_maps = desired.add_mime_maps - current_mime_maps + add_mime_maps desired.add_mime_maps - current_add_mime_maps + + delete_mime_maps desired.delete_mime_maps - current_mime_maps +end + +action :config do + converge_if_changed :default_documents_enabled do + set_default_documents_enabled(new_resource.default_documents_enabled) + end + + converge_if_changed :default_documents do + set_default_documents(new_resource.default_documents, current_resource.default_documents) + end + + converge_if_changed :mime_maps do + set_mime_maps(new_resource.mime_maps, current_resource.mime_maps) + end +end + +action :add do + converge_if_changed :add_default_documents do + set_default_documents(new_resource.add_default_documents, current_resource.add_default_documents, true, false) + end + + converge_if_changed :add_mime_maps do + set_mime_maps(new_resource.add_mime_maps, current_resource.add_mime_maps, true, false) + end +end + +action :delete do + converge_if_changed :delete_default_documents do + set_default_documents(new_resource.delete_default_documents, current_resource.delete_default_documents, false, true) + end + + converge_if_changed :delete_mime_maps do + set_mime_maps(new_resource.delete_mime_maps, current_resource.delete_mime_maps, false, true) + end +end diff --git a/cookbooks/iis/resources/section.rb b/cookbooks/iis/resources/section.rb new file mode 100644 index 00000000..08ad2474 --- /dev/null +++ b/cookbooks/iis/resources/section.rb @@ -0,0 +1,71 @@ +# +# Cookbook:: iis +# Resource:: section +# +# Copyright:: 2016-2019, 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. +# + +require 'rexml/document' + +include REXML +include IISCookbook::Helper +include IISCookbook::SectionHelper +include IISCookbook::Processors + +property :section, String, name_property: true +property :site, String +property :application_path, String +property :returns, [Integer, Array], default: 0 +property :locked, String + +load_current_value do |desired| + section desired.section + site desired.site + application_path desired.application_path + command_path = 'MACHINE/WEBROOT/APPHOST' + command_path << "/#{site}" if site + command_path << application_path.to_s if application_path + cmd = "#{appcmd(node)} list config \"#{command_path}\"" + cmd << " -section:\"#{section}\" /commit:apphost /config:* /xml" + Chef::Log.debug(cmd) + cmd = shell_out(cmd) + if cmd.stderr.empty? + xml = cmd.stdout + doc = Document.new(xml) + locked value doc.root, 'CONFIG/@overrideMode' + else + Chef::Log.info(cmd.stderr) + end +end + +action :unlock do + if current_resource.locked != 'Allow' + converge_by "Unlocking the section - \"#{new_resource}\"" do + unlock node, new_resource.section, "#{new_resource.site}#{new_resource.application_path}", new_resource.returns + end + else + Chef::Log.debug("#{new_resource} already unlocked - nothing to do") + end +end + +action :lock do + if current_resource.locked != 'Deny' + converge_by "Locking the section - \"#{new_resource}\"" do + lock node, new_resource.section, "#{new_resource.site}#{new_resource.application_path}", new_resource.returns + end + else + Chef::Log.debug("#{new_resource} already locked - nothing to do") + end +end diff --git a/cookbooks/iis/resources/site.rb b/cookbooks/iis/resources/site.rb new file mode 100644 index 00000000..2ba1255a --- /dev/null +++ b/cookbooks/iis/resources/site.rb @@ -0,0 +1,228 @@ +# +# Cookbook:: iis +# Resource:: site +# +# Copyright:: 2017-2019, 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. +# + +require 'rexml/document' + +include REXML +include IISCookbook::Helper +include IISCookbook::Processors + +property :site_name, String, name_property: true +property :site_id, Integer +property :port, Integer, default: 80, coerce: proc { |v| v.to_i } +property :path, String +property :protocol, [Symbol, String], equal_to: [:http, :https, :ftp], default: :http, coerce: proc { |v| v.to_sym } +property :host_header, String +property :bindings, String +property :application_pool, String +property :options, String, default: '' +property :log_directory, String +property :log_period, [Symbol, String], equal_to: [:Daily, :Hourly, :MaxSize, :Monthly, :Weekly], default: :Daily, coerce: proc { |v| v.to_sym } +property :log_truncsize, Integer, default: 1_048_576 +property :running, [true, false] + +load_current_value do |desired| + site_name desired.site_name + # Sanitize windows file system path + desired.path = windows_cleanpath(desired.path) if desired.path + desired.log_directory = windows_cleanpath(desired.log_directory) if desired.log_directory + desired.port = desired.port.to_i if desired.port + cmd = shell_out "#{appcmd(node)} list site \"#{site_name}\"" + Chef::Log.debug(appcmd(node)) + # 'SITE "Default Web Site" (id:1,bindings:http/*:80:,state:Started)' + Chef::Log.debug("#{desired} list site command output: #{cmd.stdout}") + if cmd.stderr.empty? + result = cmd.stdout.gsub(/\r\n?/, "\n") # ensure we have no carriage returns + result = result.match(/^SITE\s\"(?#{desired.site_name})\"\s\(id:(?.*),bindings:(?.*),state:(?.*)\)$/i) + Chef::Log.debug("#{desired} current_resource match output: #{result}") + if result + site_id result[:site_id].to_i + bindings result[:bindings] + running result[:state] =~ /Started/ ? true : false + else + running false + end + + if site_id + values = "#{bindings},".match(%r{(?[^,\/]+)\/\*:(?[^:]+):(?[^,]*),?}) + # get current values + cmd = "#{appcmd(node)} list site \"#{site_name}\" /config:* /xml" + Chef::Log.debug(cmd) + cmd = shell_out cmd + if cmd.stderr.empty? + xml = cmd.stdout + doc = Document.new(xml) + path windows_cleanpath(value(doc.root, 'SITE/site/application/virtualDirectory/@physicalPath')) + log_directory windows_cleanpath(value(doc.root, 'SITE/site/logFile/@directory')) + log_period value(doc.root, 'SITE/site/logFile/@period').to_sym + log_truncsize value(doc.root, 'SITE/site/logFile/@truncateSize').to_i + application_pool value doc.root, 'SITE/site/application/@applicationPool' + end + + if values + protocol values[:protocol].to_sym + port values[:port].to_i + host_header values[:host_header] + end + else + running false + end + else + Chef::Log.warn "Failed to run iis_site action :config, #{cmd.stderr}" + end +end + +action :add do + if exists + Chef::Log.debug("#{new_resource} site already exists - nothing to do") + else + converge_by "Created the Site - \"#{new_resource}\"" do + cmd = "#{appcmd(node)} add site /name:\"#{new_resource.site_name}\"" + cmd << " /id:#{new_resource.site_id}" if new_resource.site_id + cmd << " /physicalPath:\"#{new_resource.path}\"" if new_resource.path + if new_resource.bindings + cmd << " /bindings:\"#{new_resource.bindings}\"" + else + cmd << " /bindings:#{new_resource.protocol}/*" + cmd << ":#{new_resource.port}:" if new_resource.port + cmd << new_resource.host_header if new_resource.host_header + end + + # support for additional options -logDir, -limits, -ftpServer, etc... + cmd << " #{new_resource.options}" if new_resource.options + shell_out!(cmd, returns: [0, 42]) + + configure + + if new_resource.application_pool + shell_out!("#{appcmd(node)} set site /site.name:\"#{new_resource.site_name}\" /[path='/'].applicationPool:\"#{new_resource.application_pool}\"", returns: [0, 42]) + end + Chef::Log.info("#{new_resource} added new site '#{new_resource.site_name}'") + end + end +end + +action :config do + configure if exists +end + +action :delete do + if exists + converge_by "Deleted the Site - \"#{new_resource}\"" do + Chef::Log.info("#{appcmd(node)} stop site /site.name:\"#{new_resource.site_name}\"") + shell_out!("#{appcmd(node)} delete site /site.name:\"#{new_resource.site_name}\"", returns: [0, 42]) + end + else + Chef::Log.debug("#{new_resource} site does not exist - nothing to do") + end +end + +action :start do + if exists && !current_resource.running + converge_by "Started the Site - \"#{new_resource}\"" do + shell_out!("#{appcmd(node)} start site /site.name:\"#{new_resource.site_name}\"", returns: [0, 42]) + end + else + Chef::Log.debug("#{new_resource} already running - nothing to do") + end +end + +action :stop do + if exists && current_resource.running + converge_by "Stopped the Site - \"#{new_resource}\"" do + Chef::Log.info("#{appcmd(node)} stop site /site.name:\"#{new_resource.site_name}\"") + shell_out!("#{appcmd(node)} stop site /site.name:\"#{new_resource.site_name}\"", returns: [0, 42]) + end + else + Chef::Log.debug("#{new_resource} already stopped - nothing to do") + end +end + +action :restart do + converge_by "Restarted the Site - \"#{new_resource}\"" do + shell_out!("#{appcmd(node)} stop site /site.name:\"#{new_resource.site_name}\"", returns: [0, 42]) if current_resource.running + sleep 2 + shell_out!("#{appcmd(node)} start site /site.name:\"#{new_resource.site_name}\"", returns: [0, 42]) + end +end + +action_class.class_eval do + def exists + current_resource.site_id ? true : false + end + + def configure + if new_resource.bindings + converge_if_changed :bindings do + cmd = "#{appcmd(node)} set site /site.name:\"#{new_resource.site_name}\"" + cmd << " /bindings:\"#{new_resource.bindings}\"" + Chef::Log.debug(cmd) + shell_out!(cmd) + end + elsif new_resource.port || new_resource.host_header || new_resource.protocol + converge_if_changed :host_header, :protocol, :port do + cmd = "#{appcmd(node)} set site \"#{new_resource.site_name}\"" + cmd << " /bindings:#{new_resource.protocol}/*:#{new_resource.port}:#{new_resource.host_header}" + Chef::Log.debug(cmd) + shell_out!(cmd) + end + end + + converge_if_changed :application_pool do + cmd = "#{appcmd(node)} set app \"#{new_resource.site_name}/\" /applicationPool:\"#{new_resource.application_pool}\"" + Chef::Log.debug(cmd) + shell_out!(cmd, returns: [0, 42]) + end + + converge_if_changed :path do + cmd = "#{appcmd(node)} set vdir \"#{new_resource.site_name}/\"" + cmd << " /physicalPath:\"#{new_resource.path}\"" + Chef::Log.debug(cmd) + shell_out!(cmd) + end + + converge_if_changed :site_id do + cmd = "#{appcmd(node)} set site \"#{new_resource.site_name}\"" + cmd << " /id:#{new_resource.site_id}" + Chef::Log.debug(cmd) + shell_out!(cmd) + end + + converge_if_changed :log_directory do + cmd = "#{appcmd(node)} set site \"#{new_resource.site_name}\"" + cmd << " /logFile.directory:#{new_resource.log_directory}" + Chef::Log.debug(cmd) + shell_out!(cmd) + end + + converge_if_changed :log_period do + cmd = "#{appcmd(node)} set site \"#{new_resource.site_name}\"" + cmd << " /logFile.period:#{new_resource.log_period}" + Chef::Log.debug(cmd) + shell_out!(cmd) + end + + converge_if_changed :log_truncsize do + cmd = "#{appcmd(node)} set site \"#{new_resource.site_name}\"" + cmd << " /logFile.truncateSize:#{new_resource.log_truncsize}" + Chef::Log.debug(cmd) + shell_out!(cmd) + end + end +end diff --git a/cookbooks/iis/resources/vdir.rb b/cookbooks/iis/resources/vdir.rb new file mode 100644 index 00000000..2ca11d16 --- /dev/null +++ b/cookbooks/iis/resources/vdir.rb @@ -0,0 +1,142 @@ +# +# Cookbook:: iis +# Resource:: vdir +# +# Copyright:: 2016-2019, 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. +# + +require 'rexml/document' + +include REXML +include IISCookbook::Helper +include IISCookbook::Processors + +property :application_name, String, name_property: true +property :path, String +property :physical_path, String +property :username, String +property :password, String, sensitive: true +property :logon_method, [Symbol, String], default: :ClearText, equal_to: [:Interactive, :Batch, :Network, :ClearText], coerce: proc { |v| v.to_sym } +property :allow_sub_dir_config, [true, false], default: true + +load_current_value do |desired| + # Sanitize Application Name + desired.application_name = application_cleanname(desired.application_name) + # Sanitize Physical Path + desired.physical_path = windows_cleanpath(desired.physical_path) if desired.physical_path + application_name desired.application_name + path desired.path + cmd = shell_out("#{appcmd(node)} list vdir \"#{application_name.chomp('/') + path}\"") + Chef::Log.debug("#{desired} list vdir command output: #{cmd.stdout}") + + if cmd.stderr.empty? + # VDIR "Testfu Site/Content/Test" + result = cmd.stdout.match(/^VDIR\s\"#{Regexp.escape(application_name.chomp('/') + path)}\"/) + Chef::Log.debug("#{desired} current_resource match output: #{result}") + unless result.nil? + cmd = shell_out("#{appcmd(node)} list vdir \"#{application_name.chomp('/') + path}\" /config:* /xml") + if cmd.stderr.empty? + xml = cmd.stdout + doc = Document.new(xml) + physical_path windows_cleanpath(value(doc.root, 'VDIR/@physicalPath')) + username value doc.root, 'VDIR/virtualDirectory/@userName' + password value doc.root, 'VDIR/virtualDirectory/@password' + logon_method value(doc.root, 'VDIR/virtualDirectory/@logonMethod').to_sym + allow_sub_dir_config bool(value(doc.root, 'VDIR/virtualDirectory/@allowSubDirConfig')) + end + end + else + Chef::Log.warn "Failed to run iis_vdir action :load_current_resource, #{cmd.stderr}" + end +end + +action :add do + if exists + Chef::Log.debug("#{new_resource} virtual directory already exists - nothing to do") + else + converge_by "Created the VDIR - \"#{new_resource}\"" do + cmd = "#{appcmd(node)} add vdir /app.name:\"#{vdir_identifier}\"" + cmd << " /path:\"#{new_resource.path}\"" + cmd << " /physicalPath:\"#{new_resource.physical_path}\"" + cmd << " /userName:\"#{new_resource.username}\"" if new_resource.username + cmd << " /password:\"#{new_resource.password}\"" if new_resource.password + cmd << " /logonMethod:#{new_resource.logon_method}" if new_resource.logon_method + cmd << " /allowSubDirConfig:#{new_resource.allow_sub_dir_config}" if new_resource.allow_sub_dir_config + cmd << ' /commit:\"MACHINE/WEBROOT/APPHOST\"' + + Chef::Log.debug(cmd) + shell_out!(cmd, returns: [0, 42, 183]) + end + end +end + +action :config do + if exists + cmd = "#{appcmd(node)} set vdir \"#{application_identifier}\"" + converge_if_changed :physical_path do + cmd << " /physicalPath:\"#{new_resource.physical_path}\"" + end + + converge_if_changed :username do + cmd << " /userName:\"#{new_resource.username}\"" + end + + converge_if_changed :password do + cmd << " /password:\"#{new_resource.password}\"" + end + + converge_if_changed :logon_method do + cmd << " /logonMethod:#{new_resource.logon_method}" + end + + converge_if_changed :allow_sub_dir_config do + cmd << " /allowSubDirConfig:#{new_resource.allow_sub_dir_config}" + end + + if cmd != "#{appcmd(node)} set vdir \"#{application_identifier}\"" + converge_by "Updated the VDIR - \"#{new_resource}\"" do + Chef::Log.debug(cmd) + shell_out!(cmd) + end + else + Chef::Log.debug("#{new_resource} virtual directory - nothing changed") + end + end +end + +action :delete do + if exists + converge_by "Deleted the VDIR - \"#{new_resource}\"" do + Chef::Log.debug("#{appcmd(node)} delete vdir \"#{application_identifier}\"") + shell_out!("#{appcmd(node)} delete vdir \"#{application_identifier}\"", returns: [0, 42]) + end + else + Chef::Log.debug("#{new_resource} virtual directory does not exist - nothing to do") + end +end + +action_class.class_eval do + def exists + current_resource.physical_path ? true : false + end + + def application_identifier + new_resource.path.start_with?('/') ? vdir_identifier.chomp('/') + new_resource.path : vdir_identifier + new_resource.path + end + + def vdir_identifier + new_resource.application_name.include?('/') ? new_resource.application_name : new_resource.application_name + '/' + end +end diff --git a/cookbooks/iis/spec/spec_helper.rb b/cookbooks/iis/spec/spec_helper.rb new file mode 100644 index 00000000..64b86eb4 --- /dev/null +++ b/cookbooks/iis/spec/spec_helper.rb @@ -0,0 +1,10 @@ +require 'chefspec' +require 'chefspec/berkshelf' + +RSpec.configure do |config| + config.color = true # Use color in STDOUT + config.formatter = :documentation # Use the specified formatter + config.log_level = :error # Avoid deprecation notice SPAM + config.platform = 'windows' + config.version = '2012R2' +end diff --git a/cookbooks/iis/spec/unit/recipes/default_spec.rb b/cookbooks/iis/spec/unit/recipes/default_spec.rb new file mode 100644 index 00000000..3a5fcd88 --- /dev/null +++ b/cookbooks/iis/spec/unit/recipes/default_spec.rb @@ -0,0 +1,57 @@ +# +# Cookbook:: iis +# Spec:: default +# +# Copyright:: 2015-2019, 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. + +require 'spec_helper' + +describe 'iis::default' do + context 'when iis components provided, on an unspecified platform' do + let(:chef_run) do + ChefSpec::SoloRunner.new do |node| + node.override['iis']['components'] = ['foobar'] + end.converge(described_recipe) + end + + it 'installs windows feature foobar' do + expect(chef_run).to install_iis_install('install IIS').with(additional_components: ['foobar']) + end + + it 'installs windows feature foobar with source' do + chef_run.node.override['iis']['source'] = 'somesource' + chef_run.converge(described_recipe) + expect(chef_run).to install_iis_install('install IIS').with(source: 'somesource') + end + end + + context 'When all attributes are default, on an unspecified platform' do + cached(:chef_run) do + ChefSpec::SoloRunner.new.converge(described_recipe) + end + + it 'converges successfully' do + expect { chef_run }.to_not raise_error + end + + it 'enables iis service with name W3WVC' do + expect(chef_run).to enable_service('iis').with(service_name: 'W3SVC') + end + + it 'starts iis service with name W3WVC' do + expect(chef_run).to start_service('iis').with(service_name: 'W3SVC') + end + end +end diff --git a/cookbooks/iis/spec/unit/recipes/remove_default_site_spec.rb b/cookbooks/iis/spec/unit/recipes/remove_default_site_spec.rb new file mode 100644 index 00000000..3712c0c9 --- /dev/null +++ b/cookbooks/iis/spec/unit/recipes/remove_default_site_spec.rb @@ -0,0 +1,43 @@ +# +# Cookbook:: iis +# Spec:: default +# +# Copyright:: 2015-2019, 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. + +require 'spec_helper' + +describe 'iis::remove_default_site' do + context 'When all attributes are default, on an unspecified platform' do + let(:chef_run) do + ChefSpec::SoloRunner.new.converge(described_recipe) + end + + it 'stops default site' do + expect(chef_run).to stop_iis_site('Default Web Site') + end + + it 'deletes default site' do + expect(chef_run).to delete_iis_site('Default Web Site') + end + + it 'stops default app pool' do + expect(chef_run).to stop_iis_pool('DefaultAppPool') + end + + it 'deletes default app pool ' do + expect(chef_run).to delete_iis_pool('DefaultAppPool') + end + end +end diff --git a/cookbooks/iis/tasks/maintainers.rb b/cookbooks/iis/tasks/maintainers.rb new file mode 100644 index 00000000..82607c2b --- /dev/null +++ b/cookbooks/iis/tasks/maintainers.rb @@ -0,0 +1,75 @@ +# +# Copyright:: 2015-2019, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +require 'rake' + +SOURCE = File.join(File.dirname(__FILE__), '..', 'MAINTAINERS.toml') +TARGET = File.join(File.dirname(__FILE__), '..', 'MAINTAINERS.md') + +begin + require 'tomlrb' + task default: 'maintainers:generate' + + namespace :maintainers do + desc 'Generate MarkDown version of MAINTAINERS file' + task :generate do + @toml = Tomlrb.load_file SOURCE + out = "\n\n" + + out << preamble + out << project_lieutenant + out << all_maintainers + + File.open(TARGET, 'w') do |fn| + fn.write out + end + end + end +rescue LoadError + STDERR.puts "\n*** TomlRb not available. Skipping the Maintainers Rake task\n\n" +end + +private + +def preamble + <<-EOL +# #{@toml['Preamble']['title']} +#{@toml['Preamble']['text']} + EOL +end + +def project_lieutenant + <<-EOL +# #{@toml['Org']['Components']['Core']['title']} +#{github_link(@toml['Org']['Components']['Core']['lieutenant'])} + + EOL +end + +def all_maintainers + text = "# Maintainers\n" + @toml['Org']['Components']['Core']['maintainers'].each do |m| + text << "#{github_link(m)}\n" + end + text +end + +def github_link(person) + name = @toml['people'][person]['name'] + github = @toml['people'][person]['github'] + "* [#{name}](https://github.com/#{github})" +end diff --git a/cookbooks/iis/test/cookbooks/test/chefignore b/cookbooks/iis/test/cookbooks/test/chefignore new file mode 100644 index 00000000..ca6a59af --- /dev/null +++ b/cookbooks/iis/test/cookbooks/test/chefignore @@ -0,0 +1,100 @@ +# Put files/directories that should be ignored in this file when uploading +# to a chef-server or supermarket. +# Lines that start with '# ' are comments. + +# OS generated files # +###################### +.DS_Store +Icon? +nohup.out +ehthumbs.db +Thumbs.db + +# SASS # +######## +.sass-cache + +# EDITORS # +########### +\#* +.#* +*~ +*.sw[a-z] +*.bak +REVISION +TAGS* +tmtags +*_flymake.* +*_flymake +*.tmproj +.project +.settings +mkmf.log + +## COMPILED ## +############## +a.out +*.o +*.pyc +*.so +*.com +*.class +*.exe +*/rdoc/ + +# Testing # +########### +.watchr +.rspec +spec/* +spec/fixtures/* +test/* +features/* +examples/* +Guardfile +Procfile +.kitchen* +.rubocop.yml +spec/* +Rakefile +.travis.yml +.foodcritic +.codeclimate.yml + +# SCM # +####### +.git +*/.git +.gitignore +.gitmodules +.gitconfig +.gitattributes +.svn +*/.bzr/* +*/.hg/* +*/.svn/* + +# Berkshelf # +############# +Berksfile +Berksfile.lock +cookbooks/* +tmp + +# Cookbooks # +############# +CONTRIBUTING* +CHANGELOG* +TESTING* + +# Strainer # +############ +Colanderfile +Strainerfile +.colander +.strainer + +# Vagrant # +########### +.vagrant +Vagrantfile diff --git a/cookbooks/iis/test/cookbooks/test/files/default/F5XFFHttpModule/x64/F5XFFHttpModule.dll b/cookbooks/iis/test/cookbooks/test/files/default/F5XFFHttpModule/x64/F5XFFHttpModule.dll new file mode 100644 index 0000000000000000000000000000000000000000..29746dc2a3573bc76ef608ded8ea33ce824218e3 GIT binary patch literal 70144 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 literal 0 HcmV?d00001 diff --git a/cookbooks/iis/test/cookbooks/test/files/default/F5XFFHttpModule/x86/F5XFFHttpModule.dll b/cookbooks/iis/test/cookbooks/test/files/default/F5XFFHttpModule/x86/F5XFFHttpModule.dll new file mode 100644 index 0000000000000000000000000000000000000000..bc08561020278bacd1f7a9f414bf5b07a0fea512 GIT binary patch literal 65024 zcmeFaeSB2awLg3&bCR6Egc&r!AVC5|#Re@pM2SOmc$pBDz=W6y5dwGxI!3D)&Iwpa zNIZ$=WIIY*+iP#Nm5W+i+g{sR#g}42FawCni`6JpW1HF?Cs#vBlK^AR^IiMQBmphA z&*yi4pXZ+^Fmuj+UwiGf)?RzdnF1H)d_9y8ByIw|+b8wp;JI>uxpc-_~VSX?JDaeplAQr6pP4zI*Mu zD^gR(WXGzmUN`5%tK@(Y|9G~v8B-DVZ26Gw6==xNWN)fx|V@aATl5NrpDEgJZESvP&n6JcsC8Fj1 zv&QC0NkY+o`geu8ZnKKi|7^w=!AE_i!5;OOB}r?ps9JlgdaER@D?q}N_!Q!^4WChe zUNn7$l})O<5DC5bjKik`pHY8aNou*GYGc)Hh!cHv0YE|$a54JNOZ8Q)yYp^j+?$3J z>c|8V}t|ujz;fv}uQB%FSGJ%qrFX}hbGm%g!g^K!$S*fzjOrMFcpZOF&D~cAI>9efl z(!OPt3Bk3f$|^d!EWc-S|HdQlzcb084? z!Jq(-`}qe$rm637pdmJ%zUDj3gI4DyXTxHUY}iMPAi4LgH;Vc~=p0pY0tAnqM;Y}j zR;JhaQc+*yKIg*|P|EpIX`jB^whY*zJgB#j>h0BQdL?aIrNZw)4f-D0@C~w}LEzKD z5?GOgxy-}e@1ePnuMb$|yje7aHUQjkLsW^gAtXA~TTIz*qin&)s8gkU8J9(;T$MAK zuh-8%1w8s5#qjm$H9e9#i52y<+ay-nyDZoeN5kPS1sWhB)D5> z&=hHS(8PE-fakC;iab(q8&v>Q@T)`x3ZV#1IN1CQ^PoOxb2c6qSm@L5m4T8Y6o{kJ z4_pGh)TXoH8LF+0l6`%wPzJ&W+5Buj_oY%#9gQvOw^>miE0!^0gRC&SIQXo9y>A(R zDN3jT7#JzaVfeFSmGCVNF^H&ay)j=w4vbkGz_ejHssX~HXAE&9BUVGOGu}$EXvGm3 zAI#nn>+^LYNV{e~YD zy>p zonXn21lLg8k+QI_D+^Or*e7NyB6wEX1={HKkBqQFBP@7o%ca3B7$Op)StIGLk#sa4 z>us;3P6Uq`MIEfPV;OH0qa??YnXd=Kyw(6wN>Vv7hhu~}EO~aum|(o?duaZRAsIs& zZtO!hsC-aD0wg=3f`9KkLFci!P~#vn`T3SuY!iUzKebRVvV=mE0evPhp9Mi{h-&pe zP~~!UEfc}^hQxm$d^-zKbbCW;KOT3nA6TLE0ZNNC72HWp%oR;2vD!sT)<~s8+i)!l zb`lafzRdL5qS0PdA#w!!sC*Pb$R+2lMCw#yi6?|k<6C&BcHK@)^pMf?7?>r^ikt1Vc3E4>432ah@qlbj*BYr4~^7>?= z)@WGDe9EeXB0-!KNu^{O$XI?cyJZAT%tW!-Q*V`v`A+~bO-1qCB0u;k=RZdAQ}$Q* z38Zv3ODU4(1T&=yX(0&u?x2I%g+U({?A0~QE?ttE#(W)miwx54;y(h&XE03ByJG&d z7^ajPrPdrq4D+kgab}G;X`%yJE29a0Hs%hX#8t2{6=K>&Zi$MO+;6n_midI1OjGjJR0BA7NT%^V(;US17M3`+pyK7--J zIK?NV*mwn>MQJlV15{w9r{Oz3amCZ?o<4W_nrF_P?)}-h)3csEce?cRbEkLy59uwx zICuFcpF4MY-7n9bzUEiwPWS%$-03s^>)h$C=g*zq`#+?2{N~){cmDR=>5u*H-07QN zICuK;-=8~u){Ey(S6(`IdguR;zH{ff%QwAz?({XUoIAbn)vrrWv-E$gNBW=+S(-4U zDJeHXP?SbVCyp}zW>VyONl=JMbVRDh_)o~)?AIW7&(d1r{P`r(&dI-jIA{7u{b#8} z@%AC=4+(uj(K~G_78B88{v0F_MD1wtAD91BpBF+1;vbqCO%!gt2Oru+%PTV-D|Beh zQ9~?rg3A$$0)GC@zl+Il)btRq@9X9hXn;$UubEHc^VL*p-8Tx})6kT@2Ht-~-o^!N zT;LY<>MvUhxhsN?5%^eY@D0Z;@O{0ki4w73R76L6!=j^vj<{5Y0I$ase5Po|LKgVe zduY7~RU4DI!1IC_+%z=t@t}G5poO;)Vu4T(%{N!Hg`Uc$wnA&OC3j2n!fd64b+mRW z?B;A`U^fO$Qq!BqVC{D8o9a6a`_y79Qj3i3C}VA{e{luIcCaz8n?pmjtd$M8-?aDI zPwK}_z1MWV<8Ie?%k`f~He0=xc`-fIBlNIoNa;zpRmvCdi#W_yL;wjU&5cSGs;xd4%~c~O+S3QcDJ9F{^!Js%IrglhCw zXr4)}$W=)P#9S$!8N z$3CUm1#JVZHyl=%U0WR0ikkgj;(hM5#b0XIH2a6}e#y1PL)z44zlnF(wZ*13R`*5a zyqaj$?#T7d7rmzQ#T(2>0p5o2HWZnQw=ePbW#lTnMe!Dm%&=OEIGbIlCGFbrn#()S z^hNV3qE$WamenivwK-puoG+&2v_}3e;IHVu3RXI11}bgAZO|*(ah?DLJ)G1-#MHj3 zEo`H=?r$Md6bP{6RwBO{QT;x}rX~mY^Nfe}wKxflv3f^(Q_wB)M$6>hP^i)Kf)>z0Ge%Gr@;VjtGy%gY~>v&~Mc zU~x&HY%R;BB8C=)A?5aILQH86QyU~m@7+X_#KF9>-uWd^Zp@R{vV74*Mbz-DHAHi( zSBa`E4n~zxK;mxk`~9XCHMKNTbD315!lM}^hq5popa}S!7}!E$lxYsOL~*~(ogn#2 zDPUHonbi)6Ocbt0d4<1j6j?Qe z;;Y-eVxd6m>jTW^f`-fAn*4JOv-4pykRiyYhz`A1_&=wGjnM?%<}O(39`kvk)m(71gLa|0|6 z_=cvBZwqDORbb7yK%g8E`sQp&8w*TgFnAO;mzd!V*bZS13KAyycCk9jq?rwbb6Y06 zBg^bWYa`$V%2~5i{2tUPT zZBuhFzkJimsr{9GfPC7m`d{qo`6Jno;~G6;)Bc++%yz96DwGvURf5j>kR93ec7wBP`+We`Q>{wE4x?>ac_Sl4X4D-RvhJN*;f!$)dbI=oF zWRGz{B%}V%WIw^%IJ_YmZ?gNasMXy<^*Y=w2Kq&9X#MDfvvCuU8i(4|*_ixQ;OZLz@Wwx(EWe0>d_%R%}> z<6-r7OBZWs(I(WNBFk0PI6Z&!7@JE{6T6pWL62Z3^;2@yl>;B>pV(DL&Y?J2X#H$2 z^f!nTJY0C}*Z*t>fvHI+oJ08W9%zL3vHn!9x^I~jsMc(13E~D_4EPn5$ z;^hL2`?J%m>c^Ui+fb(aSr8Td^BUBhSL4#| z;~!mu5?`E;FNFZA)CUu^a{dcM1k*4DRNDBfz!K{%FZT>M8?FXL2F%=y<5<|_K2K04 zB4@dI5Gut5WdZ&d3YDAbUi3#_BAZ51BqP9QqvPe>r%1jJ+O^~|z7899yn&w41nKEjA=4AIE4D{>k*!Wu$^s>1 z@#)fQx?qw2A@U)HSD`hkqQ%*u$D&GmM3g>c)3PxHS!MnbJ`Ztal~M_xkNoi}lPCs# z>Zhjc+9g!qG^C@DeX7-vIzFCxxP7cLkO$V^uE=DvHYqH{U(6pQ0)U`ghs`39?rz~9 zAkHEc%ttm1$EGVtOu*8GHI0M!pqla+Vzv=t)*?UV3&5l4`3qBQF1xm%Qs&RjLe+$m z06$2tqPuEJz|W6UusqfvhYAU0pi9!OK^u`VDEa6&k=_=7ij#YDk_~Iv#TYO2ZUTP; zkg#4ey$}(8t|4S3mGc?H07DB`Fb$s!C(Exx?XhD3F7fj>PoUqu1p!_Sk|{4Y7Gcs; z&okWs<26?QD2I_Mv*YF(e{m)+C+P#4U6Oj zicz36wy*_qnR+FfxYW=6)b!w@GJcwftQ>PQ;xo*Ra+#mk#@bHN*UM7Gj5dSzAoO6jBWgNLJvR|#Ay2n771V1#P_KQWDOIC#YYP&-cYCW!R-K}q>SbJNe<-`jZ0bve;sO7 zt+E zTv&489jJ~eiBOq#JO#lQ3!1qU;E$!oszn>-L24ioppMclu`z~{fwD@ad{-8TI8@Vl z;%PF0`5ddE`mI6f3i*|~YbEu1vGkHXt!kRy zsuVBdzr|EX1h2~OmPmGgQi7V;pRA~V$BKtZ&)O(tQ@frO(Fy8NYYMT(o)#+-lk$s} zF6dM<@^9Pt?M^L+|CT8G$!)-`)cx6b4Ec77*eN1v9sK(UB~rk|lmnV{1$&7mPhe7H z*k7$s>bJ^uNZy*{+_h1O*x5#`BD(m>;bPXDq@}6ru+XSY^lXy1B=Wb=5NmJkw6mp( zeJ{Jx&^o~%B>8ARSxq-KDnUDfB}g|_o6I99KpYjh(A0YPtGq74RYhrS~r&bt)1Aj>I1~)J((=Y&lbscvSzHdoCqLg$J_*=*?4s8v51U{Y$ox| zpeK3DZ&s~C6)ptIMfq*K>KZFFP?($vqQWQ1$7QApbGND0Q z?ix*$mzRP?4phzzZX*mbs9{*`)Hu*(qoPY+cR*r`V8S?NR%e8Kd;EMeF%g7c2k*u# z&gz;_1s41Ks0ckILI?R<2pP{)8sAL`*voFBGy+IyQZN_58j^{1UI~mMWxQP&P18te zLYBzgP*?aTK!X^Lt*AnOl7<^HISs(o*UEJW5DzRR9$2cdRW5y9Cj@<`r@*l>gI3*b z%rATP*Ltz&-s)im3R`?oDTbIV<3B@>;pjjzo?1g!W26xFVc-BWcwWpIyQhOPOkZc@ zXBI|igKrVw?%;bsKjr*WGNNJMuu1f^Lxc`mJ*~e^(BFK$7F0c#6{O`0q8^toXgWDx zkaV_Qb3oEAB2@?)LUjf&plU&{uuQlD{9+&gni}S%oisLIOatK`HcDZzanTxlzq4UE zcy>;);%r!o7uZQW`!&Y^b)nALFqfjxIrw~RmP6{54x=>cKDwafSw)=(tA)8KgU@nX z!p+(6ca$j!@F~L)pAZTbWf)1UNJv6I?*Y~@@=4uqQc?{pEDEeG4O7%Y&aaBs^9!q< z_lF~Bo7LPD%N*cGkbrqz-n8}FxzlF;2PdRQroJf2sUq0Qkxj+Iq!1waqS12>}* z%4N06R|{bL0e-(#VI+^=7SDPa$_3(qOzLMLh0u<(KN(J7%faTP%tsRW@4*eRu_rBg z9B5NeTruLI7Vn-)6S@-YAoOoQ0GPMXt0uxE1e;2s0{u9&a=gPLq_hAgF9)z&#tWc_ zfXE8fDTUhXN?WKv@e?S|kSU_vkHIeCH4)Q{WW-Y*8kKSzQsUw%pMZ!1wiB#i89Mcv z3`vD{l~EF)`8@y;O*CDTMOu(%4@B&ymc^%{A`@CR*&PG?*C#PSE|P^m0=UnMc&M)g z@l6g<%Rc~vzGntdl?+Y!xz9{9Hr*E&lMt-G4u%Sl)`u9lGS1-%pzo~1JLXOPAwnS$ z;@?TcS}s}5slQH4ebY@X8?XS>Vf$x*`v91}2eR4O$WQ^R$ZJo~+IoMJcBqXw#lj@*JYu^Yh z@9npHwP|P^Jb+rrd^!vPbU%y_+5rr(lvB-Ns=4ZCD^{D`J?CrZ5=tdni;#(zMbRFnlgv z`Av)afV{t^0Q1*rmk6noWwmyu$Qes5A?K^e$uAL2Su@5KoGk-!ocg~b6Q<0(WalIGc=arjw{C&GmS){WutoC5mfAa60nN*yc!uMhmjrLDUnGlL272ryAq^>4YQpaEz`LzRtsk#~yRPbwpIr(B_nIZ_q zdH>@Svo*8PbT)h!uK{jQ_6G0{iBP^;#@8+MRf@0Jyn7>F^_uLFxi_FCg40PXWb-k9 zBY-k0VLBnv;NXvnPGWZ}_tgvQ zPhA4(qn^iH)8F$PsT$Mo&4OR#_kn@_dGdO7I+>#_+lmgTwVFy3LnwOpBG$+dj<6+d zhKvyv)Sse>xN12mmFlv*Jnbs|UYEUUW?p$(^`)#hlPyzVQ=9C3QOhO~1ZiniM*S`} z4`bsdGR2AqVn!wLRtqH%*kn?Otpd&5OcUl|E>y7x=A2^F3j+ zQdr#}s62A%t_|RtfSJA=ML>I4_N{`BPqSD?a1E0DX8KBzq(XoT4?XgAggOc%+=IYf zd;$9Zs%cshd|lIji7oRof)AamX)}E-KoXmQu*p%E&2;KA>%~fSl9~HUS~9L9;IPJz zX9!XTY&i~NWCAeq0_F5jPPo6O3hUl>s*f->4qd+!h4fU>LbnZTdgw^A{)8fLVjXf8 z=CDthP2gk32M>k|R<^tW$0l=;QJV&2!X=J+#3mCm%_GJGgniLVT7n`>C^2d`v_G&H zgtnmlftwIs5H1LI`~$m#sr>h7T$lyS>Y$mv0hPq(?dy=g5}ZXDV0@vykAgcflFIhI zD2jKp`c8h&6-bSjNGE1qf*!O1Jiv z4W$1;b0`d?upV4{rg4;$N+}2}1N(~n4KVgu*3pyzp8$zo?(RoRD*8hfDv)u2Z^dwk zc9cpNw?RXq#Wbl$%L((vuwek^#(rnRAo{@yvPp~Z^L?1;%UQupEA*-rnr(%CWrgNi zp`ThIuNC^P6x&W*@>rEOl z6}H}MD03X=W!5Ntj-5-2!{AD+_D+E<~<2dUx>OSnuRMpyvyUR&OGQ7VXj)D~u8k=f^GD zg2Evg46rsCM@QMYCzA?n9;A78GoTn|kCaL}G(cQM(kD>%Rdz^+qEgNVX*yYj4zpaM z{orfhgEI5I;Pdp{@hlh+fu}@(_!fc3MSzU#=6iZR|#Xa}*YIzi8;jFOtF=Tjz0 zg=Iy{-cAx=2c>K$t_>$r!3Xof0>WM|%36YBM~uUr4F`ZwOI-L#Tsj+GMFgJ)nlp2$ zIDh&S@Gj(ufRz70gsD~05^oe?0&53Fat&e30HQJ82vP+htqb0FJ-T95_zp4vn>*rS zxiHR40Su_GkFPfKqQ%GBc80B#3^;eDVKuJ`E#TacsHZ) z1fo|H?x8UqKTeq~r22W0w~g0|%v+EdyKLPrpzEmXNvi88ma1m%PU>PRfpd=fYEbMz z@ag%;`YlrDc2KFJlX%h9p#f}lkRICT)m3@sRD7OEK+}x z_O7(VmjR_z%ui$CSWyno2Zv>O^qsqtzVlze_xgv@ zJH;dQUGbRwym%!3QamnxRy;0$3XjJhN$kLb`J^2O#8cjJ5Kq_ycO0W|V<)f_PRzi& z4X|ye#2p9F$8cf`zEfnWC7ieiZ^YwbciL#|K#}bSp~V`F$M9;VKSZ?ZLP=~hEu+OS zm@d5uk-@#MgI3ZT@T%ui1_?}U<5y6gAk}TA*C7p@w*?PaW*os58lY>>$1E^TNCitU zK^a;iW0~^J?c8Q_z0!p*%uE=!@p+0i6YF~8M%mB5|0$7UwalC8g?0<#WC7ll_+_ZI zjU9}uU7jCu}-mzY!XG+|LX4hlFcw+7)B4HFE8(HtpguUFu}=!kU+$O+@7Q zYj3q{F6?^3r)x}?hAn*9)V57(In=4Q*xCkm6T;Mt<^=K;vuS_BPAUo=8`w=luRgV& zA%W_D8?o(F{~M_P4|;1tq)F&_7A?dam|^$nPn?CB+!j!k$}#*rR9?>eKwvIm>_ zI!x0G80S{c3Gizoh!itGV_*n9*-uU1FU96l)xyx)Bf)?$vYzHd6p-nG(ah zHX%qT=d^~h_IRcUrE7SPU&F3z4{24JOqSOfX&K3C3eY}w#2Kn)!YJMjyoMXnh5SP!G( zUW%q85fqI>1}NpS@69>5tP;~gt*DD!A!Fb`EOwGuoQ|~&&3o&eGg@&33FIY3rqdoZ zZI~qDI=}L+X^`C)_R0|D@Ckoa^YpxzL@|BBJ1Z>>FG$;G-du)p2|!00!mJCKl~Y!s&|t z2vIx8K?9IjyGv#6e$u)obwN}NmIIHM<|Vo?h}BcDUV9WI6ncPzt2|buUEd3}84DL} zKW#I|mxQQ+tbU#_d|th!<~>F76LBA{mG`5fxM2wCf>+R9!h;GsEF zPiSc=mZ0@vimf--d?rbopx3D%t&a7CpQ4!)_*eu*$IR^otMGc5^98YE^|r?m%NTqL z3>RO}s_DT;5rkkQ<&#iOO&yG7rRw&gwsO(_W5{u!QsFniI*-MW!q+?LCAQVq8yPE% z$WV>2S>n-@s@`EFL-WSAofGWnV&gFBCYXmr9!FJAJdd8g0b`59YC(GP^DMEcju9!@qQ88Fr7Ob>0>~sC+Ts+BZ z(AoF|h&Hy<@1l(Z+T`!R(q*%?=g&`nL6NVG3} zBLv$a1hJNE#luK4-;Y)Ls)&tM_G<(%mU%T@T4J8BQyoWj)^v~;DYd|AIwC&}deQxz za|s8lNyr5YDZG%vODP=JVK7O+HU$-Gh9SC$et$m|{ib0jXH4{+lA#YM{5zD;#;<|i zV~scvD2$73s8JA?b!wXb&I%(_fDe9-{=ki3K87a1#{l;M&Mu?x2cRVfcsJN2z%QFg z-xHwV!%qk%qTt_(0O^e=tMAF)L4*vY{pMg64Np}Hb_8e|4*4Dj(LM!|jP<6{TbZ>g zz%Kz8z$Gc{Y#=YC9c!?IZ{!x@JJdv;6p>l&URlx=v)!9G#@MX1d$Xl>@5N)jDfIXzJpY^3CyuMuvLa+57fq8BID4O1U3}* zb&^brtRQ&!V`4D^whG_`TF4O+;Mnv;0w^oAO+fUGQ4o=rOWm66x;RMsnmGW^f@!?{ zJIkX&fJ(gv5JkpNzHky~ z&Rn3MwmTpC7T!!T;AZ;c=riQb_%l~@ma|^+RhQKep_`vQp2#lOzpn`in0HC9_=e z)hlzGFbHL!$?hl7v$^@IZBc;#{%z1`NKLXeC&6O>S)~jwrMqZP2s4I}pAEqRc;2*X zD2dDu@CFoM9SiEN%P&{2thAMIFRdKQjbxxm==EQ$WO9J^=I=6L6A#sT5A64iLqsVQN; zQR-;E$oXQMzkt6I+Ymh8Ocv*|$3Ww1PBMLtCR+g-KywX8)vL%~UHf_6=`1y|?sSUw zQ`984&o_nQf}S}Wx&cOW(%dXno|~d26+})fiTp(*97KXRtOU1q3qY4?gH&_xizF1x ztGjNcdXk{Mq`%b$MUl>dIYI@tx;fJ{ne|3e-7VN>@kP-I^x;r9Ca&{t5RE6SoR1Fe z(~eVLFotTWfKdSmH_c5^7d0ML^PRg|{K!0=|M5x?EJh}^8JoBct8-@ZNKYfF{I{_z z_5w2*Nu`d0ZrVsh@nqbCKp3L}uI_P&L{C<&Ky`LKOEPW4dt{Ch_t8LE-ee*|&>+0J zC2P4*h%pS5G)-PC{Q0s#(A&wM)X1HU1nhz(qi=IEG&>Gk;1C!o+9f5Snm#@TJcTVA zi1vK6di};5p>jgDY@E*qTmP02lAWH`s;m9{9&9GTF5@|&UKT5EA1Vt_1^Y0ASQQlR z$Us|0ZYI9LkEDr>>`QF-12DL4z&9gzC!i~HABBf%n|6iy9vk$WRvqC)%0Z+SnQj?f z^})^Bn979ZJ18NNXw^WMGt?uK=d|XuiVELaTDh|D`n)OXIInkoUWRtkdi1Z~FPaV=o5Q>L@}}OR(EAi0y?w5EaWy+=7J za4aDTDfT?cinho~h%Z$}2ktl1e@Rijo)gZ7D&TO=Md}zYP<@)d`g7X7eze7B(f-?D zIl#u=Z~C(+(d|QKw1+(zYc&;55blvQ;(?t_A4;xW^i>8VwQqDX5(T7sg=NoB)p0N~ z<=RHM=<6K0ureWLg)0i^JP4^kX3N(A#t!n1Lst{Xjm*1)eBmk}k3u61MlW+AM%<6eR~C{dDG9W~SUAkDlQ0n4HEeZ4(xfkzbF(y_`EB}NiguZa7d zwxF1PvGC7pLstMKw!V1-Ct@Spb^+*t1y*h^{5y3H3!nWZd3owM)^W#Chu-S2f9QF$ z>hn8V9QNIwy&DzmE6J>tRuaI{7`7ZfHPP6SvD2Ur{dA({ps5%A?1o~E2&~gTBFb5^ zhED(C5YLh|unFlW6=&m4icg)3hFQLsz7N??dfukecoQ(RL5jLyWRx0L^a-()_B$+x{Y#sqy!Xb7I_;6&KeW%zj z_bD3AhGFt=0{fSjTONc5g5Kr062QzwbrPLBFz(EDh49Jggp;eVC|!xuRd4u>bsThy zwSP<}1ASv#*g8wnhP7$@ris;Hf2@j&&oYhi4)N zT?*ZY-KQZn73MqpJ8s7uUiB7;Vu=H;MOOIVDC|@Ez4CfzBi)Sy$r-{$0wqzlg7%sX z>>i&UQdfs=kV5hbw)lax(832`{OhHC=RpYhH1M&Cm6W}{g3d#Ry!J9EhsGjC5J)FVIE{o}&jskrsd&^_Ryu&GhCW_kyj5U$c*S{1FtqKCFpYr04(lhlM$^JhKi`bB&Ww%II$*JZRg zEyr3sG+O|icM+VL!;!lxGx&2@Y+>C>b0*G?0X~Q!8kd72M+Uquc}h? zmNY0Rk>SI2pky+N&2y0_NEsW-x!0k$M_a#evUhIZCnrFzJY-u4VF9BQ8+QY)1%OWI zY&?R5l2GQA?0lH!SRiWP8mCg2uN?imZJOG8O1@D)b$zwH^7>oYO|s`EMVk-Skm~eP zSsN#^{YN69#R>Ajk*O5{(4C;Te85MobMoa=y4uo&TVC!kQ@_Iva+_cK` zQFQ|Q$c`CIltOXOdx&|@^P##5f`#29d+t#*&n^M;>8y08G@Pup4A!iS*xfNrTY@j@jE28`o*|S8^)-(fMO-0V3)+W3V5-+Z+aZ1`awqKz2NCfbtOcd_| zy9;+NOv#8`CNjBz)=|02WrSa$jve_d)F9wafw+kpNyfri@B-*HF_oV{`u1nxoKK6~ z4gxUM3xZ;~dq8PH$ty{%pE&J>j#o*cDJh0pDbhueSluapMFg4GWhLrQHPMh-^&)nt zaDkPf&{cQu0!d5J*T_R6M&AsVk#!|de>OPG_e7Mrfo^0Nb@nDk<^&_ioTU@J=j;tF z9^X?ODolf!I0bA4_JNvi3Xbq3Qr>D=|F)7QxMRm0>JfJ5DBj4Y{)tI{`&_(1XA?Rc zH11w)w%+1`$1dDHs1+PuAwgoMcL5hTF-DH}oApF01q4y49fJA#)9fODaL+uloW)D| zQOYPlK{Z?nPsc1QM~E?@CwGbz2dX>|r>KXUS&Zn&kM$*rXDF{h5lXI03lEs^_<$YfbGwDr?uOGBR2E&!a-AS>VXl$ z3~h_zVYu*wUd?@(()3x=v`$pX!uvRM`+2A2G6;P6zx!rDd_O;|4pM7V$m zjTB%9dq1Zb677Q4&zx-kSrV;}Esf%A$_<|5p)Gk)HpPG+ctzCta47)mZ-bcg;l=&| z)+vv8@CMP-dQyfA9Mn%MO$FWx06{LFC=ap3@x?^0k@3=+$AI~ zCPt>{tq^b{iH~nPOUA)Ze6?&q*e#XWR>ioN&bQ^fZL_XoaX$Ps&_VkY*nKhOrJ==F zVw+6}+12pv3uT@*DqIkdRKCJxlq<$fGD(!16nuNi6|Jm!aWbUH`6NY>W!=o$m|0hI zK1q>xM#+bXp@rKPvUeg`BFzC>HAH0|B=sVnobpR?*r%sB{K6&FCCmdH1>UM zjNX=JR4AT~D(>mfwzA1o@juD)0rGsHt%x}E``{ilQnD8%uZ)#UIV0_Zs$P^x=TE}A z%{tIdY>}BlY6QQQjKS2bS{i`uq0J*@$To5_>DHCgthXmoVE!!4OFCv)V z(Jm97R2DrJE@XM}zKkP}>F+iG`S2Nt{Eei|S2=(2wuNqU`rGifv?@lWm07DHH}@@S z+y}XdyO3@^DYG#-(0h)@=nw2(3!P>a9qc6=AG=ZZ+^A?P!ApXJYA#{#5Q9fUTjqco zjf$S>E1MP?_zXEUH?I4{#6NXxWG1-B%Jz_$60O`*Ck{DLLK{nGl8Sn!-XzBqg+a8V zuznsIm!ES~I<_W-RWN5TpmL z`69)`Mu;?;vZZMuDGkVyIzpf+_mR#Odd&iLNvBYXj(nbS4Fnk$g=38|#^UkB^pJ&G zul*45HKMKpTlcYXp?ht{b+8Ct=$TCOEYJ;IODGFkvVJi|kytg9(0qA>$iXneYUg=V zO@;{foZd8vSK!!c<%CtnELf&WO8BGWXidJCe)j zk6&svhPg0O5;yeB!9mL9bhZ_HE+xEPyy0|DSRKnYM)l8A==7N#XUpPR{>30i>BppLpl!i<7hvOK2_g1@wA!!gTC7(*ESY@1v{{k z-Yr)-^iI2dubJJbAi>NI;ZTcf8=g&+F9Tl-@d@HHoyIGX*d;iM9^jjJ_qsHi%$za zJMnoQpJ(x53m@(>7CzF2C&!cH*@I^fp1pYX;@O91AD)AF4&sS9?vZFnhUp2aLa%)= zh7M*@r?H#rf+MSICO*(#R;}LGwvBo``rYb%ECw*1ff1l1o)<@?AXoCDv3obNM+PDF z%M(vW(eAc8(26 zVDAfoz2A+IHxXuKwGx5y8GXu{wJk#)W;YsNZJRNu{cq(|xcw#4V^w?N9 zdJ^?Li_cDc4p80ku_>?v1Ea=5gwfkk>u*a^cB>75FD;5AT#`)CQvYfj#iT85yRHWSA~8m@iU& z92cO)3!1wiHBhj{D!33ed)Wh|VqQLkFF*eX8Q22{@cw!ozH-92hd@LfjD`MykojT@ zLj1RQg+pp+*SiR@1J!Q&U9mUazMc4p{M=zyl_~@8LiWUxVF9k6N#9SU_rYE;JX8CmS;enQD)5HtwTT}-0COc1RKT@ zMx%1LmJbQna2zx!$JSFh3$Mb)1$lth(F{1J8y@1X!TQE}x6h2i*QH>CI!&*=Q&Kbe z(-ghoPHfdG*tGxEF)H28Z$b(3`7i%(gh>Yr72L^$8#=!ojbh(FKIuWdlOnCidNXWp zu&{NtUH%j%3DnPJ^#Yxzs*Xb8Lba1Fk#5_0p7@sGkI=SrJiXIaH0uqLvgI~I1(~>` z!v8YO*v^;svQ{jIjatR1b+mrs8rvGGbv^gob1#z{Jy!k5ob&eURIoYC*5vXo)doTj zOh#}Q{3sEpAa02^5MMyo_hcr<+-}`(U~{XaEY!%Mt>Pr4Y^L{Mv|p!kWDhxwPPto} z8WQPt5-%>9=xc8L99i2NDIyEIo>zpP_yQ5m7xy|}w0rh$nvm1#^@ko!rS!_IWjwT# zn9H%C*}ee#+#RrNR69bAQ4~RIezZ&({o=N7m2#MD-y7<7;fxBJwFA+?tPbuclHB{2{nwPQuc$PTe9@i6E`{P7LP+Khw64` zMV$JniJQ>uIJ9x7?z5~WSH#{fN%K7KRPBZmxZ3^J3jPOpj|=bQCy6#6hj%g0qD}rm zi#8W+P$%nKL7Nw_O~DvhPWaFw%NLNj4Tmgt(>VvRG}sh`7Us#7PC+7F4X(Hl8;QiY zFl>M+tn(HD9tJ^`Z>LPgq988VqZh3USxNlFDH+5eMII*gER{b9`X6PWWyjkK9H0#C zHm+fd1t(Tn;hn}fRv0AP-#AaIIG}MJELOx_g&S~{Q62D$qss-dCs6=5fzE#qr^Cqz zdPZL(N{95=Y%@2qP{O=8_QZ>!jmL#^iUQSnESW+C||+ zdc}yqrK=D9nNtx}eNff)TQ__enX3`6h zX2X}PePl%%zgnKyMr=@NIA6RLaKN9l->6YML$EQl@mc6J>;O*y7~mIst2-5-+B!05 z;$VHtto&ZUS@pMilYdE0z#EXW-s~3dYw_-UDeO1X2gLwlcLp)Ikj)Qc6|pCArW;X0 zR)iL0;(YKWzej_I=Y!K|*}l<{SIV6a45Ep;n$J=FJ9rCeUo?+vz(s1i5pcd(0G{2~ z{S4kmRr4`Ok`;BKnmhK*f}2|CHyIX*M81LfAM8HE`QmlX7h57gS!Z*dj6`Lj2S@V? zY>PaD)t_PJC@3ILlS3dMxC&th19x!4)vc?ln}q>dc!9X&hj)U1DwB)_j?e;E$Z(*Z zTh_BH=dCwp&GUM1)K0Jy+>fPlHysVGTWp^!dp)hy{iwT^j%CgU!b1x#dYR_>Iz{o` zpq<3@#u+L_l`xXyJ|FBHT9VTenD>#uj69o{OEltaT#kCN#vxW*MZ9?BZv-!<1zU(0 zUAVDMFX}Y;w*54+M$IvCH3M56gvP@)2oW3t@+^>@4P`V8Sr9(_&OZ`s;=UJaWBTPL zzy`);r%ybsPsfc>D7cfRB)AiFVgMV-&6R1m%mHWBVvIVT6$JAwR`v7D7m?Xm6)a)- z#GK~){RJCv(H(6~_a_p2!DRF&1i+-PiGvB4oPdNKUFaWMpzPq{>DbYOCoYcz(G4cn zxYo193ta0Bhpz+C-Ut^d`80LZq&6?k$ZTpF9FUOEZ6(k=Py@l4L4pofE1aaXPfZ~> zhQU5x2$W&KZv!co;{r~MX^HuMT&Ms=aJ&Psxqn4+TjXM$jtSSFwz^xwFQ-!cHtfq; zt5MtuwXPFZ?M}WIj)TLVRp(WH$paX>@^B(~xd1B6PvlvR6=Nygq!E0m8pr~&1JiK~ z21<>%%aiV`ohOslCcKT+tFVKe#tNhEz5JU0GT~YfbTR*oWz3(wOx!quP1g##xebRm zTt>o9TI{u<1={y6^;ZrBA4MavC9AbY-Q&m7RgT@7xiEVM{0rCy2d;fluhq9?&otE} zkD5KR`ts21YUcQzf$Q+FU#oBV9d2#BK=2=1_&a#jq8;(F8ZVKT=$g8<)(|b7v z!$CL|XC7?RFP;I*SIn0aD}f!oAc~kydiF^X{b@R&Bb8Jx4vF(QbPnS;&&SVUj6Q@x zGDw`d_`h>l#3zS}YVL6#Hpu9!vivp9REd!nGCA=QIAX6vVh z;8pbZ>MKA+p_RXLv9Ux%_ko5ESTwXi;p7JSGW8cSfM*~Od4BC9G^0ax5+p=Kbp|iE z1)<|&*S$RFmx32EXftYq3s<-D>wq#0=vSDb6xAr~GF+B}D}2m*X7Kb_Mo?C1psa*_ zMvimt!*pQAJcP|Akkx1GIBUg0t=lj{B6T0qP4iQWdj<0@`VM|rgZ~(-KCv7rWp`#P z%Zg3h_{m>DUkH-;4OB$0vlQ$=&8Dw8^feb>G4e$!OC`skK%QTQL&fns`W<#`@w7NR z?NvQ+)3FyRt30h66De7kj?7%DgD=~Sk!!2W3U<;&ko+fr3Rh!tuZGD=KRtHqVl|z$ zRVI|@w5rqaQSe!t)2c1xkv40tfZI2;80;n8iecDAAa19x$QpCgN_K=-08u!D(5|qg z$Stf*=T3F5&Xd%fLM%dV`#3KD;zxG=9mt~dHox9Q;BBX`$b?d zhd2EE;Z~ZUI&q02CSQ0l(XJ-^#I(iLR2IkLss!8!bAAD-BP} z+9b9V9#8KYi`F0>>*}RzjiQ6$MQa}-B0|g+mgkdEbPT(lKru@vPbd5SyrN?@_??+! zz)6Zv1nIF_rkI=7mYAiT<&lYG46Nx8SMR_Djh_!Bl(&hr zGXcXz!*QsR;Dl`~T8oQeets0wL(EYn4a~+LM02DP!+Hs%fYY6gaJG_ybKl0qkRHWc zYMrW4>^mQr8jlB6stlDD1ULcO!#y+u_Z%f)nL zIf|Fe?F1hZVT8FOmWbWws7N<+shhkc7LO?u|LH`G$Uts$;K&i*8_Q-5&(XNe`sc^a zuvwFSXW6XbZEo4DGhnkmIOjrDp1)Khr_Rrt$2E7vMf9E0GIw^C#$iWNbS597b4p07)N1Slxnid}tBY{dcObsO((sK0I*T<8w@E z@oH0e3RXyUvv36_V zOg90X^!r#_oR=?dNpuJJbZBKDUT0$!aEq&+=)i>^uT~d?cPus$GzTE)`Vd*$P&`%S zQoVnBT{Nuz5G8@bc~hBm*$%<1X0}{)=Bw)Juqpbs9IC zARy$wxHz&IAv9P7R9agh)#8n|LYxghL1#VI9hEnbJN|M=SM(KwmPp=ExdDDDRuzOE zY@A%m7DNj%6D6>AKb8hv{5`0cCHxZ92f>Zfi}8jDn~wMtVoZ`SCP4l07|^w%mS=_^ z^319;>+Cx3r#f+UBR7E|Fk^gJt^lO;%ShUl=y&|mO4J@8H0AMN&#IDYq9pK}vhSVt-jq0}od^t0KLV?L;XeHGSdhm0yuu9Uqr2JeGk!14Di3v}aISr?^QC#1 zqnt0@ljJ^J7FwueH1=0dBF~LNhv#Hf3ba1BV4SWRGhc6+;d!qL%QK+|#qX{jh6hU! zFNoUm$=wc&($C((BPQ;MJ1BnqF6MP>i0g$Z6WnjW3Eu!>EJxE)@bcvp=eJUb!?5%L z&3c$OyOmEFIEWvYiP6ny-`&`%C=a3Y&DMZ_KlSwFK*J@mSeIR zQPp;=6hW}+8e-M&9swAb!DACpx{On6pz+8zW2aKVBJO?pxZI<~`DiPyokW}UHJucO z?v6u}DtO|o6RJ9@jB5$BJS6kcCI3x!OZ=!oQD1XuTEoq@$#nl89CER7+sll-K#cPx zdERuNE9NzB$6jL{oe;r63}ID@&4=`Jrl=FD%YO(2qGux`_P?+n`7{_gwiWi3{m6y~ z{>gsiV~rr{?9ii>j%NlvpGDle_zdDRyvKO1{Ya`E`&GkvzkWYb!0=D^BV%>khpK}3 ztifkFK7M=(@$up_2OsQVbzu+d|8PH&8e=AP`f+@o#pgAOiSK#+U)zt&YNB?4!lwtH zK76A1$Y}Zk>e>Iwek3)<%vt!JgHItoD=8*EHvcF4kzg|Vk)|5>Gr=>1Zhge|KhEt( zl0rWQ8{=&I-AVW?!HNC516lZ5MJM*@5dTs{Z7oC8*42o*d%YK5clq&Ey#`;k8<6lV z#BIGBaa%VbZtKIo$${zYWe_%I1}VxZ9k$P%~0I?bN1_>IO%cb z(SLRb9!WPsM`my9pKQg?9^&^r&d)hc8pNeSn2^4O-vWjE$tL)^!QIS$B&zXFxc+TPz#d9_vFP@n^MLg$ln|RLU zC!eJ0%4=48`R8~ws~7T5#j}uqB%X`;d*bQmZ;R*6yj?t(^IhV(lD{aPYxu9lb1i>H zJcIlv;&~_kp?GfK4~wVD9}v&YyjDE7@M=5>1VIrzNU<+AfH-)CcqJn+UnX8@^~@KE z*KPDVSG+z-uUCrK$LRGE@%lKuP7<$A(yL3nK1HvI;`Ld2J@r#+duDuvK)dl+F6Oc% zPomg|#|q(nWWkMJ*n5f6rZ!^U5HWCv$(3M3reBWw9mSkgNi8dIcoJoi13&3x)#CCb zDzTWYR!o{F(GiRJwiT0sn-*d*E3BAIPhwgu<_0S!%afQ9i@8R`RA+l~Gerz8+NBsk zGdzKUwF5C@2!6SV+%4gok%0ScQg8>3^Eo*i2QFaP*=Hgi*WolLiKKR$bBCP0@pJq# z&YrCJEuzKopYFtZc>7wY93=s)DA`FI)Vr3>tw6~R1h>2|?)q~<=YSrh7`c=&GW)Dk zhaxgjRD!d9)&`5G&Djvfz|hq%jT|pV#b91V27DxvX&VdoDdsv*D|Uk_vgk0O3qDv- zaYFJNU?Xh73FCB zI2@)Vy(cZ^n+8&{sOWg!#83U~!)T=Cv=(}NX*D*l;Y-_2`324W5@bU(M_z4$=4dr5 zXf6xGmLzB{YlP;qiRRJ-&ACQsE-OxRkDzevg33cyWjHQt4LeaC+9DI%U(i{WOE@WkgCJ!PcBc2(UO1h4-n2F- z2Ye19dG#_7p|gP;Vmw8e&PRTR7i-iUp!)XMum5z=s!dN{nqL@V`NWW__Tv z%5V~~4a~2R3;n!{i0(|z>4mP}kBsxg;oA}D;$t|iq=eW)E-8s5#mR3FKQe>PrN1E7 z;)4NkZv}49=;QNnri!?!yIc$nP7U?uRVdczfTAR~r2o7uYL{??a!!T);Vc@Gi?u69^@ijw2Kd4bhhD?(cpHrEBx`!Ol%{ zARa7XGJzig*|8{0aeoRY3#^0%R^ER6D_9u>R!n4k0a(FhPCI`nBnko;1sKDIhtO(K zcK1gv267-%!JgQ)CQj|)88is6AdyHI_-Io9bQI@Pum~%spEfvylZ8y84l&@X55K|! zT#o$_a?)kOZK@*=(gu^+;A0fk9$MEqEHr}O{~Dn&_hS+oGlbBv?!P{xH9jLs{ei#w z*T{_k?c9uQ(Pm)BgLZKoWL9Gxv}uB8FKZiEi}<~)ou2kXkwti4i5U8sDdaiSedy?+ z&kl8r-KX^poM64km4+PHNF4aoeyD1k2l+NBRZb7`R;MhAe6Z?@BND?-Q z$}wWq%GY9d2-8DsHI56MXr90?#qp$%gvBhhz?M(@z?)$5o=#YsPu%njjE1q?sFV z^;^_mOtUZQfmNG3guylodvUHgzCLoo=p`o%oIFZ%zT}He_c`ito{W~@z2w*doAjCT zy*PxOshqt~w(YHx_Kj^V?|ubxWH>fC9{Utxu~WB)w%JEn24G$9<&HlI%K-H5QFeff zr8;t_IDFb%LGaCZmfKW-&B$Ryk_ehi3)$;v1?VAOOPHSfZ_>ugw!!C|@N7=lqNCZEB{ zq-S7)UxhodZQ61gA(9C+=i{DJMET%(5ca)`f)f1(BIIuepWaMnvho7YK-C?*Po00>bK?nCfwP894hGijr){@p9a9FrZ6@ z9h+&eYN{O}`D&63UHp#k31Nb(o$)&}qpAb2TUo^cSdS-DLz#5BeivRGmY_xQ8l$2! zvVu(}xtmw>E`GcMf5W*1JnCHht}0K5TZ?eK0600wLRZ;aRULs7JnX@p{8x`63y>Na ztJfSe@tXog2Mu(qi`U}50f?Q>&^ofkSz~5@WYn0Y!5B*hr5^rA*jZ`V{-5@~20n`F zYX2q#jTAI$+6F~BAYhOXc6MjK=3_S@2_~3?m;{ZAl4W;7RyMoq?rcab#VFW63MyKx z*rHP9RkWyBL1{}hRK!@RqNQ!1RI#F>V5OD{Rx1DJ%hG?s z`FH4b^XcbNJ;%@4PRn@xZ~5LuyIySjY;59`ITbnSyYTXqF^PU~M4>`gynx=ItiP#n zylxqB#_eucQ1>ou`^8eskXE=B#^3s>qHH2Gf~%`%3JB1irD+JPfxP`pc^De!84Vc&ibouh;d% z3M#D^qAcK%wkNL2?uVK20TP|g>>j*+IrcP{rzMm*+tanvZa@u2J)U_Qq#WZ;9B3Z3 z^TT!YWulz47uj%lX;9UHgS*av3*HV!U#RG}0i!%*EEJl4vy0rde*3OE&?5u!Sm~~u z6pf{a7v5dh^&tbyWQHGPA^nziU{Ge&0mMdcno?YL! z>HLoQ>qj!wOsOL_VE($x7vXIM86%z_OOG1fgzp8W#<%z+9hN`7^^#VBnGtmJOyN^k zJk8O(Y1Dunx16e7fGN`X7}?^n0r9=qDdO8R)6?G-Uxe*>*fxmU@#SNDXYw`MOX7Cz zG^~mrJQz#gw`Kl1d?6Ff?ZJ^UDqO17#fMm`c3Sb8bF`xPob|2a2hN|k4QC17oR3$r zE!~P&narApx7~JKc>KF+XL?WiPS8I=^c#u3yeECdp7(d&h*F-4d_Rb9B;x%<{5=qN zdF_VRbn&zf;kk(13ur5 zPuRlLfCa$ExPKQI4|^xfjK6^%7zMb1QlJ*72V%evfyKZ>z%PJy;CH~^fRBLzm|6@4 ztUx6Y0@{Fuz+&JbU=6SV=mb6n2JB#L1Rw&nz%(EV%mx+%%YkQsPGAp^`3_?_z$m~9 zcz{x%7H9yPfqB46;I}|0@B#2|p!c;7Rrkt?SZ}~luHJsBd%rkkg1v6Sgo;QY5mNI* zk?D*LLaUrRsj#|cG^cQr!iD~86Tz5TtzMf@<64d8)6_h!QS}AX82m378NUFLCFw% zSgsN*Mb#MiX`MfBAuFUd@82!>STH*xOMf{`%S5Q{XW6k1wRSX@$#$!JM! zZCT|-H57KTp7Z`hTmxMXPLst7G?|@v2JO3e9&M;m*5~2AU@-QBfHq($&<<<|*f}hV z0}6n8fSm~%m`j0nU^}^;3mTvRs0Z4Br9eBd9biN7tlL?jfms0518u-kAPYRyHU{Hd zlU}K~cw$=I9}7-{`n3qBHd8SuD%G^8QRzf+Qh2;NJs3{bFm75x;{w3|N2M;(tj1!& zfXZo&D%YfHjS;=B1hu$13NF|b4e6P$Yc!wZszRzSu5$iH)jz`=HXfWF_Mt2w!U)&o zo1ua`+yph;XrPYk#QsPurWa*B&x~aAsoJqV%2gGKYbT6s#~@!}0{Ifwf_^lLCqnie zOa7fuGWM~2l5CM!@VXNt^Ny|lolr9NG5^rvMncW0+$-{-1v{>r&ts{7CzOnR%)bg> zG}&yHVvHBUi1K*u{En^uolr9NG5@H4Kg|5#_|3(>$`?~hT2z0ct9L&^is`YmGgT*| ztbNSS6D~9RC?D0w6Hdls7ImaL$<>Lt@V;{@u4cc>9!tKR5VG|#ze;FrQeVG4zMIKo$*&Vawm#+;<_uLntezjYv!Oo9 zL(9J;4?VaaiXs0P2A@U@6(*-p6`zLd~6zp?;V*#g6MLF?Os6dv();aZQcU zKGg&}*K7NWqa7PAxlfu;PdS#A)f5(2lvR>m1y%Y8M!o<_mDXP$*)w z9*kMwH)R;h+LDKTCfEmz!k!bZ{jk3aH*%jGo)M1B40CFWUyV|=gg<>^BaH}?S3j6s z{~rxb-5=!fF2${g&tk+u>6*irg#D3#S``U~p$G)Jn3b?O~q>93_O0x_07abOxFlazwnDa%Wp;RN>=))!)Hmb3K%=t7;ZHj8N z?-hzbYT8gM;!^2{g41HYSS$7=^}R2@7HZ8OklI9xgf*WZArZn9`vr0AokgRO7<^P; z6E=ur*zu#ywC=sld|d#@K>XPT4H(N6cC(Sd23Svf~)G4K) zq2LS^v6DF1ZKtYkgc7Q{lK4 zOZYVik3W4Yw>T84@CC!V>?F69>_+I+zlHJ%1 zEvl|H^sP05=}6eG<{!O2C>`R>LTOM;#9wy;fuz6HMgEDfZyMM{$?2w`jp(SsE#k2{ zzd**BK~q3I-@3y&juAhox(+F>$W)<(-OW=cLq^T>Io2Es1rxf{nSWUZ3$}Q zFb{{pX(VD7U%Z>bb;})zs$mqsFm_v19NK6O`c1S+9jPr*<17bh##}qW2e0cVffSQ8 zO(=Fa9umX2kV?Uf-taS|m)TH6R1g>N-3utuHn`L4@&Co?7(! z)PP1z(@#`TTiw+XQ54j?sd@=!tRm=-MdFbLjk`3cOIb8#OqV{&jYbd66B~f~kdIzX z#;Kd>F|=l3A6n&v(ZhI9SCT3$p>}%MfB`smLu4X{utkwr35pP${AxVTSQCpgKZ~#! zQ}N4Z0T#l~xcZ~%$M;Y5>pa*qlJ*~)?0Cy;JDmch>o$}9c9VUf$$p2)ey7R)Ba=NX zyj z;yA$-^rK?vm2Y|iXPz!#^-aF8Z#wErGZ;h5?2klS^$MSA+=Hk&NoMPlG|kiWBPL%! ziL-S_6JMYer41}4o1y@YnI*dv>Lf@#tUg84-2$VxF?{P)95XZ6{!*4qv|l9RA^I@! zWYPrqIz(^X{h^t#o{oX(Cv?z!ViKiZc@^gmMdbDIC;0Xq?`md{4zd zJtGic}fh83j7YyPFFO{q{EcH z4=c2Z?y%}J`BT@D%5$^YP=1o#TOb(kR#B5L3O%IC))z66qB$%BBzsr+JUj#SadfA? zn4xlNZo4B&mP@t4M?)yH1l_9YieJyN!-Y4P?-6S~RH0`A@zhh6i&C~SUC&&6^Ng(^xXnbY?qX1b}n8%~Ak+6>g#sXu23xQd)Kr;#^g#l&*xubEm z7AAr)bOZRlEC6#PFb){&xsV|U8$)&i{*A%Sg}NVO7&z$725uRZ(_sj&0K;%EBO(tX zO_pc9EEC<-sTg>Ka8OMRz>Xm*)Zy32J*veV0!)lZNo1Y2!57zzo2gT2_?)t1{M1Dg z^^vm?H`-}`2ysy3704wwx=J@ zz&7}82G+p73Fbzi16U8V18aemzzSeFunbrVECCh+i-3i|0$?667ia@!0WE+AM1c^{ z2n2w7ULU=6SkXaov?Y+yfhwi#Fn;8EtRIzR?Ur56#ua|8@yTyP@lsc9d5t2g$rKt^1drc67f~_(P@d ztIL`N>b0+#`# z{mhzQ{_59jfAj2f?dyK~{Q4I*yx8&5?_S>c`&VAw^xErx*!;&o{ke0?*1v4~>l<%w zf9r2=?|A3k_jbPj!LHpO{{5pp|M>Wyd;j&xzWty6`?CZ8`TQXJsuQy#PrQz5V)jkT z|4pa=mG%E+6XPTM>l5Q|TK>{fv8hRsF*g@iW9raWce3@c?0jYo$0SJcVTwePLEZ4|W9LLGj_C5wg`bCSviV z+huAXtR`=2@hlfPS46_PZw;Q>B6`F@VJRE~Jp&!lF!)onWa1XC@B|G=DFo#6g~0~6 z0aM@&EP_)o48FlWq#$8%8BY(9t?w6om%1K%7pL_KngRDAc-|-FoDNGK?p;7_(w%7Z z1`mGp#3|7h02D3{esoWl*)N(5OYRi5%@iNGrLHQ3Ut*%A^jF}14X`=sPBe#0pTb3t zkp7-zSV~6^i@l#ze5tg_r0`~1awD0{{FB=vxD_J~veQL;*5bY%n3Z%Vn#1u);a0*= z4~TzeJuOa#B|i$g+!PhWv>SbDHF~A8s7V2HEK% z*(|u1fs|}Sb2!<|;W~yh_WJoK8+FiEGh=v_I{WM%%xQmu=iz`jaJY;3-E$Ai8jig- zN@KB!7c)Ki5iR$VZrb%!j|*lkKyH+`WK#NM4g}^T z=~H=Y_G`#vS$HdhPP;j2(*5u;c+C_*aU9N{+@Jjt|J?j94nMz_|0YxV6#qTg$0YMg zm@1Isqtiq;-paBr1`3EUd5yN=9f?Vrl$r9QydenNjJ%;TR17=0)xw0)b&(rgsdVuQ z2whL9d!Jy?zlQX-0x5U19!njVLj&e`%>2Ivzju=U2gez78GkkMH4A1cU#VPE94UDy zU+Xc@cNTQh-Dk3!>0TJmvR(p+J|(Bw|Jy|@YcOE;@6FGr z#YgtvP=?300dx3{UiyBuqNo1?lmFdSEbFI$IehQ*FPzfTzjt{X(b&_!clgi4U+mv; zZBPG=CjN-8^O}45xA*e5&FbmjJN;l=PygQhzj8xQe{=rqnu9t4nDt{0KV>eQ z5`}Rse+$pjFU9ljCbv)E#^83i>*RC$U;NyD5i7!OfNDHm!fwsDEQV$93D|&Vt207a z01c_(LdM?ghl3U5+I2vqg%x2N#~>|at1vdj34rl%nt^u?;LZ11G@qyO~-8wOH=Q74PLx&N6VIY9@Y0Mskj9Sx4 z7c1Qv5i&d3yUxSd=uS_z9ooa58rJt`sDZMuAMZVY42@ zyKCq55tBAjj-HIkVH}Xa!*zi!sgSuynz3(ZAgv>Mzm{GW*UQdyHHL?S;>4arlGkW~ zWI<)aGHOC9<|Y|w<}KizB!fXxgx4lOsy`EFRHkTOlDUmod^oufrA6IBHZhHqQqsLI zZj{M*A$yKO9_qm^K0=7g*mW6~;feX8MqjKpQbFeo#h6NqHYVG$&9nC+Tvx z;*eQWElxcZ#&wOr#y(0fSAETgR3o;9l~5_^UG-RPimzlTTc&eets1uv>321Ft{EdF zos%k3GpiurN-D_y7vwWeXaxgBbo2|WxXrW z>|(2rT=xsZftqMAY$!r8a+>zDDCZH^IsLlwq&AYuC|1yu4!QDHdU+9!L3g!HZ=3Jo z-+isy@tuq5Zv4B(_$>`~f(!RDPyj@;8M_oFX2$folkT@K=nYh=H8Pq$qB?mUpBe}~ zh<&7Ijj>9;xA4-UUfDST2lXPc)`9}CZ>B5j&T%tI51QU_Q6%O#Oz-T_<0lPuf)_Il z&QnhHQBP8U{YOxl{kqOsCjBbkE%^15gP$wz9S3dgP7R{IB0Tx^_NO#@$A#gdei1G4 zmAd*RE$L*wfPFt0o7Wp_D9d5e`N}Mq6llluEbB~|t6-i5b0N&LVFqC4z|4a=7-j~{ zb6{@#Ez3F=<|3FwV1{50g;@^sdoXvd!<-!EN|?i7u4%`-3T6(>7MK|@F}-GcpJQ3q z!Q27!0L<+$X)?75=6lI;Jqg!F%pT)K@{ul11t{%QRMbv<2O#|rh=xo$mqar62L=JB z0JQEz;c0$FdL)zF$fWql?^{61kK(1UWS#*~yu=5&k)BD%1ac?+kh?v3UzofvO5Rt& zq%hS<_nM?h4I#yUIY4P+u%*Y-1d{`z0Od^#AYMrhqHhC;=NppdjWEf74nY2M0pjNl zU^H-F^8RNqiQi=arS~vEbk6|9-zxz5{}~|v94LkKLm<7-m1Y=SX7aY{KIMNT_apiD zl|B_u%1nj-Ce8BKjQUIYPS@AP8+}{cNWu93Rqu(<-n`Ol;!|mqzKU}Of56#-KVn@L z?(`jPq9>C+(wUpkMdk z)(1Jm`;h-Pd~P@uB+b=FNne(yI1 zHg)SYTdjxE|Dp4Z?VmEn&o($SKf^=BD;D8Q)=_}k-HGT^TJYTo4Tu6Epb-cF^*|j^ z1(X6ZU;%Q0AwUk04P*fWflMF+KnI_7;7=I)0(*fyz;0j%&zEXV&^%eP$cQ4F(e460PaDDQkzK7PLDIN-+imxqd*!SQ= z6mVu$HML|M^Ho*+6~iBZE&v+erkLn$9|{i%xB{TD>)pU=U^DPf;7kZ-0V;tefWlK4 z5ukD5OyI}BD&P;m#{hM{} zs1w>o)9h`$_63ZT;|-G`E=2#8;l6lTxH&RIjSc4#!9qVhprH(J@P*>)aF0B$EAF0w zyW%%d9Fn>`t_QF3xGtd)TppLwr>Cm0s<5~ikMPyiB`sg&o<@pP)-4u?Ws+s8C2aY= z@v>v9V~67d$7ts`=XhtSQ*&-`{?Yj-*W0cE?oxN9yVl+44!bq?Jojzx zMegP9$K9*k9qw1$o83Fze|PV7XNsqb*=0iOH;X&Pzl(dtOzCtfTgsL4B|$2cDy3SfQ3^|%G*7xsS|lx(9+y^09nve(W@)GN zcWJMbDW5K9%eivCEXbvDrCcjF%3)cP=gGIpi{#yMrgFNHt>h~CilCG$k1J0r>y-(f z8qW;R9MAop10Kd<^&RD1=F9jRzJb4s@8DnI|HQw|@8c(1Pq&S-jj=7Vud;t=KWJ}u zw!5m`m$`lJyWEetSG#}hP7_ZRhl|ya=!fDK@f2x>^aE+5^t$x6)L)(qE?$z~lFw4k zQ|?w)DqEB{lz%Cuo+~_$dRBTic~14_c&B?c??c`#-o0L`jI+Q;nkCz^&5~~Y%vx;Q zE=+aIbl>Oxx%(060eQLnl>D5$S^kUsk^G5#o^n295|v5HrOGwRwaU%PUCK|Dhaulu z;3Q7une)>&S({K2xt^1kIGO9p=ye;z-A_wvPjIbY3R&QFD&LcGR*pKs&m z@ptg|@(=J2^N;aQ^3U*V`QP#{LVvrVzXSZK)`8aVT8CIiTb)+LI?;NKHELa8U2ffL zJ!rkqX16W2-Dg{7d(^hl_O$Icw)M7`@k#P6w(Yj}Y#-V7*$&#iC1eYOh3^TY1*@P4 zWkRKJwcrIP^b^DJU4?5O3e&=}4G1TdB7CKdD*qLz7c0TKT z-nq+}<+8g&LF&xK_A*;*H{b@otp6KZ|dRL!^-sFHM%NmgY+jNh_q)(pu>a zNs&wBI@yo%)FR&~-;C09FLK~nxl`VOa&WNa1Y_t5c3i_>y5>f=+E*DU|Ed~O-Um++JL`}s%t zRs0M5CVq}>k!=ZT=fk$gY$Ul|C=f1#%u!*c@VM|FA~yd&IubewY0v`z!Ws z_8s;;_I-BdINNcaW3vi-2s%_Kf3q3 z`-^9agT-OuSn(3^axnsZJT5*fz97CTekz_S4U#O9Q>u~z(lt_C`l0lw#_L z?RnnwlILyDPR~9M^A18OzR;_9OTCreTJPoFY2NF-H+dI&@ABU3ebDiwhl zZSM!(kEpEGV{8U>^tXHqrOjcHEftnuSSp1pgj5AzGZp?j`P}?qzygv)_Hd&BO-rT5*B+BXO~~ zL|iJa6L*Q{Nh8pry|g&A9lY95@@Mn&(KbBDui&5NKj%-eo@*Utz1BL*`a|pe)<>*st=p~NwUyhZ z+FrHowh6*g;W&^EjysvrRr83#Z z*ftn>7OTZ$`H^J<%43j^@a_Bt{sVrHwa|JI`iq}fpRzXEnrzqG?zKH>d&V{jWzr+m z2y+AxrEs48cKhA-CHAHEW%l3O|7kzdk>eQR;2a~+m*hDt4#6?oG1oEAvB0s=@rfhN zImCIsGuN5tv^XzuejhTga;|~g?auYi4(CSaCg(XW&Naf7>&kQ8B;74NBE2mARr*Lu zlh2k%%1-${w1VyOi}Gvo7WrNIL$rcVD`PzGdp`4Idb7Ply`#Lm*XO;1WLtdxv|FsEF5yH;D_;7u_SWr8vhz`rs|Rz~=}< z1Ww2m@&t<@2rfZJO)M5lg>s=vs1@pjDMGyv5E_LL>ZT^N2(yGXVXiO_?b1SFk+4`; zf>N+dU@MI^M@}ArUMf$vpr3NdvRoh+qrWPbtI%WB$y4NdIe?ZXBuCL}w8*pMHhC`k zum$o$v^$ICCGtk}7@JY&c6;`q_1=$~m*LGs3to(xSB^Tikz{UXtOLf;#J5yl23@X@ zSE9_Uk=H`2>*WrVo=xasI^}KhcC>OkQ8V_)d*%HoOH9d7GL?Z!7JAbhWr)HlBhahn zDHimrE=5)flwze6J#3XytJEn|lzJtgG%6t_s%T1!GD~Sw=Ax}!pe$4tp}kz9ELD~% z%as-A7gs53&}X%yU+z#gDw~we3fsi+bwt3)T-mN1y);-{E?1SS))jKia<#b@xfZ*Y zyH>bXy4JWhxi-6YyAHS*+J+o=t~<{yy9?Y^7@5?$>)kExS!gAeVPvw_-R|CmamhA} zN;1SuF-IIC=7|=JOJs~nmS8N>fl+Fpv`}6E8>}%|6(H5<@ci1=CH`^IT zTmz*nv?@8$5J=v;r7XrMtQ>l%g(jv*_2>^8p^+#?WG&JxsZH0-g09wdsk985S|P2( zC~XaT(ROJ)^tMsjgz;LZv`yMB?UD9N2P7tE$eHp$U7I=b5Y!ARcaZ+%by5Q-HE>b` ZCpB literal 0 HcmV?d00001 diff --git a/cookbooks/iis/test/cookbooks/test/metadata.rb b/cookbooks/iis/test/cookbooks/test/metadata.rb new file mode 100644 index 00000000..d4950c78 --- /dev/null +++ b/cookbooks/iis/test/cookbooks/test/metadata.rb @@ -0,0 +1,7 @@ +name 'test' +maintainer 'Chef Software, Inc.' +maintainer_email 'cookbooks@chef.io' +license 'Apache-2.0' +version '0.1.0' + +depends 'iis' diff --git a/cookbooks/iis/test/cookbooks/test/recipes/app.rb b/cookbooks/iis/test/cookbooks/test/recipes/app.rb new file mode 100644 index 00000000..427bb1b5 --- /dev/null +++ b/cookbooks/iis/test/cookbooks/test/recipes/app.rb @@ -0,0 +1,31 @@ +# +# Cookbook:: test +# Recipe:: app +# +# copyright: 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. + +include_recipe 'iis' + +directory "#{node['iis']['docroot']}\\v1_1" do + recursive true +end + +iis_app 'Default Web Site' do + path '/v1_1' + application_pool 'DefaultAppPool' + physical_path "#{node['iis']['docroot']}/v1_1" + enabled_protocols 'http,net.pipe' + action [:add, :config] +end diff --git a/cookbooks/iis/test/cookbooks/test/recipes/config.rb b/cookbooks/iis/test/cookbooks/test/recipes/config.rb new file mode 100644 index 00000000..051d5a74 --- /dev/null +++ b/cookbooks/iis/test/cookbooks/test/recipes/config.rb @@ -0,0 +1,44 @@ +# +# Cookbook:: test +# Recipe:: config +# +# copyright: 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. + +include_recipe 'iis' + +# create and start a new site that maps to +# the physical location C:\inetpub\wwwroot\testfu +# first the physical location must exist +directory "#{node['iis']['docroot']}/MySite" do + action :create +end + +# now create and start the site (note this will use the default application pool which must exist) +iis_site 'MySite' do + protocol :http + port 80 + path "#{node['iis']['docroot']}/MySite" + action [:add, :start] +end + +# Sets up logging +iis_config '/section:system.applicationHost/sites /siteDefaults.logfile.directory:\"D:\\logs\"' do + action :set +end + +# Increase file upload size for 'MySite' +iis_config '\"MySite\" /section:requestfiltering /requestlimits.maxallowedcontentlength:50000000' do + action :set +end diff --git a/cookbooks/iis/test/cookbooks/test/recipes/config_property.rb b/cookbooks/iis/test/cookbooks/test/recipes/config_property.rb new file mode 100644 index 00000000..80165f6c --- /dev/null +++ b/cookbooks/iis/test/cookbooks/test/recipes/config_property.rb @@ -0,0 +1,74 @@ +# +# Cookbook:: test +# Recipe:: config_property +# +# copyright: 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. + +include_recipe 'iis' + +# create and start a new site that maps to +# the physical location C:\inetpub\wwwroot\testfu +# first the physical location must exist +directory "#{node['iis']['docroot']}/ConfigSite" do + action :create +end + +# now create and start the site (note this will use the default application pool which must exist) +iis_site 'ConfigSite' do + protocol :http + port 8080 + path "#{node['iis']['docroot']}/ConfigSite" + action [:add, :start] +end + +# Sets up logging +iis_config_property 'directory' do + ps_path 'MACHINE/WEBROOT/APPHOST' + filter 'system.applicationHost/sites/siteDefaults/logfile' + value 'D:\\logs' +end + +# Increase file upload size for 'ConfigSite' +iis_config_property 'maxAllowedContentLength' do + ps_path 'MACHINE/WEBROOT/APPHOST/ConfigSite' + filter 'system.webServer/security/requestFiltering/requestLimits' + value 50_000_000 +end + +# Set XSS-Protection header on all sites +iis_config_property 'Add X-Xss-Protection' do + ps_path 'MACHINE/WEBROOT/APPHOST' + filter 'system.webServer/httpProtocol/customHeaders' + property 'name' + value 'X-Xss-Protection' + action :add +end +iis_config_property 'Set X-Xss-Protection' do + ps_path 'MACHINE/WEBROOT/APPHOST' + filter "system.webServer/httpProtocol/customHeaders/add[@name='X-Xss-Protection']" + property 'value' + value '1; mode=block' +end + +# Add environment variable + value +iis_config_property 'Add login/ASPNETCORE_ENVIRONMENT' do + ps_path 'MACHINE/WEBROOT/APPHOST' + location 'Default Web site' + filter 'system.webServer/aspNetCore/environmentVariables' + property 'name' + value 'ASPNETCORE_ENVIRONMENT' + extra_add_values value: 'Test' + action :add +end diff --git a/cookbooks/iis/test/cookbooks/test/recipes/manager.rb b/cookbooks/iis/test/cookbooks/test/recipes/manager.rb new file mode 100644 index 00000000..f31fec43 --- /dev/null +++ b/cookbooks/iis/test/cookbooks/test/recipes/manager.rb @@ -0,0 +1,7 @@ +include_recipe 'iis' + +iis_manager 'IIS Manager' do + port 19500 + enable_remote_management true + log_directory 'C:\\CustomPath' +end diff --git a/cookbooks/iis/test/cookbooks/test/recipes/manager_permission.rb b/cookbooks/iis/test/cookbooks/test/recipes/manager_permission.rb new file mode 100644 index 00000000..a272e999 --- /dev/null +++ b/cookbooks/iis/test/cookbooks/test/recipes/manager_permission.rb @@ -0,0 +1,9 @@ +include_recipe 'iis' + +iis_manager 'IIS Manager' do + enable_remote_management true +end + +iis_manager_permission 'Default Web Site' do + users ['BUILTIN\\Users'] +end diff --git a/cookbooks/iis/test/cookbooks/test/recipes/module.rb b/cookbooks/iis/test/cookbooks/test/recipes/module.rb new file mode 100644 index 00000000..a4bd7cbb --- /dev/null +++ b/cookbooks/iis/test/cookbooks/test/recipes/module.rb @@ -0,0 +1,69 @@ +# +# Cookbook:: test +# Recipe:: module +# +# copyright: 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. + +include_recipe 'iis' + +directory "#{node['iis']['docroot']}\\v1_1" do + recursive true +end + +iis_app 'Default Web Site' do + path '/v1_1' + application_pool 'DefaultAppPool' + physical_path "#{node['iis']['docroot']}/v1_1" + enabled_protocols 'http,net.pipe' + action :add +end + +iis_module 'example module' do + application 'Default Web Site/v1_1' + type 'System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' + precondition 'managedHandler' + action :add +end + +f5xff_module_path = 'C:/httpmodules/F5XFF' + +directory f5xff_module_path do + recursive true + action :create +end + +cookbook_file ::File.join(f5xff_module_path, 'F5XFFHttpModule-x64.dll') do + source 'F5XFFHttpModule/x64/F5XFFHttpModule.dll' + action :create +end + +cookbook_file ::File.join(f5xff_module_path, 'F5XFFHttpModule-x86.dll') do + source 'F5XFFHttpModule/x86/F5XFFHttpModule.dll' + action :create +end + +iis_module 'F5XFFHttpModule-x64' do + module_name 'F5XFFHttpModule-x64' + precondition 'bitness64' + image ::File.join(f5xff_module_path, 'F5XFFHttpModule-x64.dll') + action [:install, :add] +end + +iis_module 'F5XFFHttpModule-x86' do + module_name 'F5XFFHttpModule-x86' + precondition 'bitness32' + image ::File.join(f5xff_module_path, 'F5XFFHttpModule-x86.dll') + action [:install, :add] +end diff --git a/cookbooks/iis/test/cookbooks/test/recipes/pool.rb b/cookbooks/iis/test/cookbooks/test/recipes/pool.rb new file mode 100644 index 00000000..2d9c8b35 --- /dev/null +++ b/cookbooks/iis/test/cookbooks/test/recipes/pool.rb @@ -0,0 +1,92 @@ +# +# Cookbook:: test +# Recipe:: pool +# +# copyright: 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. + +include_recipe 'iis' + +directory "#{node['iis']['docroot']}\\test" do + recursive true +end + +# creates a new app pool +iis_pool 'myAppPool_v1_1' do + runtime_version '2.0' + pipeline_mode :Classic + action [:add, :config, :stop] +end + +iis_pool 'test_start' do + pipeline_mode :Classic + action [:add, :config, :stop] +end + +iis_pool 'testapppool' do + thirty_two_bit false + runtime_version '4.0' + pipeline_mode :Integrated + start_mode :OnDemand + identity_type :SpecificUser + periodic_restart_schedule ['06:00:00', '14:00:00', '17:00:00'] + environment_variables ['HELLO=WORLD', 'FOO=BAR', 'ALPHA=BETA2'] + username "#{node['hostname']}\\vagrant" + password 'vagrant' + action [:add, :config] +end + +iis_pool 'passwordwithentityapppool' do + thirty_two_bit false + runtime_version '4.0' + pipeline_mode :Integrated + start_mode :OnDemand + identity_type :SpecificUser + periodic_restart_schedule ['06:00:00', '14:00:00', '17:00:00'] + environment_variables 'HELLO=WORLD' + username "#{node['hostname']}\\vagrant" + password 'vagrant&' + action [:add, :config] +end + +iis_pool 'start test_start' do + pool_name 'test_start' + action [:start] +end + +iis_pool 'My App Pool' do + runtime_version '4.0.30319' + thirty_two_bit true + pipeline_mode :Integrated + action [:add, :config, :start] +end + +iis_pool 'test_identity_type' do + identity_type :NetworkService + action [:add, :config, :start] +end + +iis_pool 'Process Model Create' do + pool_name 'Process Model Cleanup' + identity_type :SpecificUser + username "#{node['hostname']}\\vagrant" + password 'vagrant' + action [:add, :config, :start] +end + +iis_pool 'Process Model Cleanup' do + pool_name 'Process Model Cleanup' + identity_type :ApplicationPoolIdentity + action [:add, :config, :start] +end diff --git a/cookbooks/iis/test/cookbooks/test/recipes/root.rb b/cookbooks/iis/test/cookbooks/test/recipes/root.rb new file mode 100644 index 00000000..32262c77 --- /dev/null +++ b/cookbooks/iis/test/cookbooks/test/recipes/root.rb @@ -0,0 +1,30 @@ +# +# Cookbook:: test +# Recipe:: root +# +# copyright: 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. + +include_recipe 'iis' + +iis_root 'adding test html' do + add_default_documents ['test.html'] + add_mime_maps ['fileExtension=\'.dmg\',mimeType=\'application/octet-stream\''] + action :add +end + +iis_root 'remove mime types' do + delete_mime_maps ['fileExtension=\'.rpm\',mimeType=\'audio/x-pn-realaudio-plugin\'', 'fileExtension=\'.msi\',mimeType=\'application/octet-stream\''] + action :delete +end diff --git a/cookbooks/iis/test/cookbooks/test/recipes/section.rb b/cookbooks/iis/test/cookbooks/test/recipes/section.rb new file mode 100644 index 00000000..bf7de2f5 --- /dev/null +++ b/cookbooks/iis/test/cookbooks/test/recipes/section.rb @@ -0,0 +1,25 @@ +# +# Cookbook:: test +# Recipe:: site +# +# copyright: 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. + +include_recipe 'iis' + +iis_section 'unlock staticContent of default web site' do + section 'system.webServer/staticContent' + site 'Default Web Site' + action :unlock +end diff --git a/cookbooks/iis/test/cookbooks/test/recipes/site.rb b/cookbooks/iis/test/cookbooks/test/recipes/site.rb new file mode 100644 index 00000000..70c731f9 --- /dev/null +++ b/cookbooks/iis/test/cookbooks/test/recipes/site.rb @@ -0,0 +1,101 @@ +# +# Cookbook:: test +# Recipe:: site +# +# copyright: 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. + +include_recipe 'iis' +include_recipe 'iis::mod_ftp' + +directory "#{node['iis']['docroot']}\\site_test" do + recursive true +end + +directory "#{node['iis']['docroot']}\\site_test2" do + recursive true +end + +directory "#{node['iis']['docroot']}\\ftp_site_test" do + recursive true +end + +iis_site 'add/start to_be_deleted' do + site_name 'to_be_deleted' + application_pool 'DefaultAppPool' + path "#{node['iis']['docroot']}/site_test" + host_header 'localhost' + port 8081 + action [:add, :start] +end + +iis_site 'test' do + application_pool 'DefaultAppPool' + path "#{node['iis']['docroot']}/site_test" + host_header 'localhost' + action [:add, :start] +end + +iis_site 'restart to_be_deleted' do + site_name 'to_be_deleted' + action [:restart] +end + +iis_site 'test2' do + application_pool 'DefaultAppPool' + path "#{node['iis']['docroot']}/site_test2" + host_header 'localhost' + port 8080 + action [:add, :start] +end + +iis_site 'stop/delete to_be_deleted' do + site_name 'to_be_deleted' + action [:stop, :delete] +end + +iis_site 'myftpsite' do + path "#{node['iis']['docroot']}\\ftp_site_test" + application_pool 'DefaultAppPool' + bindings 'ftp/*:21:*' + action [:add, :config] +end + +directory "#{node['iis']['docroot']}\\mytest" do + action :create +end + +iis_site 'add/start MyTest' do + site_name 'MyTest' + protocol :http + port 8090 + path "#{node['iis']['docroot']}\\mytest" + action [:add, :start] +end + +iis_app 'MyTest' do + path '/testpool' + application_pool 'Test AppPool' + physical_path "#{node['iis']['docroot']}\\mytest" + enabled_protocols 'http' + action :add +end + +iis_site 'config MyTest' do + site_name 'MyTest' + protocol :http + port 8090 + path "#{node['iis']['docroot']}\\mytest" + action :config +end diff --git a/cookbooks/iis/test/cookbooks/test/recipes/vdir.rb b/cookbooks/iis/test/cookbooks/test/recipes/vdir.rb new file mode 100644 index 00000000..d90c349a --- /dev/null +++ b/cookbooks/iis/test/cookbooks/test/recipes/vdir.rb @@ -0,0 +1,93 @@ +# +# Cookbook:: test +# Recipe:: vdir +# +# copyright: 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. + +include_recipe 'iis' + +directory node['iis']['docroot'].to_s do + recursive true +end + +directory "#{node['iis']['docroot']}\\vdir_test" do + recursive true +end + +directory "#{node['iis']['docroot']}\\foo" do + recursive true +end + +directory "#{node['iis']['docroot']}\\app_test" do + recursive true +end + +directory "#{node['iis']['docroot']}\\app_test\\vdir_test2" do + recursive true +end + +iis_pool 'DefaultAppPool' do + pipeline_mode :Classic + action :add +end + +iis_site 'Default Web Site' do + protocol :http + port 80 + path node['iis']['docroot'].to_s + action [:add, :start] +end + +iis_app 'Default Web Site' do + path '/app_test' + application_pool 'DefaultAppPool' + physical_path "#{node['iis']['docroot']}/app_test" + enabled_protocols 'http,net.pipe' + action [:add, :config] +end + +iis_vdir 'Default Web Site/' do + path '/vdir_test' + physical_path "#{node['iis']['docroot']}\\vdir_test" + username 'vagrant' + password 'vagrant' + logon_method :ClearText + allow_sub_dir_config false + action [:add, :config] +end + +iis_vdir 'Creating vDir /foo for Sitename' do + application_name 'Default Web Site' + path '/foo' + physical_path "#{node['iis']['docroot']}\\foo" + action [:add, :config] +end + +iis_vdir 'Creating vDir /vdir_test2 in app' do + application_name 'Default Web Site/app_test' + path '/vdir_test2' + physical_path "#{node['iis']['docroot']}\\app_test\\vdir_test2" + action [:add, :config] +end + +iis_vdir 'Default Web Site/' do + path '/vdir_test' + physical_path "#{node['iis']['docroot']}\\vdir_test" + username 'vagrant' + password 'vagrant' + logon_method :ClearText + allow_sub_dir_config false + action [:add, :config] +end diff --git a/cookbooks/iis/test/integration/app/README.md b/cookbooks/iis/test/integration/app/README.md new file mode 100644 index 00000000..e033f342 --- /dev/null +++ b/cookbooks/iis/test/integration/app/README.md @@ -0,0 +1,3 @@ +# iis_app InSpec Profile + +This will allow the testing of iis_app until it can be added into inspec. diff --git a/cookbooks/iis/test/integration/app/controls/app_spec.rb b/cookbooks/iis/test/integration/app/controls/app_spec.rb new file mode 100644 index 00000000..6910ebf0 --- /dev/null +++ b/cookbooks/iis/test/integration/app/controls/app_spec.rb @@ -0,0 +1,24 @@ +# encoding: utf-8 +# copyright: 2017, Chef Software, Inc. +# license: All rights reserved + +title 'iis_app section' + +describe service('W3SVC') do + it { should be_installed } + it { should be_running } + its ('startmode') { should eq 'Auto' } +end + +describe iis_site('Default Web Site') do + it { should exist } + it { should be_running } + it { should have_app_pool('DefaultAppPool') } +end + +describe iis_app('/v1_1', 'Default Web Site') do + it { should exist } + it { should have_application_pool('DefaultAppPool') } + it { should have_physical_path('C:\\inetpub\\wwwroot\\v1_1') } + it { should have_protocol('http') } +end diff --git a/cookbooks/iis/test/integration/app/inspec.yml b/cookbooks/iis/test/integration/app/inspec.yml new file mode 100644 index 00000000..9b974c73 --- /dev/null +++ b/cookbooks/iis/test/integration/app/inspec.yml @@ -0,0 +1,6 @@ +name: app +title: iis_app InSpec Profile +copyright: 2017, Chef Software, Inc. +license: All Rights Reserved +summary: An InSpec Compliance Profile for iis_app +version: 0.1.0 diff --git a/cookbooks/iis/test/integration/app/libraries/.gitkeep b/cookbooks/iis/test/integration/app/libraries/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/cookbooks/iis/test/integration/app/libraries/iis_app.rb b/cookbooks/iis/test/integration/app/libraries/iis_app.rb new file mode 100644 index 00000000..a1ee26e1 --- /dev/null +++ b/cookbooks/iis/test/integration/app/libraries/iis_app.rb @@ -0,0 +1,124 @@ +# encoding: utf-8 +# frozen_string_literal: true +# check for web applications in IIS +# Usage: +# describe iis_app('/myapp', 'Website') do +# it { should exist } +# it { should have_application_pool('MyAppPool') } +# it { should have_protocols('http') } +# it { should have_site_name('Default Web Site') } +# it { should have_physical_path('C:\\inetpub\\wwwroot\\myapp') } +# it { should have_path('\\My Application') } +# end +# +# Note: this is only supported in windows 2012 and later + +class IisApp < Inspec.resource(1) + name 'iis_app' + desc 'Tests IIS application configuration on windows. Supported in server 2012+ only' + example " + describe iis_app('/myapp', 'Default Web Site') do + it { should exist } + it { should have_application_pool('MyAppPool') } + it { should have_protocols('http') } + it { should have_site_name('Default Web Site') } + it { should have_physical_path('C:\\inetpub\\wwwroot\\myapp') } + it { should have_path('\\My Application') } + end + " + + def initialize(path, site_name) + @path = path + @site_name = site_name + @cache = nil + + @app_provider = AppProvider.new(inspec) + + # verify that this resource is only supported on Windows + return skip_resource 'The `iis_app` resource is not supported on your OS.' unless inspec.os.windows? + end + + def application_pool + iis_app[:application_pool] + end + + def protocols + iis_app[:protocols] + end + + def site_name + iis_app[:site_name] + end + + def path + iis_app[:path] + end + + def physical_path + iis_app[:physical_path] + end + + def exists? + !iis_app[:path].empty? + end + + def has_site_name?(site_name) + iis_app[:site_name] == site_name + end + + def has_application_pool?(application_pool) + iis_app[:application_pool] == application_pool + end + + def has_path?(path) + iis_app[:path] == path + end + + def has_physical_path?(physical_path) + iis_app[:physical_path] == physical_path + end + + def has_protocol?(protocol) + (iis_app[:protocols].include? protocol) + end + + def to_s + "iis_app '#{@site_name}#{@path}'" + end + + def iis_app + return @cache unless @cache.nil? + @cache = @app_provider.iis_app(@path, @site_name) unless @app_provider.nil? + end +end + +class AppProvider + attr_reader :inspec + + def initialize(inspec) + @inspec = inspec + end + + # want to populate everything using one powershell command here and spit it out as json + def iis_app(path, site_name) + command = "Import-Module WebAdministration; Get-WebApplication -Name '#{path}' -Site '#{site_name}' | Select-Object * | ConvertTo-Json" + cmd = @inspec.command(command) + + begin + app = JSON.parse(cmd.stdout) + rescue JSON::ParserError => _e + return {} + end + + # map our values to a hash table + info = { + site_name: site_name, + path: path, + application_pool: app['applicationPool'], + physical_path: app['PhysicalPath'], + protocols: app['enabledProtocols'], + } + + info + end +end diff --git a/cookbooks/iis/test/integration/config_property/config_property_spec.rb b/cookbooks/iis/test/integration/config_property/config_property_spec.rb new file mode 100644 index 00000000..adf3f47f --- /dev/null +++ b/cookbooks/iis/test/integration/config_property/config_property_spec.rb @@ -0,0 +1,26 @@ +# encoding: utf-8 +# copyright: 2018, Chef Software, Inc. +# license: All rights reserved + +control 'config_property' do + title 'Check IIS properties are set' + + describe powershell("(Get-WebConfigurationProperty -PSPath \"MACHINE/WEBROOT/APPHOST\" \ + -filter \"system.applicationHost/sites/siteDefaults/logfile\" \ + -Name \"directory\").value") do + its('stdout') { should eq "D:\\logs\r\n" } + end + + describe powershell("(Get-WebConfigurationProperty -PSPath \"MACHINE/WEBROOT/APPHOST\" \ + -filter \"system.webServer/httpProtocol/customHeaders/add[@name='X-Xss-Protection']\" \ + -Name \"value\").value") do + its('stdout') { should eq "1; mode=block\r\n" } + end + + describe powershell("(Get-WebConfigurationProperty -PSPath \"MACHINE/WEBROOT/APPHOST\" \ + -Location \"Default Web site\" \ + -filter \"system.webServer/aspNetCore/environmentVariables/environmentVariable[@name='ASPNETCORE_ENVIRONMENT']\" \ + -Name \"value\").value") do + its('stdout') { should eq "Test\r\n" } + end +end diff --git a/cookbooks/iis/test/integration/default/spec/default_spec.rb b/cookbooks/iis/test/integration/default/spec/default_spec.rb new file mode 100644 index 00000000..17de5852 --- /dev/null +++ b/cookbooks/iis/test/integration/default/spec/default_spec.rb @@ -0,0 +1,30 @@ +# +# Copyright:: 2015-2019, 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. +# + +describe service('W3SVC') do + it { should be_installed } + it { should be_running } + its ('startmode') { should eq 'Auto' } +end + +# Unless we are on a 'polluted' machine, the default website should +# be present if the IIS Role was freshly installed. All our vagrant +# configurations install with the system drive at C:\ +describe iis_site('Default Web Site') do + it { should exist } + it { should be_running } + it { should have_app_pool('DefaultAppPool') } +end diff --git a/cookbooks/iis/test/integration/manager/manager.rb b/cookbooks/iis/test/integration/manager/manager.rb new file mode 100644 index 00000000..35402ada --- /dev/null +++ b/cookbooks/iis/test/integration/manager/manager.rb @@ -0,0 +1,10 @@ +control 'Manager Property' do + title 'Check manager is setup and listening correctly' + + describe port(19500) do + it { should be_listening } + end + describe windows_feature('Web-Mgmt-Service') do + it { should be_installed } + end +end diff --git a/cookbooks/iis/test/integration/manager_permission/manager_permission.rb b/cookbooks/iis/test/integration/manager_permission/manager_permission.rb new file mode 100644 index 00000000..b2417cda --- /dev/null +++ b/cookbooks/iis/test/integration/manager_permission/manager_permission.rb @@ -0,0 +1,9 @@ +control 'Manager Permissions' do + title 'Check permissions to access the manager has been correctly granted' + + describe powershell('[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Management") | Out-Null + $current = [Microsoft.Web.Management.Server.ManagementAuthorization]::GetAuthorizedUsers("Default Web Site", $false, 0, 1000) + ($current | ? { $_.ConfigurationPath -eq "/Default Web Site" } | Select-Object Name).Name') do + its('strip') { should eq 'BUILTIN\\Users' } + end +end diff --git a/cookbooks/iis/test/integration/module/README.md b/cookbooks/iis/test/integration/module/README.md new file mode 100644 index 00000000..264be453 --- /dev/null +++ b/cookbooks/iis/test/integration/module/README.md @@ -0,0 +1,3 @@ +# iis_module InSpec Profile + +This will allow the testing of iis_module until it can be added into inspec. diff --git a/cookbooks/iis/test/integration/module/controls/module_spec.rb b/cookbooks/iis/test/integration/module/controls/module_spec.rb new file mode 100644 index 00000000..aaead48d --- /dev/null +++ b/cookbooks/iis/test/integration/module/controls/module_spec.rb @@ -0,0 +1,30 @@ +# encoding: utf-8 +# copyright: 2017, Chef Software, Inc. +# license: All rights reserved + +title 'iis_module section' + +describe service('W3SVC') do + it { should be_installed } + it { should be_running } + its ('startmode') { should eq 'Auto' } +end + +describe iis_module('example module', 'Default Web Site/v1_1') do + it { should exist } + it { should have_name('example module') } + it { should have_pre_condition('managedHandler') } + it { should have_type('System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35') } +end + +describe iis_module('F5XFFHttpModule-x64') do + it { should exist } + it { should have_name('F5XFFHttpModule-x64') } + it { should have_pre_condition('bitness64') } +end + +describe iis_module('F5XFFHttpModule-x86') do + it { should exist } + it { should have_name('F5XFFHttpModule-x86') } + it { should have_pre_condition('bitness32') } +end diff --git a/cookbooks/iis/test/integration/module/inspec.yml b/cookbooks/iis/test/integration/module/inspec.yml new file mode 100644 index 00000000..3e1fd345 --- /dev/null +++ b/cookbooks/iis/test/integration/module/inspec.yml @@ -0,0 +1,6 @@ +name: module +title: iis_module InSpec Profile +copyright: 2017, Chef Software, Inc. +license: All Rights Reserved +summary: An InSpec Compliance Profile for iis_module +version: 0.1.0 diff --git a/cookbooks/iis/test/integration/module/libraries/.gitkeep b/cookbooks/iis/test/integration/module/libraries/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/cookbooks/iis/test/integration/module/libraries/iis_module.rb b/cookbooks/iis/test/integration/module/libraries/iis_module.rb new file mode 100644 index 00000000..70c744ee --- /dev/null +++ b/cookbooks/iis/test/integration/module/libraries/iis_module.rb @@ -0,0 +1,103 @@ +# encoding: utf-8 +# frozen_string_literal: true +# check for application modules in IIS +# Usage: +# describe iis_module('module_name', 'Default Web Site') do +# it { should exist } +# it { should have_name('module_name') } +# it { should have_type('System.Web.Security.FileAuthorizationModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a') } +# end +# +# Note: this is only supported in windows 2012 and later + +class IisModule < Inspec.resource(1) + name 'iis_module' + desc 'Tests IIS module configuration on windows. Supported in server 2012+ only' + example " + describe iis_module('module_name', 'Default Web Site') do + it { should exist } + it { should have_name('module_name') } + it { should have_type('System.Web.Security.FileAuthorizationModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a') } + end + " + + def initialize(module_name, application = nil) + @module_name = module_name + @application = application + @cache = nil + + @module_provider = ModuleProvider.new(inspec) + + # verify that this resource is only supported on Windows + return skip_resource 'The `iis_module` resource is not supported on your OS.' unless inspec.os.windows? + end + + def name + iis_module[:name] + end + + def type + iis_module[:type] + end + + def pre_condition + iis_module[:pre_condition] + end + + def exists? + !iis_module.nil? && !iis_module[:name].nil? + end + + def has_name?(module_name) + iis_module.nil? ? false : iis_module[:name] == module_name + end + + def has_type?(module_type) + iis_module.nil? ? false : iis_module[:type] == module_type + end + + def has_pre_condition?(pre_condition) + iis_module.nil? ? false : iis_module[:pre_condition] == pre_condition + end + + def to_s + "iis_module `#{@module_name}` - `#{@application}`" + end + + def iis_module + return @cache unless @cache.nil? + @cache = @module_provider.iis_module(@module_name, @application) unless @module_provider.nil? + end +end + +class ModuleProvider + attr_reader :inspec + + def initialize(inspec) + @inspec = inspec + end + + # want to populate everything using one powershell command here and spit it out as json + def iis_module(module_name, application = nil) + command = if application.nil? + "Import-Module WebAdministration; Get-WebGlobalModule -Name '#{module_name}' | Select-Object name, type, preCondition | ConvertTo-Json" + else + "Import-Module WebAdministration; Get-WebManagedModule -Name '#{module_name}' -PSPath 'IIS:\\sites\\#{application}' | Select-Object name, type, preCondition | ConvertTo-Json" + end + + cmd = @inspec.command(command) + + begin + mod = JSON.parse(cmd.stdout) + rescue JSON::ParserError => _e + return {} + end + + # map our values to a hash table + { + name: mod['name'], + type: mod['type'], + pre_condition: mod['preCondition'], + } + end +end diff --git a/cookbooks/iis/test/integration/pool/README.md b/cookbooks/iis/test/integration/pool/README.md new file mode 100644 index 00000000..8e52bbc2 --- /dev/null +++ b/cookbooks/iis/test/integration/pool/README.md @@ -0,0 +1,3 @@ +# Example InSpec Profile + +This example shows the implementation of an InSpec [profile](../../docs/profiles.rst). diff --git a/cookbooks/iis/test/integration/pool/controls/pool_spec.rb b/cookbooks/iis/test/integration/pool/controls/pool_spec.rb new file mode 100644 index 00000000..f12a4489 --- /dev/null +++ b/cookbooks/iis/test/integration/pool/controls/pool_spec.rb @@ -0,0 +1,69 @@ +# encoding: utf-8 +# copyright: 2017, Chef Software, Inc. +# license: All rights reserved + +title 'iis_app section' + +describe service('W3SVC') do + it { should be_installed } + it { should be_running } + its ('startmode') { should eq 'Auto' } +end + +describe iis_pool('myAppPool_v1_1') do + it { should exist } + it { should_not be_running } + its('managed_runtime_version') { should eq 'v2.0' } + it { should have_name('myAppPool_v1_1') } + it { should have_queue_length(1000) } +end + +describe iis_pool('testapppool') do + it { should exist } + it { should be_running } + its('managed_runtime_version') { should eq 'v4.0' } + its('managed_pipeline_mode') { should eq 'Integrated' } + it { should have_name('testapppool') } + its('start_mode') { should eq 'OnDemand' } + its('identity_type') { should eq 'SpecificUser' } + its('periodic_restart_schedule') { should eq ['06:00:00', '14:00:00', '17:00:00'] } + its('environment_variables') { should eq ['ALPHA=BETA2', 'FOO=BAR', 'HELLO=WORLD'] } + its('username') { should include('\\vagrant') } + its('password') { should eq 'vagrant' } +end + +describe iis_pool('passwordwithentityapppool') do + it { should exist } + its('password') { should eq 'vagrant&' } + its('environment_variables') { should eq ['HELLO=WORLD'] } +end + +describe iis_pool('test_start') do + it { should exist } + it { should be_running } + its('managed_pipeline_mode') { should eq 'Classic' } + it { should have_name('test_start') } +end + +describe iis_pool('My App Pool') do + it { should exist } + it { should be_running } + it { should be_enable_32bit_app_on_win64 } + its('managed_runtime_version') { should eq 'v4.0.30319' } + its('managed_pipeline_mode') { should eq 'Integrated' } + it { should have_name('My App Pool') } +end + +describe iis_pool('test_identity_type') do + it { should exist } + it { should be_running } + its('identity_type') { should eq 'NetworkService' } +end + +describe iis_pool('Process Model Cleanup') do + it { should exist } + it { should be_running } + its('identity_type') { should eq 'ApplicationPoolIdentity' } + its('username') { should eq '' } + its('password') { should eq '' } +end diff --git a/cookbooks/iis/test/integration/pool/inspec.yml b/cookbooks/iis/test/integration/pool/inspec.yml new file mode 100644 index 00000000..cc2c9f0c --- /dev/null +++ b/cookbooks/iis/test/integration/pool/inspec.yml @@ -0,0 +1,8 @@ +name: pool +title: InSpec Profile +maintainer: The Authors +copyright: The Authors +copyright_email: you@example.com +license: All Rights Reserved +summary: An InSpec Compliance Profile +version: 0.1.0 diff --git a/cookbooks/iis/test/integration/pool/libraries/.gitkeep b/cookbooks/iis/test/integration/pool/libraries/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/cookbooks/iis/test/integration/pool/libraries/iis_pool.rb b/cookbooks/iis/test/integration/pool/libraries/iis_pool.rb new file mode 100644 index 00000000..6f028f0e --- /dev/null +++ b/cookbooks/iis/test/integration/pool/libraries/iis_pool.rb @@ -0,0 +1,255 @@ +# encoding: utf-8 +# frozen_string_literal: true +# check for application pools in IIS +# Usage: +# describe iis_pool('DefaultAppPool') do +# it { should exist } +# it { should have_name('DefaultAppPool') } +# it { should have_queue_length(1000) } +# it { should be_running } +# end +# +# Note: this is only supported in windows 2012 and later + +class IisPool < Inspec.resource(1) + name 'iis_pool' + desc 'Tests IIS application pool\'s configuration on windows. Supported in server 2012+ only' + example " + describe iis_pool('DefaultAppPool') do + it { should exist } + it { should have_name('DefaultAppPool') } + it { should have_queue_length(1000) } + is { should be_running } + end + " + + def initialize(pool_name) + @pool_name = pool_name + @cache = nil + + @pool_provider = PoolProvider.new(inspec) + + # verify that this resource is only supported on Windows + return skip_resource 'The `iis_pool` resource is not supported on your OS.' unless inspec.os.windows? + end + + def name + iis_pool[:name] + end + + def queue_length + iis_pool[:queue_length] + end + + def auto_start? + iis_pool[:auto_start] + end + + def enable_32bit_app_on_win64? + iis_pool[:enable_32bit_app_on_win64] + end + + def managed_runtime_version + iis_pool[:managed_runtime_version] + end + + def managed_runtime_loader + iis_pool[:managed_runtime_loader] + end + + def enable_configuration_override? + iis_pool[:enable_configuration_override] + end + + def managed_pipeline_mode + iis_pool[:managed_pipeline_mode] + end + + def pass_anonymous_token + iis_pool[:pass_anonymous_token] + end + + def start_mode + iis_pool[:start_mode] + end + + def state + iis_pool[:state] + end + + def item_x_path + iis_pool[:item_x_path] + end + + def worker_processes + iis_pool[:worker_processes] + end + + def identity_type + iis_pool[:process_model][:identity_type] + end + + def username + iis_pool[:process_model][:username] + end + + def password + iis_pool[:process_model][:password] + end + + def periodic_restart_schedule + iis_pool[:recycling][:periodic_restart][:schedule] + end + + def environment_variables + iis_pool[:environment_variables] + end + + def exists? + !iis_pool.nil? && !iis_pool[:name].nil? + end + + def running? + iis_pool.nil? ? false : (iis_pool[:state] == 'Started') + end + + def has_name?(pool_name) + iis_pool.nil? ? false : iis_pool[:name] == pool_name + end + + def has_queue_length?(queue_length) + iis_pool.nil? ? false : iis_pool[:queue_length] == queue_length + end + + def to_s + "iis_pool '#{@pool_name}' " + end + + def iis_pool + return @cache unless @cache.nil? + @cache = @pool_provider.iis_pool(@pool_name) unless @pool_provider.nil? + end +end + +class PoolProvider + attr_reader :inspec + + def initialize(inspec) + @inspec = inspec + end + + # want to populate everything using one powershell command here and spit it out as json + def iis_pool(pool_name) + command = "Import-Module WebAdministration; Get-Item \"IIS:\\AppPools\\#{pool_name}\" | Select-Object name, queueLength, autoStart, enable32BitAppOnWin64, managedRuntimeVersion, managedRuntimeLoader, enableConfigurationOverride, managedPipelineMode, passAnonymousToken, startMode, state, ItemXPath | ConvertTo-Json" + cmd = @inspec.command(command) + command_process_model = "(Get-Item \"IIS:\\AppPools\\#{pool_name}\").processModel | Select-Object identityType, userName, password, loadUserProfile, setProfileEnvironment, logonType, manualGroupMembership, idleTimeout, idleTimeoutAction, maxProcesses, shutdownTimeLimit, startupTimeLimit, pingingEnabled, pingInterval, pingResponseTime, logEventOnProcessModel | ConvertTo-Json" + cmd_process_model = @inspec.command(command_process_model) + command_recycling = "(Get-Item \"IIS:\\AppPools\\#{pool_name}\").recycling | Select-Object disallowOverlappingRotation, disallowRotationOnConfigChange, logEventOnRecycle | ConvertTo-Json" + cmd_recycling = @inspec.command(command_recycling) + command_recycling_periodic_restart = "(Get-Item \"IIS:\\AppPools\\#{pool_name}\").recycling.periodicRestart | Select-Object memory, privateMemory, requests, time | ConvertTo-Json" + cmd_recycling_periodic_restart = @inspec.command(command_recycling_periodic_restart) + command_recycling_period_restart_schedule = "(Get-Item \"IIS:\\AppPools\\#{pool_name}\").recycling.periodicRestart.schedule | Select-Object Collection | ConvertTo-Json" + cmd_recycling_period_restart_schedule = @inspec.command(command_recycling_period_restart_schedule) + command_failing = "(Get-Item \"IIS:\\AppPools\\#{pool_name}\").failure | Select-Object loadBalancerCapabilities, orphanWorkerProcess, orphanActionExe, orphanActionParams, rapidFailProtection, rapidFailProtectionInterval, rapidFailProtectionMaxCrashes, autoShudownExe, autoShutdownParams | ConvertTo-Json" + cmd_failing = @inspec.command(command_failing) + command_cpu = "(Get-Item \"IIS:\\AppPools\\#{pool_name}\").cpu | Select-Object limit, action, resetInterval, smpAffinitized, smpProcessorAffinityMask, smpProcessorAffinityMask2, processorGroup, numaNodeAssignment, numaNodeAffinityMode | ConvertTo-Json" + cmd_cpu = @inspec.command(command_cpu) + command_worker_processes = "(Get-Item \"IIS:\\AppPools\\#{pool_name}\").workerProcesses | Select-Object Collection | ConvertTo-Json" + cmd_worker_processes = @inspec.command(command_worker_processes) + command_environment_variables = "(Get-Item \"IIS:\\AppPools\\#{pool_name}\").environmentVariables | Select-Object Collection | ConvertTo-Json" + cmd_environment_variables = @inspec.command(command_environment_variables) + + begin + pool = JSON.parse(cmd.stdout) + pool_process_model = JSON.parse(cmd_process_model.stdout) + pool_recyling = JSON.parse(cmd_recycling.stdout) + pool_recycling_periodic_restart = JSON.parse(cmd_recycling_periodic_restart.stdout) + pool_recycling_period_restart_schedule = JSON.parse(cmd_recycling_period_restart_schedule.stdout) + pool_failing = JSON.parse(cmd_failing.stdout) + pool_cpu = JSON.parse(cmd_cpu.stdout) + pool_worker_processes = JSON.parse(cmd_worker_processes.stdout) + pool_environment_variables = JSON.parse(cmd_environment_variables.stdout) + rescue JSON::ParserError => _e + return {} + end + + restart_schedules = [] + pool_recycling_period_restart_schedule['Collection'].each { |schedule| restart_schedules.push(schedule['value']) } + + worker_processes = [] + pool_worker_processes['Collection'].each { |process| worker_processes.push(process_id: process['processId'], handles: process['Handles'], state: process['state'], start_time: process['StartTime']) } + + environment_variables = [] + pool_environment_variables['Collection'].each { |environment_variable| environment_variables.push("#{environment_variable['name']}=#{environment_variable['value']}") } + + # map our values to a hash table + { + name: pool['name'], + queue_length: pool['queueLength'], + auto_start: pool['autoStart'], + enable_32bit_app_on_win64: pool['enable32BitAppOnWin64'], + managed_runtime_version: pool['managedRuntimeVersion'], + managed_runtime_loader: pool['managedRuntimeLoader'], + enable_configuration_override: pool['enableConfigurationOverride'], + managed_pipeline_mode: pool['managedPipelineMode'], + pass_anonymous_token: pool['passAnonymousToken'], + start_mode: pool['startMode'], + state: pool['state'], + item_x_path: pool['ItemXPath'], + process_model: { + identity_type: pool_process_model['identityType'], + username: pool_process_model['userName'], + password: pool_process_model['password'], + load_user_profile: pool_process_model['loadUserProfile'], + set_profile_environment: pool_process_model['setProfileEnvironment'], + logon_type: pool_process_model['logonType'], + manual_group_membership: pool_process_model['manualGroupMembership'], + idle_timeout: "#{pool_process_model['idleTimeout']['Days']}.#{pool_process_model['idleTimeout']['Hours']}:#{pool_process_model['idleTimeout']['Minutes']}:#{pool_process_model['idleTimeout']['Seconds']}", + idle_timeout_action: pool_process_model['idleTimeoutAction'], + max_processes: pool_process_model['maxProcesses'], + shutdown_time_limit: "#{pool_process_model['shutdownTimeLimit']['Days']}.#{pool_process_model['shutdownTimeLimit']['Hours']}:#{pool_process_model['shutdownTimeLimit']['Minutes']}:#{pool_process_model['shutdownTimeLimit']['Second']}", + startup_time_limit: "#{pool_process_model['startupTimeLimit']['Days']}.#{pool_process_model['startupTimeLimit']['Hours']}:#{pool_process_model['startupTimeLimit']['Minutes']}:#{pool_process_model['startupTimeLimit']['Seconds']}", + pinging_enabled: pool_process_model['pingingEnabled'], + ping_interval: "#{pool_process_model['pingInterval']['Days']}.#{pool_process_model['pingInterval']['Hours']}:#{pool_process_model['pingInterval']['Minutes']}:#{pool_process_model['pingInterval']['Seconds']}", + ping_response_time: "#{pool_process_model['pingResponseTime']['Days']}.#{pool_process_model['pingResponseTime']['Hours']}:#{pool_process_model['pingResponseTime']['Minutes']}:#{pool_process_model['pingResponseTime']['Second']}", + log_event_on_process_model: pool_process_model['logEventOnProcessModel'], + }, + recycling: { + disallow_overlapping_rotation: pool_recyling['disallowOverlappingRotation'], + disallow_rotation_on_config_change: pool_recyling['disallowRotationOnConfigChange'], + log_event_on_recycle: pool_recyling['logEventOnRecycle'], + periodic_restart: { + memory: pool_recycling_periodic_restart['memory'], + privateMemory: pool_recycling_periodic_restart['privateMemory'], + requests: pool_recycling_periodic_restart['requests'], + time: "#{pool_recycling_periodic_restart['time']['Days']}.#{pool_recycling_periodic_restart['time']['Hours']}:#{pool_recycling_periodic_restart['time']['Minutes']}:#{pool_recycling_periodic_restart['time']['Seconds']}", + schedule: restart_schedules, + }, + }, + failing: { + loadBalancerCapabilities: pool_failing['loadBalancerCapabilities'], + orphanWorkerProcess: pool_failing['orphanWorkerProcess'], + orphanActionExe: pool_failing['orphanActionExe'], + orphanActionParams: pool_failing['orphanActionParams'], + rapidFailProtection: pool_failing['rapidFailProtection'], + rapidFailProtectionInterval: "#{pool_failing['rapidFailProtectionInterval']['Days']}.#{pool_failing['rapidFailProtectionInterval']['Hours']}:#{pool_failing['rapidFailProtectionInterval']['Minutes']}:#{pool_failing['rapidFailProtectionInterval']['Seconds']}", + rapidFailProtectionMaxCrashes: pool_failing['rapidFailProtectionMaxCrashes'], + autoShudownExe: pool_failing['autoShudownExe'], + autoShutdownParam: pool_failing['autoShutdownParam'], + }, + cpu: { + limit: pool_cpu['limit'], + action: pool_cpu['action'], + resetInterval: "#{pool_cpu['resetInterval']['Days']}.#{pool_cpu['resetInterval']['Hours']}:#{pool_cpu['resetInterval']['Minutes']}:#{pool_cpu['resetInterval']['Seconds']}", + smpAffinitized: pool_cpu['smpAffinitized'], + smpProcessorAffinityMask: pool_cpu['smpProcessorAffinityMask'], + smpProcessorAffinityMask2: pool_cpu['smpProcessorAffinityMask2'], + processorGroup: pool_cpu['processorGroup'], + numaNodeAssignment: pool_cpu['numaNodeAssignment'], + numaNodeAffinityMode: pool_cpu['numaNodeAffinityMode'], + }, + environment_variables: environment_variables, + worker_processes: worker_processes, + } + end +end diff --git a/cookbooks/iis/test/integration/root/README.md b/cookbooks/iis/test/integration/root/README.md new file mode 100644 index 00000000..17ab0460 --- /dev/null +++ b/cookbooks/iis/test/integration/root/README.md @@ -0,0 +1,3 @@ +# `iis_root` InSpec Profile + +This will allow the testing of `iis_root` until it can be added into inspec. diff --git a/cookbooks/iis/test/integration/root/controls/root_spec.rb b/cookbooks/iis/test/integration/root/controls/root_spec.rb new file mode 100644 index 00000000..24220dad --- /dev/null +++ b/cookbooks/iis/test/integration/root/controls/root_spec.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 +# copyright: 2017, Chef Software, Inc. +# license: All rights reserved + +title 'iis_app section' + +describe service('W3SVC') do + it { should be_installed } + it { should be_running } + its ('startmode') { should eq 'Auto' } +end + +describe iis_root do + it { should have_document('test.html') } + it { should_not have_document('not_there.html') } + its('default_documents') { should eq ['test.html', 'Default.htm', 'Default.asp', 'index.htm', 'index.html', 'iisstart.htm', 'default.aspx'] } + it { should have_mime("fileExtension='.323',mimeType='text/h323'") } + it { should have_mime("fileExtension='.dmg',mimeType='application/octet-stream'") } + it { should_not have_mime("fileExtension='.rpm',mimeType='audio/x-pn-realaudio-plugin'") } + it { should_not have_mime("fileExtension='.msi',mimeType='application/octet-stream'") } +end diff --git a/cookbooks/iis/test/integration/root/inspec.yml b/cookbooks/iis/test/integration/root/inspec.yml new file mode 100644 index 00000000..97db2d8d --- /dev/null +++ b/cookbooks/iis/test/integration/root/inspec.yml @@ -0,0 +1,6 @@ +name: root +title: iis_root InSpec Profile +copyright: 2017, Chef Software, Inc. +license: All Rights Reserved +summary: An InSpec Compliance Profile for iis_root +version: 0.1.0 diff --git a/cookbooks/iis/test/integration/root/libraries/.gitkeep b/cookbooks/iis/test/integration/root/libraries/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/cookbooks/iis/test/integration/root/libraries/iis_root.rb b/cookbooks/iis/test/integration/root/libraries/iis_root.rb new file mode 100644 index 00000000..8962cffe --- /dev/null +++ b/cookbooks/iis/test/integration/root/libraries/iis_root.rb @@ -0,0 +1,91 @@ +# encoding: utf-8 +# frozen_string_literal: true +# check for application pools in IIS +# Usage: +# describe iis_root() do +# it { should have_document('index.htm') } +# it { should have_mime("fileExtension='.323',mimeType='text/h323'") } +# end +# +# Note: this is only supported in windows 2012 and later + +class IisRoot < Inspec.resource(1) + name 'iis_root' + desc 'Tests IIS default documents and mime types configuration on windows. Supported in server 2012+ only' + example " + describe iis_root() do + it { should have_document('index.htm') } + it { should have_mime(\"fileExtension='.323',mimeType='text/h323'\") } + end + " + + def initialize + @cache = nil + + @root_provider = RootProvider.new(inspec) + + # verify that this resource is only supported on Windows + return skip_resource 'The `iis_root` resource is not supported on your OS.' unless inspec.os.windows? + end + + def default_documents + iis_root[:default_documents] + end + + def mime_maps + iis_root[:mime_maps] + end + + def has_document?(document) + iis_root.nil? ? false : (iis_root[:default_documents].include? document) + end + + def has_mime?(mime) + iis_root.nil? ? false : (iis_root[:mime_maps].include? mime) + end + + def to_s + 'iis_root config' + end + + def iis_root + return @cache unless @cache.nil? + @cache = @root_provider.iis_root unless @root_provider.nil? + end +end + +class RootProvider + attr_reader :inspec + + def initialize(inspec) + @inspec = inspec + end + + # want to populate everything using one powershell command here and spit it out as json + def iis_root + command_default_documents = 'Import-Module WebAdministration; Get-WebConfiguration -Filter /system.webServer/defaultDocument/files/add -PSPath MACHINE/WEBROOT/APPHOST | Select-Object value | ConvertTo-JSON' + cmd_default_documents = @inspec.command(command_default_documents) + + command_mime_maps = 'Get-WebConfiguration -Filter system.webServer/staticContent/mimeMap -PSPath MACHINE/WEBROOT/APPHOST | Select-Object fileExtension, mimeType | ConvertTo-Json' + cmd_mime_maps = @inspec.command(command_mime_maps) + + begin + docs = JSON.parse(cmd_default_documents.stdout) + mimes = JSON.parse(cmd_mime_maps.stdout) + rescue JSON::ParserError => _e + return {} + end + + default_documents = [] + docs.each { |doc| default_documents.push(doc['value']) } + + mime_maps = [] + mimes.each { |mime| mime_maps.push("fileExtension='#{mime['fileExtension']}',mimeType='#{mime['mimeType']}'") } + + # map our values to a hash table + { + default_documents: default_documents, + mime_maps: mime_maps, + } + end +end diff --git a/cookbooks/iis/test/integration/section/README.md b/cookbooks/iis/test/integration/section/README.md new file mode 100644 index 00000000..b9ca6a8f --- /dev/null +++ b/cookbooks/iis/test/integration/section/README.md @@ -0,0 +1,3 @@ +# `iis_section` InSpec Profile + +This will allow the testing of `iis_section` until it can be added into inspec. diff --git a/cookbooks/iis/test/integration/section/controls/section_spec.rb b/cookbooks/iis/test/integration/section/controls/section_spec.rb new file mode 100644 index 00000000..600c4e55 --- /dev/null +++ b/cookbooks/iis/test/integration/section/controls/section_spec.rb @@ -0,0 +1,17 @@ +# encoding: utf-8 +# copyright: 2017, Chef Software, Inc. +# license: All rights reserved + +title 'iis_section section' + +describe service('W3SVC') do + it { should be_installed } + it { should be_running } + its ('startmode') { should eq 'Auto' } +end + +describe iis_section('system.webServer/staticContent', 'Default Web Site') do + it { should exist } + it { should have_override_mode('Allow') } + it { should have_override_mode_effective('Allow') } +end diff --git a/cookbooks/iis/test/integration/section/inspec.yml b/cookbooks/iis/test/integration/section/inspec.yml new file mode 100644 index 00000000..7a311b27 --- /dev/null +++ b/cookbooks/iis/test/integration/section/inspec.yml @@ -0,0 +1,6 @@ +name: section +title: iis_section InSpec Profile +copyright: 2017, Chef Software, Inc. +license: All Rights Reserved +summary: An InSpec Compliance Profile for iis_section +version: 0.1.0 diff --git a/cookbooks/iis/test/integration/section/libraries/.gitkeep b/cookbooks/iis/test/integration/section/libraries/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/cookbooks/iis/test/integration/section/libraries/iis_section.rb b/cookbooks/iis/test/integration/section/libraries/iis_section.rb new file mode 100644 index 00000000..ca9af53e --- /dev/null +++ b/cookbooks/iis/test/integration/section/libraries/iis_section.rb @@ -0,0 +1,99 @@ +# encoding: utf-8 +# frozen_string_literal: true +# check for sections in IIS +# Usage: +# describe iis_section('//staticContent', 'Default Web Site') do +# it { should exist } +# it { should have_override_mode('Allow') } +# it { should have_override_mode_effective('Allow') } +# end +# +# Note: this is only supported in windows 2012 and later + +class IisSection < Inspec.resource(1) + name 'iis_section' + desc 'Tests IIS section on windows. Supported in server 2012+ only' + example " + describe iis_section('//staticContent', 'Default Web Site') do + it { should exist } + it { should have_override_mode('Allow') } + it { should have_override_mode_effective('Allow') } + end + " + + def initialize(section, location) + @section = section + @location = location + @cache = nil + + @section_provider = SectionProvider.new(inspec) + + # verify that this resource is only supported on Windows + skip_resource 'The `iis_section` resource is not supported on your OS.' unless inspec.os.windows? + end + + def is_locked + iis_section[:is_locked] + end + + def override_mode + iis_section[:override_mode] + end + + def override_mode_effective + iis_section[:override_mode_effective] + end + + def exists? + !iis_section[:override_mode].empty? + end + + def has_locked?(locked) + iis_section[:is_locked] == locked + end + + def has_override_mode?(override_mode) + iis_section[:override_mode] == override_mode + end + + def has_override_mode_effective?(effective_override) + iis_section[:override_mode_effective] == effective_override + end + + def to_s + "iis_section section: '#{@section}' - location: '#{@location}'" + end + + def iis_section + return @cache unless @cache.nil? + @cache = @section_provider.iis_section(@section, @location) unless @section_provider.nil? + end +end + +class SectionProvider + attr_reader :inspec + + def initialize(inspec) + @inspec = inspec + end + + # want to populate everything using one powershell command here and spit it out as json + def iis_section(section, location) + command = "Import-Module WebAdministration; get-webconfiguration -Filter '#{section}' -PSPath 'MACHINE/WEBROOT/APPHOST' -Location '#{location}' -metadata | Select-Object IsLocked, OverrideMode, OverrideModeEffective | ConvertTo-JSON" + cmd = @inspec.command(command) + override_mode_enumeration = %w(N/A Inherit Allow Deny Unknown) + + begin + section = JSON.parse(cmd.stdout) + rescue JSON::ParserError => _e + return {} + end + + # map our values to a hash table + { + is_locked: section['IsLocked'], + override_mode: override_mode_enumeration[section['OverrideMode']], + override_mode_effective: override_mode_enumeration[section['OverrideModeEffective']], + } + end +end diff --git a/cookbooks/iis/test/integration/site/site_spec.rb b/cookbooks/iis/test/integration/site/site_spec.rb new file mode 100644 index 00000000..452dd5fb --- /dev/null +++ b/cookbooks/iis/test/integration/site/site_spec.rb @@ -0,0 +1,58 @@ +# +# Copyright:: 2017-2019, 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. +# + +describe service('W3SVC') do + it { should be_installed } + it { should be_running } + its ('startmode') { should eq 'Auto' } +end + +# Unless we are on a 'polluted' machine, the default website should +# be present if the IIS Role was freshly installed. All our vagrant +# configurations install with the system drive at C:\ +describe iis_site('test') do + it { should exist } + it { should be_running } + it { should have_app_pool('DefaultAppPool') } +end + +describe iis_site('test2') do + it { should exist } + it { should be_running } + it { should have_app_pool('DefaultAppPool') } + its('bindings') { should eq ['http *:8080:localhost'] } +end + +describe iis_site('to_be_deleted') do + it { should_not exist } + it { should_not be_running } +end + +describe iis_site('myftpsite') do + it { should exist } + it { should be_running } + its('bindings') { should eq ['ftp *:21:*'] } +end + +describe iis_site('mytest') do + it { should exist } + it { should be_running } + its('bindings') { should eq ['http *:8090:'] } +end + +describe port(8090) do + it { should be_listening } +end diff --git a/cookbooks/iis/test/integration/vdir/README.md b/cookbooks/iis/test/integration/vdir/README.md new file mode 100644 index 00000000..a8f4d1fa --- /dev/null +++ b/cookbooks/iis/test/integration/vdir/README.md @@ -0,0 +1,3 @@ +# `iis_vdir` InSpec Profile + +This will allow the testing of `iis_vdir` until it can be added into inspec. diff --git a/cookbooks/iis/test/integration/vdir/controls/vdir_spec.rb b/cookbooks/iis/test/integration/vdir/controls/vdir_spec.rb new file mode 100644 index 00000000..5a45906d --- /dev/null +++ b/cookbooks/iis/test/integration/vdir/controls/vdir_spec.rb @@ -0,0 +1,36 @@ +# encoding: utf-8 +# copyright: 2017, Chef Software, Inc. +# license: All rights reserved + +title 'iis_vdir section' + +describe service('W3SVC') do + it { should be_installed } + it { should be_running } + its ('startmode') { should eq 'Auto' } +end + +describe iis_vdir('/vdir_test', 'Default Web Site') do + it { should exist } + it { should have_path('/vdir_test') } + it { should have_physical_path('C:\\inetpub\\wwwroot\\vdir_test') } + it { should have_username('vagrant') } + it { should have_password('vagrant') } + it { should have_logon_method('ClearText') } + it { should have_allow_sub_dir_config(false) } +end + +describe iis_vdir('/foo', 'Default Web Site') do + it { should exist } + it { should have_path('/foo') } + it { should have_physical_path('C:\\inetpub\\wwwroot\\foo') } +end + +describe iis_vdir('/vdir_test2', 'Default Web Site/app_test') do + it { should exist } + it { should have_path('/vdir_test2') } + it { should have_physical_path('C:\\inetpub\\wwwroot\\app_test\\vdir_test2') } + it { should have_logon_method('ClearText') } + it { should have_username('') } + it { should have_password('') } +end diff --git a/cookbooks/iis/test/integration/vdir/inspec.yml b/cookbooks/iis/test/integration/vdir/inspec.yml new file mode 100644 index 00000000..24a4a419 --- /dev/null +++ b/cookbooks/iis/test/integration/vdir/inspec.yml @@ -0,0 +1,6 @@ +name: vdir +title: iis_vdir InSpec Profile +copyright: 2017, Chef Software, Inc. +license: All Rights Reserved +summary: An InSpec Compliance Profile for iis_vdir +version: 0.1.0 diff --git a/cookbooks/iis/test/integration/vdir/libraries/.gitkeep b/cookbooks/iis/test/integration/vdir/libraries/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/cookbooks/iis/test/integration/vdir/libraries/iis_vdir.rb b/cookbooks/iis/test/integration/vdir/libraries/iis_vdir.rb new file mode 100644 index 00000000..07bf2822 --- /dev/null +++ b/cookbooks/iis/test/integration/vdir/libraries/iis_vdir.rb @@ -0,0 +1,147 @@ +# encoding: utf-8 +# frozen_string_literal: true +# check for virtual directories in IIS +# Usage: +# describe iis_vdir('Default Web Site', '/vdir_test') do +# it { should exist } +# it { should have_path('/vdir_test') } +# it { should have_physical_path('C:\\inetpub\\wwwroot\\vdir_test') } +# it { should have_username('vagrant') } +# it { should have_password('vagrant') } +# it { should have_logon_method('ClearText') } +# it { should have_allow_sub_dir_config(false) } +# end +# +# Note: this is only supported in windows 2012 and later + +class IisVdir < Inspec.resource(1) + name 'iis_vdir' + desc 'Tests IIS application configuration on windows. Supported in server 2012+ only' + example " + describe iis_vdir('Default Web Site', '/vdir_test') do + it { should exist } + it { should have_path('/vdir_test') } + it { should have_physical_path('C:\\inetpub\\wwwroot\\vdir_test') } + it { should have_username('vagrant') } + it { should have_password('vagrant') } + it { should have_logon_method('ClearText') } + it { should have_allow_sub_dir_config(false) } + end + " + + def initialize(path, application_name) + @path = path + @application_name = application_name + @cache = nil + + @vdir_provider = VdirProvider.new(inspec) + + # verify that this resource is only supported on Windows + skip_resource 'The `iis_vdir` resource is not supported on your OS.' unless inspec.os.windows? + end + + def application_name + iis_vdir[:application_name] + end + + def path + iis_vdir[:path] + end + + def physical_path + iis_vdir[:physical_path] + end + + def username + iis_vdir[:username] + end + + def password + iis_vdir[:password] + end + + def logon_method + iis_vdir[:logon_method] + end + + def allow_sub_dir_config + iis_vdir[:allow_sub_dir_config] + end + + def exists? + !iis_vdir[:path].empty? + end + + def has_application_name?(application_name) + iis_vdir[:application_name] == application_name + end + + def has_path?(path) + iis_vdir[:path] == path + end + + def has_physical_path?(physical_path) + iis_vdir[:physical_path] == physical_path + end + + def has_password?(password) + iis_vdir[:password] == password + end + + def has_username?(username) + iis_vdir[:username] == username + end + + def has_logon_method?(method) + iis_vdir[:logon_method] == method + end + + def has_allow_sub_dir_config?(allow) + iis_vdir[:allow_sub_dir_config] == allow + end + + def to_s + "iis_vdir '#{@application_name}#{@path}'" + end + + def iis_vdir + return @cache unless @cache.nil? + @cache = @vdir_provider.iis_vdir(@path, @application_name) unless @vdir_provider.nil? + end +end + +class VdirProvider + attr_reader :inspec + + def initialize(inspec) + @inspec = inspec + end + + # want to populate everything using one powershell command here and spit it out as json + def iis_vdir(path, application_name) + site_app = application_name.split('/', 2) + + command = "Import-Module WebAdministration; Get-WebVirtualDirectory -Site \"#{site_app[0]}\"" + command = "#{command.dup} -Application \"#{site_app[1]}\"" if site_app.length > 1 + command = "#{command.dup} -Name \"#{path}\" | Select-Object path, physicalPath, userName, password, logonMethod, allowSubDirConfig, PSPath, ItemXPath | ConvertTo-Json" + cmd = @inspec.command(command) + + begin + vdir = JSON.parse(cmd.stdout) + Log.info(vdir) + rescue JSON::ParserError => _e + return {} + end + + # map our values to a hash table + { + application_name: application_name, + path: path, + physical_path: vdir['physicalPath'], + username: vdir['userName'], + password: vdir['password'], + logon_method: vdir['logonMethod'], + allow_sub_dir_config: vdir['allowSubDirConfig'], + } + end +end From 056a716fb34319126bec3297fc529b28952a845b Mon Sep 17 00:00:00 2001 From: Suyash Mohan Date: Mon, 6 Apr 2020 15:36:57 +0800 Subject: [PATCH 5/5] add chocolatey --- cookbooks/chocolatey/CHANGELOG.md | 110 +++++++ cookbooks/chocolatey/README.md | 45 +++ cookbooks/chocolatey/attributes/default.rb | 11 + cookbooks/chocolatey/files/install.ps1 | 345 +++++++++++++++++++++ cookbooks/chocolatey/libraries/helpers.rb | 55 ++++ cookbooks/chocolatey/metadata.json | 1 + cookbooks/chocolatey/recipes/default.rb | 40 +++ 7 files changed, 607 insertions(+) create mode 100644 cookbooks/chocolatey/CHANGELOG.md create mode 100644 cookbooks/chocolatey/README.md create mode 100644 cookbooks/chocolatey/attributes/default.rb create mode 100644 cookbooks/chocolatey/files/install.ps1 create mode 100644 cookbooks/chocolatey/libraries/helpers.rb create mode 100644 cookbooks/chocolatey/metadata.json create mode 100644 cookbooks/chocolatey/recipes/default.rb diff --git a/cookbooks/chocolatey/CHANGELOG.md b/cookbooks/chocolatey/CHANGELOG.md new file mode 100644 index 00000000..8323621e --- /dev/null +++ b/cookbooks/chocolatey/CHANGELOG.md @@ -0,0 +1,110 @@ +# Changelog for Chocolatey cookbook + +## v2.0.1 (2018-07-03) + +- Remove mentions of the package provider from the readme and metadata + +## v2.0.0 (2018-05-01) + +### Breaking Change + +The package LWRP has been removed from this cookbook. chocolatey_package was integrated into Chef 12.7, which was released in Feb 2016\. This cookbook now requires Chef 12.7 or later. + +### Other Changes + +- This cookbook no longer requires the Windows cookbook +- The install script has been updated to the latest Chocolatey install script +- Converted testing to use Delivery Local Mode from within ChefDK + +## v1.2.1 (2017-08-20) + +- Explicitly use the double-dash long option names for `--source` and `--installargs` + +## v1.2.0 (2017-05-04) + +- Change the default `['chocolatey']['upgrade']` attribute value to `false`. Preventing chocolatey from reinstalling every chef run + +## v1.1.1 (2017-04-22) + +- Fix chef 13 converges renaming conflicting `env_path` method + +## v1.1.0 (2017-01-09) + +- Update the chocolatey install script to match chocolatey.org. + +## v1.0.3 (2016-09-12) + +- Loosen windows-cookbook constraint + +## v1.0.2 (2016-08-29) + +- Ensure `chocolateyVersion` attribute is used and the correct version of chocolatey is installed. + +## v1.0.1 (2016-07-15) + +- Always execute chocolatey installer unless guard is satisfied to allow the install to retry on subsequent attempts if it fails. + +## v1.0.0 (2016-03-07) + +- No longer dependent on chocolatey.org for install script +- Removed deprecated overwriting of the current_resource and fixed visibility problem with `env_path` + +## v0.6.2 (2016-01-07) + +- Fix Chocolatey detection on chef clients older than 12.4.0 + +## v0.6.1 (2015-11-24) + +- Fix LocalJumpError on existing chocolatey package + +## v0.6.0 (2015-11-17) + +- Path Tracking. Tracking additions to the user and machine %PATH% environment and merging them into the current process. +- Downcase package name results from choco upgrade. + +## v0.5.1 (2015-11-10) + +- Prepend library include with :: in provder to fix 12.3.0 and likely other versions older than 12.5.1. +- Add backward compatibiliy to new metadata.rb attributes `source_url` and `issues_url`. + +## v0.5.0 (2015-11-09) + +- Refactored install script (and .kitchen.yml) to support installing Chocolatey in test-kitchen behind a proxy. +- Download `node['chocolatey']['Uri']` via `remote_file` resource instead of .net web client +- Set `chocolateyProxyLocation` environment variable to `Chef::Config['https_proxy']` if one is set before chocolatey install +- Changed helpers module namespacing from: `ChocolateyHelpers` to `Chocolatey::Helpers` +- Add ChefSpec unit tests +- Add ServerSpec integration tests +- Gemfile: bump foodcritic to 5.0 and Berkshelf to 4.0 +- Add ChefSpec matchers + +## v0.4.1 (2015-10-15) + +- Adds example how to install package with version +- use the vanilla script resource to bypass 64bit interpreter builder introduced in Chef 12.5 + +## v0.4.0 (2015-06-30) + +- Refactor script to download Chocolatey install script +- Chocolatey install: add proxy support +- fix for 64-bit chocolatey installs + +## v0.3.0 (2015-04-20) + +- Support for chocolatey >= 0.9.9 +- Make package name case insensitive + +## v0.2.0 (2014-09-24) + +- Allow spaces in the path to the "choco" command. +- Update tests to use Rakefile +- Support Chocolatey version 0.9.8.24+ +- Support custom command line options when installing packages + +## v0.1.0 (2014-02-20) + +- Fix and tests + +## v0.0.5 (2013-04-30) + +- Initial release diff --git a/cookbooks/chocolatey/README.md b/cookbooks/chocolatey/README.md new file mode 100644 index 00000000..12cb8d3e --- /dev/null +++ b/cookbooks/chocolatey/README.md @@ -0,0 +1,45 @@ +# chocolatey Cookbook + +[![Cookbook Version](https://img.shields.io/cookbook/v/chocolatey.svg)](https://supermarket.getchef.com/cookbooks/chocolatey) [![Build Status](http://img.shields.io/travis/chocolatey/chocolatey-cookbook/master.svg)](https://travis-ci.org/chocolatey/chocolatey-cookbook) + +Install Chocolatey with the default recipe. + +## Requirements + +### Platform + +- Windows + +### Chef + +- 12.7 or greater + +## Notes + +As of Chocolatey version [0.9.8.24](https://github.com/chocolatey/chocolatey/blob/master/CHANGELOG.md#09824-july-3-2014) the install directory for Chocolatey has changed from `C:\Chocolatey` to `C:\ProgramData\Chocolatey`. + +More information can be gotten from the [Chocolateywiki](https://github.com/chocolatey/chocolatey/wiki/DefaultChocolateyInstallReasoning). + +## Attributes + +All attributes below are pre-pended with `node['chocolatey']` + +Attribute | Description | Type | Default +---------------------------------------------------- | ----------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------- +`['upgrade']` | Whether to upgrade Chocolatey if it's already installed | Boolean | false +`['install_vars']['chocolateyProxyLocation']` | HTTPS proxy for Chocolatey install script | String | Chef::Config['https_proxy'] or ENV['https_proxy'] +`['install_vars']['chocolateyProxyUser']` | Proxy user for authenticating proxies | String | nil +`['install_vars']['chocolateyProxyPassword']` | Proxy user password | String | nil +`['install_vars']['chocolateyVersion']` | Version of Chocolatey to install, e.g. '0.9.9.11' | String | nil (download latest version) +`['install_vars']['chocolateyDownloadUrl']` | Chocolatey .nupkg file URL. Use this if you host an internal copy of the chocolatey.nupkg | String | (download from chocolatey.org) +`['install_vars']['chocolateyUseWindowsCompression']`| To use built-in compression instead of 7zip (requires additional download) set to `true` | String | nil (use 7zip) + +## Recipes + +- `chocolatey::default` - installs Chocolatey + +## License and Maintainer + +Maintainer:: Guilhem Lettron ([guilhem@lettron.fr](mailto:guilhem@lettron.fr)) + +License:: Apache 2.0 diff --git a/cookbooks/chocolatey/attributes/default.rb b/cookbooks/chocolatey/attributes/default.rb new file mode 100644 index 00000000..9ff80050 --- /dev/null +++ b/cookbooks/chocolatey/attributes/default.rb @@ -0,0 +1,11 @@ +default['chocolatey']['upgrade'] = false + +# Chocolatey install.ps1 env vars. See https://chocolatey.org/install.ps1 +default['chocolatey']['install_vars'].tap do |env| + env['chocolateyProxyLocation'] = Chef::Config['https_proxy'] || ENV['https_proxy'] + env['chocolateyProxyUser'] = nil + env['chocolateyProxyPassword'] = nil + env['chocolateyVersion'] = nil + env['chocolateyDownloadUrl'] = 'https://chocolatey.org/api/v2/package/chocolatey' + env['chocolateyUseWindowsCompression'] = nil +end diff --git a/cookbooks/chocolatey/files/install.ps1 b/cookbooks/chocolatey/files/install.ps1 new file mode 100644 index 00000000..8811ca09 --- /dev/null +++ b/cookbooks/chocolatey/files/install.ps1 @@ -0,0 +1,345 @@ +# ===================================================================== +# Copyright 2017 Chocolatey Software, Inc, and the +# original authors/contributors from ChocolateyGallery +# Copyright 2011 - 2017 RealDimensions Software, LLC, and the +# original authors/contributors from ChocolateyGallery +# at https://github.com/chocolatey/chocolatey.org +# +# 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. +# ===================================================================== + +# Environment Variables, specified as $env:NAME in PowerShell.exe and %NAME% in cmd.exe. +# For explicit proxy, please set $env:chocolateyProxyLocation and optionally $env:chocolateyProxyUser and $env:chocolateyProxyPassword +# For an explicit version of Chocolatey, please set $env:chocolateyVersion = 'versionnumber' +# To target a different url for chocolatey.nupkg, please set $env:chocolateyDownloadUrl = 'full url to nupkg file' +# NOTE: $env:chocolateyDownloadUrl does not work with $env:chocolateyVersion. +# To use built-in compression instead of 7zip (requires additional download), please set $env:chocolateyUseWindowsCompression = 'true' +# To bypass the use of any proxy, please set $env:chocolateyIgnoreProxy = 'true' + +#specifically use the API to get the latest version (below) +$url = '' + +$chocolateyVersion = $env:chocolateyVersion +if (![string]::IsNullOrEmpty($chocolateyVersion)){ + Write-Output "Downloading specific version of Chocolatey: $chocolateyVersion" + $url = "https://chocolatey.org/api/v2/package/chocolatey/$chocolateyVersion" +} + +$chocolateyDownloadUrl = $env:chocolateyDownloadUrl +if (![string]::IsNullOrEmpty($chocolateyDownloadUrl)){ + Write-Output "Downloading Chocolatey from : $chocolateyDownloadUrl" + $url = "$chocolateyDownloadUrl" +} + +if ($env:TEMP -eq $null) { + $env:TEMP = Join-Path $env:SystemDrive 'temp' +} +$chocTempDir = Join-Path $env:TEMP "chocolatey" +$tempDir = Join-Path $chocTempDir "chocInstall" +if (![System.IO.Directory]::Exists($tempDir)) {[void][System.IO.Directory]::CreateDirectory($tempDir)} +$file = Join-Path $tempDir "chocolatey.zip" + +# PowerShell v2/3 caches the output stream. Then it throws errors due +# to the FileStream not being what is expected. Fixes "The OS handle's +# position is not what FileStream expected. Do not use a handle +# simultaneously in one FileStream and in Win32 code or another +# FileStream." +function Fix-PowerShellOutputRedirectionBug { + $poshMajorVerion = $PSVersionTable.PSVersion.Major + + if ($poshMajorVerion -lt 4) { + try{ + # http://www.leeholmes.com/blog/2008/07/30/workaround-the-os-handles-position-is-not-what-filestream-expected/ plus comments + $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField" + $objectRef = $host.GetType().GetField("externalHostRef", $bindingFlags).GetValue($host) + $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetProperty" + $consoleHost = $objectRef.GetType().GetProperty("Value", $bindingFlags).GetValue($objectRef, @()) + [void] $consoleHost.GetType().GetProperty("IsStandardOutputRedirected", $bindingFlags).GetValue($consoleHost, @()) + $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField" + $field = $consoleHost.GetType().GetField("standardOutputWriter", $bindingFlags) + $field.SetValue($consoleHost, [Console]::Out) + [void] $consoleHost.GetType().GetProperty("IsStandardErrorRedirected", $bindingFlags).GetValue($consoleHost, @()) + $field2 = $consoleHost.GetType().GetField("standardErrorWriter", $bindingFlags) + $field2.SetValue($consoleHost, [Console]::Error) + } catch { + Write-Output "Unable to apply redirection fix." + } + } +} + +Fix-PowerShellOutputRedirectionBug + +# Attempt to set highest encryption available for SecurityProtocol. +# PowerShell will not set this by default (until maybe .NET 4.6.x). This +# will typically produce a message for PowerShell v2 (just an info +# message though) +try { + # Set TLS 1.2 (3072), then TLS 1.1 (768), then TLS 1.0 (192), finally SSL 3.0 (48) + # Use integers because the enumeration values for TLS 1.2 and TLS 1.1 won't + # exist in .NET 4.0, even though they are addressable if .NET 4.5+ is + # installed (.NET 4.5 is an in-place upgrade). + [System.Net.ServicePointManager]::SecurityProtocol = 3072 -bor 768 -bor 192 -bor 48 +} catch { + Write-Output 'Unable to set PowerShell to use TLS 1.2 and TLS 1.1 due to old .NET Framework installed. If you see underlying connection closed or trust errors, you may need to do one or more of the following: (1) upgrade to .NET Framework 4.5+ and PowerShell v3, (2) specify internal Chocolatey package location (set $env:chocolateyDownloadUrl prior to install or host the package internally), (3) use the Download + PowerShell method of install. See https://chocolatey.org/install for all install options.' +} + +function Get-Downloader { +param ( + [string]$url + ) + + $downloader = new-object System.Net.WebClient + + $defaultCreds = [System.Net.CredentialCache]::DefaultCredentials + if ($defaultCreds -ne $null) { + $downloader.Credentials = $defaultCreds + } + + $ignoreProxy = $env:chocolateyIgnoreProxy + if ($ignoreProxy -ne $null -and $ignoreProxy -eq 'true') { + Write-Debug "Explicitly bypassing proxy due to user environment variable" + $downloader.Proxy = [System.Net.GlobalProxySelection]::GetEmptyWebProxy() + } else { + # check if a proxy is required + $explicitProxy = $env:chocolateyProxyLocation + $explicitProxyUser = $env:chocolateyProxyUser + $explicitProxyPassword = $env:chocolateyProxyPassword + if ($explicitProxy -ne $null -and $explicitProxy -ne '') { + # explicit proxy + $proxy = New-Object System.Net.WebProxy($explicitProxy, $true) + if ($explicitProxyPassword -ne $null -and $explicitProxyPassword -ne '') { + $passwd = ConvertTo-SecureString $explicitProxyPassword -AsPlainText -Force + $proxy.Credentials = New-Object System.Management.Automation.PSCredential ($explicitProxyUser, $passwd) + } + + Write-Debug "Using explicit proxy server '$explicitProxy'." + $downloader.Proxy = $proxy + + } elseif (!$downloader.Proxy.IsBypassed($url)) { + # system proxy (pass through) + $creds = $defaultCreds + if ($creds -eq $null) { + Write-Debug "Default credentials were null. Attempting backup method" + $cred = get-credential + $creds = $cred.GetNetworkCredential(); + } + + $proxyaddress = $downloader.Proxy.GetProxy($url).Authority + Write-Debug "Using system proxy server '$proxyaddress'." + $proxy = New-Object System.Net.WebProxy($proxyaddress) + $proxy.Credentials = $creds + $downloader.Proxy = $proxy + } + } + + return $downloader +} + +function Download-String { +param ( + [string]$url + ) + $downloader = Get-Downloader $url + + return $downloader.DownloadString($url) +} + +function Download-File { +param ( + [string]$url, + [string]$file + ) + #Write-Output "Downloading $url to $file" + $downloader = Get-Downloader $url + + $downloader.DownloadFile($url, $file) +} + +if ($url -eq $null -or $url -eq '') { + Write-Output "Getting latest version of the Chocolatey package for download." + $url = 'https://chocolatey.org/api/v2/Packages()?$filter=((Id%20eq%20%27chocolatey%27)%20and%20(not%20IsPrerelease))%20and%20IsLatestVersion' + [xml]$result = Download-String $url + $url = $result.feed.entry.content.src +} + +# Download the Chocolatey package + +Write-Output "Getting Chocolatey from $url." +Download-File $url $file + +# Determine unzipping method +# 7zip is the most compatible so use it by default +$7zaExe = Join-Path $tempDir '7za.exe' +$unzipMethod = '7zip' +$useWindowsCompression = $env:chocolateyUseWindowsCompression +if ($useWindowsCompression -ne $null -and $useWindowsCompression -eq 'true') { + Write-Output 'Using built-in compression to unzip' + $unzipMethod = 'builtin' +} elseif (-Not (Test-Path ($7zaExe))) { + Write-Output "Downloading 7-Zip commandline tool prior to extraction." + # download 7zip + Download-File 'https://chocolatey.org/7za.exe' "$7zaExe" +} + +#if ($useWindowsCompression -eq $null -or $windowsCompression -eq '') { +# Write-Output 'Using 7zip to unzip.' +# Write-Warning "The default is currently 7zip to better handle things like Server Core. This default will be changed to use built-in compression in December 2016. Please make sure if you need to use 7zip that you have adjusted your scripts to set `$env:chocolateyUseWindowsCompression = 'false' prior to calling the install." +# $unzipMethod = '7zip' +#} + +# unzip the package +Write-Output "Extracting $file to $tempDir..." +if ($unzipMethod -eq '7zip') { + $params = "x -o`"$tempDir`" -bd -y `"$file`"" + # use more robust Process as compared to Start-Process -Wait (which doesn't + # wait for the process to finish in PowerShell v3) + $process = New-Object System.Diagnostics.Process + $process.StartInfo = New-Object System.Diagnostics.ProcessStartInfo($7zaExe, $params) + $process.StartInfo.RedirectStandardOutput = $true + $process.StartInfo.UseShellExecute = $false + $process.StartInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden + $process.Start() | Out-Null + $process.BeginOutputReadLine() + $process.WaitForExit() + $exitCode = $process.ExitCode + $process.Dispose() + + $errorMessage = "Unable to unzip package using 7zip. Perhaps try setting `$env:chocolateyUseWindowsCompression = 'true' and call install again. Error:" + switch ($exitCode) { + 0 { break } + 1 { throw "$errorMessage Some files could not be extracted" } + 2 { throw "$errorMessage 7-Zip encountered a fatal error while extracting the files" } + 7 { throw "$errorMessage 7-Zip command line error" } + 8 { throw "$errorMessage 7-Zip out of memory" } + 255 { throw "$errorMessage Extraction cancelled by the user" } + default { throw "$errorMessage 7-Zip signalled an unknown error (code $exitCode)" } + } +} else { + if ($PSVersionTable.PSVersion.Major -lt 5) { + try { + $shellApplication = new-object -com shell.application + $zipPackage = $shellApplication.NameSpace($file) + $destinationFolder = $shellApplication.NameSpace($tempDir) + $destinationFolder.CopyHere($zipPackage.Items(),0x10) + } catch { + throw "Unable to unzip package using built-in compression. Set `$env:chocolateyUseWindowsCompression = 'false' and call install again to use 7zip to unzip. Error: `n $_" + } + } else { + Expand-Archive -Path "$file" -DestinationPath "$tempDir" -Force + } +} + +# Call chocolatey install +Write-Output "Installing chocolatey on this machine" +$toolsFolder = Join-Path $tempDir "tools" +$chocInstallPS1 = Join-Path $toolsFolder "chocolateyInstall.ps1" + +& $chocInstallPS1 + +Write-Output 'Ensuring chocolatey commands are on the path' +$chocInstallVariableName = "ChocolateyInstall" +$chocoPath = [Environment]::GetEnvironmentVariable($chocInstallVariableName) +if ($chocoPath -eq $null -or $chocoPath -eq '') { + $chocoPath = "$env:ALLUSERSPROFILE\Chocolatey" +} + +if (!(Test-Path ($chocoPath))) { + $chocoPath = "$env:SYSTEMDRIVE\ProgramData\Chocolatey" +} + +$chocoExePath = Join-Path $chocoPath 'bin' + +if ($($env:Path).ToLower().Contains($($chocoExePath).ToLower()) -eq $false) { + $env:Path = [Environment]::GetEnvironmentVariable('Path',[System.EnvironmentVariableTarget]::Machine); +} + +Write-Output 'Ensuring chocolatey.nupkg is in the lib folder' +$chocoPkgDir = Join-Path $chocoPath 'lib\chocolatey' +$nupkg = Join-Path $chocoPkgDir 'chocolatey.nupkg' +if (![System.IO.Directory]::Exists($chocoPkgDir)) { [System.IO.Directory]::CreateDirectory($chocoPkgDir); } +Copy-Item "$file" "$nupkg" -Force -ErrorAction SilentlyContinue + +# SIG # Begin signature block +# MIINVQYJKoZIhvcNAQcCoIINRjCCDUICAQExDzANBglghkgBZQMEAgEFADB5Bgor +# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG +# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBtI1XhNa+BTJDA +# Udd7cvDCY121zDB7LmEXLgQMpQmPnqCCCnIwggUwMIIEGKADAgECAhAECRgbX9W7 +# ZnVTQ7VvlVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK +# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV +# BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBa +# Fw0yODEwMjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy +# dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lD +# ZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3 +# DQEBAQUAA4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/l +# qJ3bMtdx6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fT +# eyOU5JEjlpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqH +# CN8M9eJNYBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+ +# bMt+dDk2DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLo +# LFH3c7y9hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIB +# yTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAK +# BggrBgEFBQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9v +# Y3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGln +# aWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHow +# eDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJl +# ZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp +# Z2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwA +# AgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAK +# BghghkgBhv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0j +# BBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7s +# DVoks/Mi0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGS +# dQ9RtG6ljlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6 +# r7VRwo0kriTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo +# +MUSaJ/PQMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qz +# sIzV6Q3d9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHq +# aGxEMrJmoecYpJpkUe8wggU6MIIEIqADAgECAhAGsBFbtfCQ0/DaDmIsYn1YMA0G +# CSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ +# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0 +# IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwHhcNMTcwMzI4MDAwMDAw +# WhcNMTgwNDAzMTIwMDAwWjB3MQswCQYDVQQGEwJVUzEPMA0GA1UECBMGS2Fuc2Fz +# MQ8wDQYDVQQHEwZUb3Bla2ExIjAgBgNVBAoTGUNob2NvbGF0ZXkgU29mdHdhcmUs +# IEluYy4xIjAgBgNVBAMTGUNob2NvbGF0ZXkgU29mdHdhcmUsIEluYy4wggEiMA0G +# CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLIWIaEiqkPbIMZi6jD6J8F3YIYPxG +# 3Vw2I8AsM5c63WUmV+bYZQGxY5AHHVFphy9mU6spXgAqVpzkcALjo1oArVscUU34 +# 8S4mokGbZVvHlO8ny1b1HzfR4ZPHpUL71btSqpcOElYOOL0wUnf5As/39VN+Wxef +# //D5KTDD17AA2DVvIaXMT+utERbo+c+leaPS4fKo/Q0KvpCt0sKr6LItAMNgaqL4 +# 9Z+Dg5n1oHjxAz4ZYhJYdHIPZPoqyeLQ8IuYiqCxKS07tkfvkwlgWxksHpliIKqf +# Jpv0YE2vqlZrcx0WYHNhgX3BIhQa21wxn/XAFNCpgrDgI0u0UupZfxAdAgMBAAGj +# ggHFMIIBwTAfBgNVHSMEGDAWgBRaxLl7KgqjpepxA8Bg+S32ZXUOWDAdBgNVHQ4E +# FgQUJqUaP1/S0OF1EG1dxC6UzM6w6T8wDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQM +# MAoGCCsGAQUFBwMDMHcGA1UdHwRwMG4wNaAzoDGGL2h0dHA6Ly9jcmwzLmRpZ2lj +# ZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMDWgM6Axhi9odHRwOi8vY3Js +# NC5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLWNzLWcxLmNybDBMBgNVHSAERTBD +# MDcGCWCGSAGG/WwDATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2Vy +# dC5jb20vQ1BTMAgGBmeBDAEEATCBhAYIKwYBBQUHAQEEeDB2MCQGCCsGAQUFBzAB +# hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTgYIKwYBBQUHMAKGQmh0dHA6Ly9j +# YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJBc3N1cmVkSURDb2RlU2ln +# bmluZ0NBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQCLBAE/ +# 2x4amEecDEoy9g+WmWMROiB4GnkPqj+IbiwftmwC5/7yL3/592HOFMJr0qOgUt51 +# moE8SuuLuOGw63c5+/48LJS4jP2XzbVNByRPIxPWorm4t/OzTJNziTowHQ+wLwwI +# 8U97+8DaHCNL7iLZNEiqbVlpF3j7SMWGgf2BVYADJyxluNzf0ZUO+lXN4gOkM8tl +# VDc7SjZEKvu6ckAaxXf7NPbCXVL/3+LvdmoLbT3vJlfzeXqduO3oieB10ic3ug5T +# XtoYmyEk/P3yR3x/TqUlg1x/xaolBxy5TyMeSLcBlYn42fnQL154bvMGwFiCsHWQ +# wY09I0xpEysOMiy8MYICOTCCAjUCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNV +# BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8G +# A1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2lnbmluZyBDQQIQ +# BrARW7XwkNPw2g5iLGJ9WDANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEM +# MQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQB +# gjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCA30tiIkQr58z/E +# B7+e4qnBMyyqgtyBNCzS+4Lf0KDlwTANBgkqhkiG9w0BAQEFAASCAQB0y8X6HZlj +# VVxJY4s+6XYx/QM6a8KCe1oTwPt++jafTuOCZkv4LaFONT8jQO+ddPYhkeNv2D1v +# xjJu7oU2vsbwdHGdgOFdaCvjce+6j4FqJ6QvFT4CbIYgq5F+dJ6idy9i0f2Wa4N9 +# Ei8bJ2C5ruOwDbDtPeoGP5+H4ehHqHKY1ubVXdm5nOKrB0XRxroUykAZbzho7OHv +# UZ3uA7RX0CvDJ78hEAn5Zg3MsMB1e7B3B5m9DKbPTa/k6q65uVDDNZE66GEyzQ04 +# lqUJK2K9SNM7MmSJkCga40y02t0OTR8w+V8Ev4GPL47Ubu3fLetknY2Z5r+b1+eu +# camDGbsbstoG +# SIG # End signature block diff --git a/cookbooks/chocolatey/libraries/helpers.rb b/cookbooks/chocolatey/libraries/helpers.rb new file mode 100644 index 00000000..1d4b36c4 --- /dev/null +++ b/cookbooks/chocolatey/libraries/helpers.rb @@ -0,0 +1,55 @@ +module Chocolatey + module Helpers + # include the PowershellOut module from the windows cookbook + # in case we are running an older chef client + include Chef::Mixin::PowershellOut + + # Get the ChocolateyInstall directory from the environment. + def chocolatey_install + ENV.fetch('ChocolateyInstall') { |env_var| machine_env_var(env_var) } + end + + # The Chocolatey command. + # + # Reference: https://github.com/chocolatey/chocolatey-cookbook/pull/16#issuecomment-47975896 + def chocolatey_executable + "\"#{::File.join(chocolatey_install, 'bin', 'choco')}\"" + end + + def chocolatey_lib_dir + File.join(chocolatey_install, 'lib', 'chocolatey') + end + + # Check if Chocolatey is installed + def chocolatey_installed? + return @is_chocolatey_installed if @is_chocolatey_installed + return false if chocolatey_install.nil? + # choco /? returns an exit status of -1 with chocolatey 0.9.9 => use list + cmd = Mixlib::ShellOut.new("#{chocolatey_executable} list -l chocolatey") + cmd.run_command + @is_chocolatey_installed = cmd.exitstatus == 0 + end + + # combine the local path with the user and machine paths + def environment_path(local_path) + machine = env_var('PATH', 'MACHINE').split(';') + user = env_var('PATH', 'USER').split(';') + local = local_path.split(';') + combined = local.concat(machine).concat(user).uniq.compact + combined.join(';') + end + + private + + def machine_env_var(env_var) + env_var(env_var, 'MACHINE') + end + + def env_var(env_var, scope) + env_var = powershell_out!( + "[System.Environment]::GetEnvironmentVariable('#{env_var}', '#{scope}')" + ) + env_var.stdout.chomp + end + end +end diff --git a/cookbooks/chocolatey/metadata.json b/cookbooks/chocolatey/metadata.json new file mode 100644 index 00000000..fec3ac0f --- /dev/null +++ b/cookbooks/chocolatey/metadata.json @@ -0,0 +1 @@ +{"name":"chocolatey","version":"2.0.1","description":"Install Chocolatey on Windows","long_description":"Installs the Chocolatey package manager for Windows.","maintainer":"Guilhem Lettron","maintainer_email":"guilhem.lettron@youscribe.com","license":"Apache-2.0","platforms":{"windows":">= 0.0.0"},"dependencies":{},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{},"source_url":"https://github.com/chocolatey/chocolatey-cookbook","issues_url":"https://github.com/chocolatey/chocolatey-cookbook/issues","chef_version":[[">= 12.7"]],"ohai_version":[]} \ No newline at end of file diff --git a/cookbooks/chocolatey/recipes/default.rb b/cookbooks/chocolatey/recipes/default.rb new file mode 100644 index 00000000..45933608 --- /dev/null +++ b/cookbooks/chocolatey/recipes/default.rb @@ -0,0 +1,40 @@ +# +# Cookbook Name:: chocolatey +# recipe:: default +# Author:: Guilhem Lettron +# +# Copyright 2012, Societe Publica. +# Copyright 2015, Doug Ireton +# +# 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. +# +unless platform_family?('windows') + return "Chocolatey install not supported on #{node['platform_family']}" +end + +Chef::Resource.send(:include, Chocolatey::Helpers) + +install_ps1 = File.join(Chef::Config['file_cache_path'], 'chocolatey-install.ps1') + +cookbook_file install_ps1 do + action :create + backup false + source 'install.ps1' +end + +powershell_script 'Install Chocolatey' do + environment node['chocolatey']['install_vars'] + cwd Chef::Config['file_cache_path'] + code install_ps1 + not_if { chocolatey_installed? && (node['chocolatey']['upgrade'] == false) } +end