From b7293f32d02c0781d5a939fa0b5e0b5e5699eedb Mon Sep 17 00:00:00 2001 From: Jjk422 Date: Mon, 20 Mar 2017 23:00:01 +0000 Subject: [PATCH 1/4] Windows modules (web browsers, languages and text editor) and chocolatey repository manager. --- .../languages/python/manifests/install.pp | 10 + .../windows/languages/python/python.pp | 1 + .../languages/python/secgen_metadata.xml | 20 + .../languages/ruby/manifests/install.pp | 10 + .../utilities/windows/languages/ruby/ruby.pp | 1 + .../languages/ruby/secgen_metadata.xml | 20 + .../chocolatey/CHANGELOG.md | 172 ++++ .../chocolatey/CONTRIBUTING.md | 219 +++++ .../repository_managers/chocolatey/Gemfile | 152 ++++ .../repository_managers/chocolatey/LICENSE | 202 +++++ .../chocolatey/MAINTAINERS.md | 6 + .../repository_managers/chocolatey/NOTICE | 0 .../repository_managers/chocolatey/README.md | 783 ++++++++++++++++++ .../repository_managers/chocolatey/Rakefile | 104 +++ .../chocolatey/appveyor.yml | 44 + .../chocolatey/checksums.json | 91 ++ .../chocolatey/chocolatey.pp | 1 + .../chocolatey/examples/init.pp | 23 + .../lib/facter/choco_install_path.rb | 9 + .../lib/facter/chocolateyversion.rb | 9 + .../provider/chocolateyconfig/windows.rb | 144 ++++ .../provider/chocolateyfeature/windows.rb | 126 +++ .../provider/chocolateysource/windows.rb | 197 +++++ .../lib/puppet/provider/package/chocolatey.rb | 280 +++++++ .../lib/puppet/type/chocolateyconfig.rb | 85 ++ .../lib/puppet/type/chocolateyfeature.rb | 57 ++ .../lib/puppet/type/chocolateysource.rb | 141 ++++ .../puppet_x/chocolatey/chocolatey_common.rb | 90 ++ .../puppet_x/chocolatey/chocolatey_install.rb | 34 + .../puppet_x/chocolatey/chocolatey_version.rb | 32 + .../chocolatey/manifests/config.pp | 34 + .../chocolatey/manifests/init.pp | 104 +++ .../chocolatey/manifests/install.pp | 27 + .../chocolatey/manifests/params.pp | 9 + .../chocolatey/metadata.json | 53 ++ .../chocolatey/secgen_metadata.xml | 17 + .../chocolatey/spec/classes/config_spec.rb | 77 ++ .../chocolatey/spec/classes/coverage_spec.rb | 1 + .../chocolatey/spec/classes/init_spec.rb | 200 +++++ .../chocolatey/spec/classes/install_spec.rb | 30 + .../chocolatey/spec/spec_helper.rb | 64 ++ .../unit/facter/choco_install_path_spec.rb | 32 + .../unit/facter/chocolateyversion_spec.rb | 32 + .../provider/chocolateyconfig/windows_spec.rb | 268 ++++++ .../chocolateyfeature/windows_spec.rb | 170 ++++ .../provider/chocolateysource/windows_spec.rb | 607 ++++++++++++++ .../provider/package/chocolatey_spec.rb | 514 ++++++++++++ .../unit/puppet/type/chocolateyconfig_spec.rb | 103 +++ .../puppet/type/chocolateyfeature_spec.rb | 58 ++ .../unit/puppet/type/chocolateysource_spec.rb | 129 +++ .../chocolatey/chocolatey_common_spec.rb | 71 ++ .../chocolatey/chocolatey_install_spec.rb | 52 ++ .../chocolatey/chocolatey_version_spec.rb | 81 ++ .../templates/InstallChocolatey.ps1.erb | 151 ++++ .../acceptance/pre-suite/00_pe_install.rb | 20 + .../pre-suite/01_chocolatey_module.install.rb | 25 + .../02_chocolatey_application_install.rb | 47 ++ .../tests/acceptance/tests/hello.rb | 7 + .../chocolatey/tests/configs/.gitignore | 3 + .../chocolatey/tests/lib/chocolatey_helper.rb | 50 ++ .../reference/pre-suite/00_install_certs.rb | 93 +++ .../pre-suite/01_puppet_agent_install.rb | 13 + .../pre-suite/02_chocolatey_module_install.rb | 27 + .../03_chocolatey_application_install.rb | 39 + .../chocolateyconfig/add_new_config_item.rb | 29 + .../add_value_to_existing_config.rb | 29 + .../chocolateyconfig/change_config_value.rb | 46 + ...sure_config_value_with_password_in_name.rb | 50 ++ .../fail_to_appy_bad_manifest.rb | 25 + .../fail_to_set_present_without_value.rb | 24 + ...move_config_value_with_password_in_name.rb | 50 ++ .../remove_value_from_config.rb | 28 + .../disable_disabled_feature.rb | 35 + .../disable_enabled_feature.rb | 35 + .../enable_disabled_feature.rb | 35 + .../enable_enabled_feature.rb | 35 + .../fail_to_enable_nonexistent_feature.rb | 24 + .../fail_to_remove_feature.rb | 25 + .../install_and_remove_good_package.rb | 62 ++ .../install_and_remove_good_package_utf-8.rb | 65 ++ .../add_priority_to_existing_source.rb | 30 + .../add_source_all_options.rb | 36 + .../chocolateysource/add_source_minimal.rb | 29 + .../chocolateysource/add_source_normal.rb | 30 + .../add_user_pass_to_existing_source.rb | 33 + .../change_existing_priority.rb | 51 ++ .../change_existing_source_location.rb | 30 + .../chocolateysource/change_user_pass.rb | 54 ++ .../disable_existing_source.rb | 28 + .../disable_existing_source_two_runs.rb | 43 + .../fail_to_apply_source_without_location.rb | 24 + .../fail_to_appy_bad_manifest.rb | 25 + .../fail_to_set_password_without_user.rb | 26 + .../fail_to_set_user_without_password.rb | 26 + .../remove_existing_source.rb | 28 + .../remove_priority_from_existing_source.rb | 50 ++ .../remove_user_pass_from_existing_source.rb | 53 ++ .../test_run_scripts/acceptance_tests.sh | 68 ++ .../tests/test_run_scripts/reference_tests.sh | 65 ++ .../notepadplusplus/manifests/install.pp | 12 + .../notepadplusplus/notepadplusplus.pp | 1 + .../notepadplusplus/secgen_metadata.xml | 20 + .../windows/web_browsers/firefox/firefox.pp | 1 + .../web_browsers/firefox/manifests/install.pp | 10 + .../web_browsers/firefox/secgen_metadata.xml | 20 + .../google_chrome/google_chrome.pp | 1 + .../google_chrome/manifests/configure.pp | 13 + .../google_chrome/manifests/install.pp | 10 + .../google_chrome/secgen_metadata.xml | 20 + .../internet_explorer_11.pp | 1 + .../internet_explorer_11/manifests/install.pp | 10 + .../internet_explorer_11/secgen_metadata.xml | 20 + 112 files changed, 7736 insertions(+) create mode 100644 modules/utilities/windows/languages/python/manifests/install.pp create mode 100644 modules/utilities/windows/languages/python/python.pp create mode 100644 modules/utilities/windows/languages/python/secgen_metadata.xml create mode 100644 modules/utilities/windows/languages/ruby/manifests/install.pp create mode 100644 modules/utilities/windows/languages/ruby/ruby.pp create mode 100644 modules/utilities/windows/languages/ruby/secgen_metadata.xml create mode 100644 modules/utilities/windows/repository_managers/chocolatey/CHANGELOG.md create mode 100644 modules/utilities/windows/repository_managers/chocolatey/CONTRIBUTING.md create mode 100644 modules/utilities/windows/repository_managers/chocolatey/Gemfile create mode 100644 modules/utilities/windows/repository_managers/chocolatey/LICENSE create mode 100644 modules/utilities/windows/repository_managers/chocolatey/MAINTAINERS.md create mode 100644 modules/utilities/windows/repository_managers/chocolatey/NOTICE create mode 100644 modules/utilities/windows/repository_managers/chocolatey/README.md create mode 100644 modules/utilities/windows/repository_managers/chocolatey/Rakefile create mode 100644 modules/utilities/windows/repository_managers/chocolatey/appveyor.yml create mode 100644 modules/utilities/windows/repository_managers/chocolatey/checksums.json create mode 100644 modules/utilities/windows/repository_managers/chocolatey/chocolatey.pp create mode 100644 modules/utilities/windows/repository_managers/chocolatey/examples/init.pp create mode 100644 modules/utilities/windows/repository_managers/chocolatey/lib/facter/choco_install_path.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/lib/facter/chocolateyversion.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/chocolateyconfig/windows.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/chocolateyfeature/windows.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/chocolateysource/windows.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/package/chocolatey.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/lib/puppet/type/chocolateyconfig.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/lib/puppet/type/chocolateyfeature.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/lib/puppet/type/chocolateysource.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/lib/puppet_x/chocolatey/chocolatey_common.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/lib/puppet_x/chocolatey/chocolatey_install.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/lib/puppet_x/chocolatey/chocolatey_version.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/manifests/config.pp create mode 100644 modules/utilities/windows/repository_managers/chocolatey/manifests/init.pp create mode 100644 modules/utilities/windows/repository_managers/chocolatey/manifests/install.pp create mode 100644 modules/utilities/windows/repository_managers/chocolatey/manifests/params.pp create mode 100644 modules/utilities/windows/repository_managers/chocolatey/metadata.json create mode 100644 modules/utilities/windows/repository_managers/chocolatey/secgen_metadata.xml create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/classes/config_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/classes/coverage_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/classes/init_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/classes/install_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/spec_helper.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/unit/facter/choco_install_path_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/unit/facter/chocolateyversion_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/chocolateyconfig/windows_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/chocolateyfeature/windows_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/chocolateysource/windows_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/package/chocolatey_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/type/chocolateyconfig_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/type/chocolateyfeature_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/type/chocolateysource_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet_x/chocolatey/chocolatey_common_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet_x/chocolatey/chocolatey_install_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet_x/chocolatey/chocolatey_version_spec.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/templates/InstallChocolatey.ps1.erb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/pre-suite/00_pe_install.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/pre-suite/01_chocolatey_module.install.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/pre-suite/02_chocolatey_application_install.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/tests/hello.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/configs/.gitignore create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/lib/chocolatey_helper.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/00_install_certs.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/01_puppet_agent_install.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/02_chocolatey_module_install.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/03_chocolatey_application_install.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/add_new_config_item.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/add_value_to_existing_config.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/change_config_value.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/ensure_config_value_with_password_in_name.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/fail_to_appy_bad_manifest.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/fail_to_set_present_without_value.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/remove_config_value_with_password_in_name.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/remove_value_from_config.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/disable_disabled_feature.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/disable_enabled_feature.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/enable_disabled_feature.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/enable_enabled_feature.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/fail_to_enable_nonexistent_feature.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/fail_to_remove_feature.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateypackage/install_and_remove_good_package.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateypackage/install_and_remove_good_package_utf-8.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_priority_to_existing_source.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_source_all_options.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_source_minimal.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_source_normal.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_user_pass_to_existing_source.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/change_existing_priority.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/change_existing_source_location.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/change_user_pass.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/disable_existing_source.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/disable_existing_source_two_runs.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_apply_source_without_location.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_appy_bad_manifest.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_set_password_without_user.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_set_user_without_password.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/remove_existing_source.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/remove_priority_from_existing_source.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/remove_user_pass_from_existing_source.rb create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/test_run_scripts/acceptance_tests.sh create mode 100644 modules/utilities/windows/repository_managers/chocolatey/tests/test_run_scripts/reference_tests.sh create mode 100644 modules/utilities/windows/text_editor/notepadplusplus/manifests/install.pp create mode 100644 modules/utilities/windows/text_editor/notepadplusplus/notepadplusplus.pp create mode 100644 modules/utilities/windows/text_editor/notepadplusplus/secgen_metadata.xml create mode 100644 modules/utilities/windows/web_browsers/firefox/firefox.pp create mode 100644 modules/utilities/windows/web_browsers/firefox/manifests/install.pp create mode 100644 modules/utilities/windows/web_browsers/firefox/secgen_metadata.xml create mode 100644 modules/utilities/windows/web_browsers/google_chrome/google_chrome.pp create mode 100644 modules/utilities/windows/web_browsers/google_chrome/manifests/configure.pp create mode 100644 modules/utilities/windows/web_browsers/google_chrome/manifests/install.pp create mode 100644 modules/utilities/windows/web_browsers/google_chrome/secgen_metadata.xml create mode 100644 modules/utilities/windows/web_browsers/internet_explorer_11/internet_explorer_11.pp create mode 100644 modules/utilities/windows/web_browsers/internet_explorer_11/manifests/install.pp create mode 100644 modules/utilities/windows/web_browsers/internet_explorer_11/secgen_metadata.xml diff --git a/modules/utilities/windows/languages/python/manifests/install.pp b/modules/utilities/windows/languages/python/manifests/install.pp new file mode 100644 index 000000000..74e75b016 --- /dev/null +++ b/modules/utilities/windows/languages/python/manifests/install.pp @@ -0,0 +1,10 @@ +class python::install { + include chocolatey + + notice('Installing python') + + package { 'python': + ensure => installed, + provider => 'chocolatey', + } +} \ No newline at end of file diff --git a/modules/utilities/windows/languages/python/python.pp b/modules/utilities/windows/languages/python/python.pp new file mode 100644 index 000000000..0a11b98f1 --- /dev/null +++ b/modules/utilities/windows/languages/python/python.pp @@ -0,0 +1 @@ +include python::install \ No newline at end of file diff --git a/modules/utilities/windows/languages/python/secgen_metadata.xml b/modules/utilities/windows/languages/python/secgen_metadata.xml new file mode 100644 index 000000000..79fb6d3c3 --- /dev/null +++ b/modules/utilities/windows/languages/python/secgen_metadata.xml @@ -0,0 +1,20 @@ + + + + Python programming language + Jason Keighley + Apache v2 + A Python installation + + languages + windows + + + + + + Chocolatey install + + \ No newline at end of file diff --git a/modules/utilities/windows/languages/ruby/manifests/install.pp b/modules/utilities/windows/languages/ruby/manifests/install.pp new file mode 100644 index 000000000..6a21fd72d --- /dev/null +++ b/modules/utilities/windows/languages/ruby/manifests/install.pp @@ -0,0 +1,10 @@ +class ruby::install { + include chocolatey + + notice('Installing ruby') + + package { 'ruby': + ensure => installed, + provider => 'chocolatey', + } +} \ No newline at end of file diff --git a/modules/utilities/windows/languages/ruby/ruby.pp b/modules/utilities/windows/languages/ruby/ruby.pp new file mode 100644 index 000000000..782d52619 --- /dev/null +++ b/modules/utilities/windows/languages/ruby/ruby.pp @@ -0,0 +1 @@ +include ruby::install \ No newline at end of file diff --git a/modules/utilities/windows/languages/ruby/secgen_metadata.xml b/modules/utilities/windows/languages/ruby/secgen_metadata.xml new file mode 100644 index 000000000..39c1d4718 --- /dev/null +++ b/modules/utilities/windows/languages/ruby/secgen_metadata.xml @@ -0,0 +1,20 @@ + + + + Ruby programming language + Jason Keighley + Apache v2 + A Ruby installation + + languages + windows + + + + + + Chocolatey install + + \ No newline at end of file diff --git a/modules/utilities/windows/repository_managers/chocolatey/CHANGELOG.md b/modules/utilities/windows/repository_managers/chocolatey/CHANGELOG.md new file mode 100644 index 000000000..ca4f59c21 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/CHANGELOG.md @@ -0,0 +1,172 @@ +## 2016-12-30 Supported Release 2.0.1 + +### Summary + +This is a bug fix release, correcting some issues in the original supported release and one that was introduced by the switchover to the puppetlabs-powershell v2 module. + +### Bug Fixes + +- Fix: ChocolateyInstall environment variable not set for alternate installation directory ([MODULES-4091](https://tickets.puppetlabs.com/browse/MODULES-4091)) +- Fix: Unsuitable providers should not cause errors ([MODULES-4149](https://tickets.puppetlabs.com/browse/MODULES-4149)) +- Fix: version is malformed with any extraneous messages ([MODULES-4135](https://tickets.puppetlabs.com/browse/MODULES-4135)) +- Fix: module does not propagate null source error correctly ([MODULES-4056](https://tickets.puppetlabs.com/browse/MODULES-4056)) +- Fix: install fails on Windows 10 when using built-in compression ([MODULES-4210](https://tickets.puppetlabs.com/browse/MODULES-4210)) + +### Improvements + +- Set TLS 1.1+ when available +- Document considerations for install to "C:\Chocolatey" ([MODULES-4090](https://tickets.puppetlabs.com/browse/MODULES-4090)) + + +## 2016-09-29 First Supported Release 2.0.0 + +### Summary + +Puppetlabs-Chocolatey is now a supported module! This includes everything from the approved chocolatey-chocolatey module, plus the improvements in the unsupported releases 0.7.0 and 0.8.0. It also adds the following additional changes and fixes. + +### Features + +- `chocolateysource` - explicitly require location in ensure ([MODULES-3430](https://tickets.puppet.com/browse/MODULES-3430)) +- set ignore package exit codes when Chocolatey is on version 0.9.10+ ([MODULES-3880](https://tickets.puppet.com/browse/MODULES-3880)) + +### Bug Fixes + +- Fix: Ensure config file exists before `chocolateyfeature`, `chocolateyconfig`, or `chocolateysource` ([MODULES-3677](https://tickets.puppet.com/browse/MODULES-3677)) +- Fix: `chocolateysource` - ensure flush when disabling source ([MODULES-3430](https://tickets.puppet.com/browse/MODULES-3430)) +- Fix: `chocolateysource` - erroneous user sync messages ([MODULES-3758](https://tickets.puppet.com/browse/MODULES-3758)) + + +## 2016-07-13 Unsupported Release 0.8.0 + +This brings the unsupported puppetlabs-chocolatey provider on par with the approved chocolatey-chocolatey at 1.2.6 and adds additional features. + + * Includes community module releases up to 1.2.6 (changelog below). + * Manage features - `chocolateyfeature` - see [MODULES-3034](https://tickets.puppet.com/browse/MODULES-3034) + * Manage config settings - `chocolateyconfig` - see [MODULES-3035](https://tickets.puppet.com/browse/MODULES-3035) + + +## 2016-06-01 Unsupported Release 0.7.0 + + * Manage sources - `chocolateysource` - see [MODULES-3037](https://tickets.puppetlabs.com/browse/MODULES-3037) + * Includes community module releases up to 1.2.1 (changelog below up to 1.2.1), plus these additional fixes: + * $::chocolateyversion fact is optional - see [#110](https://github.com/chocolatey/puppet-chocolatey/issues/110) + * Fix: puppet apply works again - see [#105](https://github.com/chocolatey/puppet-chocolatey/issues/105) + + +# Approved Community Module Changelog - Chocolatey Team + +The Chocolatey team has graciously agreed to allow Puppet to take this module +to the next level. Puppet will rerelease a supported module under the original +versioning scheme. For now we are using a number less than 1.0 to show that this +could have some technical issues and should be treated as a prerelease version. + +## 2016-07-11 Release 1.2.6 + +- Fix - AutoUninstaller runs every time in 0.9.9.x [#134](https://github.com/chocolatey/puppet-chocolatey/issues/134) + + +## 2016-06-20 Release 1.2.5 + +- Support feature list changes in v0.9.10+ [#133](https://github.com/chocolatey/puppet-chocolatey/issues/133) +- Fix - Chocolatey fails to install in PowerShell v2 with PowerShell Module 1.x [#128](https://github.com/chocolatey/puppet-chocolatey/issues/128) + + +## 2016-06-04 Release 1.2.4 + +- Compatibility with puppetlabs-powershell 2.x [#125](https://github.com/chocolatey/puppet-chocolatey/issues/125). + + +## 2016-05-06 Release 1.2.3 + +- Do not call choco with --debug --verbose by default [#100](https://github.com/chocolatey/puppet-chocolatey/issues/100). +- Announce [Chocolatey for Business](https://chocolatey.org/compare) in ReadMe. + + +## 2016-05-06 Release 1.2.3 + +- Do not call choco with --debug --verbose by default [#100](https://github.com/chocolatey/puppet-chocolatey/issues/100). +- Announce Chocolatey for Business in ReadMe. + + +## 2016-04-06 Release 1.2.2 + +- Fix: puppet apply works again [#105](https://github.com/chocolatey/puppet-chocolatey/issues/105). +- `$::chocolateyversion` fact is optional - see [#110](https://github.com/chocolatey/puppet-chocolatey/issues/110) +- Fix: Implement PowerShell Redirection Fix for Windows 2008 / PowerShell v2 - see [#119](https://github.com/chocolatey/puppet-chocolatey/issues/119) + + +## 2015-12-08 Release 1.2.1 + +- Small release for support of newer PE versions. + + +##2015-11-03 Release 1.2.0 + +- Implement holdable ([#95](https://github.com/chocolatey/puppet-chocolatey/issues/95)) +- Fix - Use install unless version specified in install ([#71](https://github.com/chocolatey/puppet-chocolatey/issues/71)) + + +## 2015-10-02 Release 1.1.2 + +- Ensure 0.9.9.9 compatibility ([#94](https://github.com/chocolatey/puppet-chocolatey/issues/94)) +- Fix - Mixed stale environment variables of existing choco install causing issues ([#86](https://github.com/chocolatey/puppet-chocolatey/issues/86)) +- Upgrade From POSH Version of Chocolatey Fails from Puppet ([#60](https://github.com/chocolatey/puppet-chocolatey/issues/60)) + + +## 2015-09-25 Release 1.1.1 + +- Add log_output for chocolatey bootstrap installer script +- Ensure bootstrap enforces chocolatey.nupkg in libs folder +- Allow file location for installing nupkg file. + + +## 2015-09-09 Release 1.1.0 + +- Install Chocolatey itself / ensure Chocolatey is installed (PUP-1691) +- Adds custom facts for chocolateyversion and choco_install_path + + +## 2015-07-23 Release 1.0.2 + +- Fixes [#71](https://github.com/chocolatey/puppet-chocolatey/issues/71) - Allow `ensure => $version` to work with already installed packages + + +## 2015-07-01 Release 1.0.1 + +- Fixes [#66](https://github.com/chocolatey/puppet-chocolatey/issues/66) - Check for choco existence more comprehensively + + +## 2015-06-08 Release 1.0.0 + +- No change, bumping to 1.0.0 + + +## 2015-05-22 Release 0.5.3 + +- Fix manifest issue +- Fix choco path issue +- Update ReadMe - fix/clarify how options with quotes need to be passed. + + +## 2015-04-23 Release 0.5.2 + +- Update ReadMe +- Add support for Windows 10. +- Fixes [#56](https://github.com/chocolatey/puppet-chocolatey/pull/56) - Avoiding puppet returning 2 instead of 0 when there are no changes to be done. + + +## 2015-03-31 Release 0.5.1 + +- Fixes [#54](https://github.com/chocolatey/puppet-chocolatey/issues/54) - Blocking: Linux masters throw error if module is present + + +## 2015-03-30 Release 0.5.0 + +- Provider enhancements +- Better docs +- Works with both compiled and powershell Chocolatey clients +- Fixes #50 - work with newer compiled Chocolatey client (0.9.9+) +- Fixes #43 - check for installed packages is case sensitive +- Fixes #18 - The OS handle's position is not what FileStream expected. +- Fixes #52 - Document best way to pass options with spaces (#15 also related) +- Fixes #26 - Document Chocolatey needs to be installed by other means diff --git a/modules/utilities/windows/repository_managers/chocolatey/CONTRIBUTING.md b/modules/utilities/windows/repository_managers/chocolatey/CONTRIBUTING.md new file mode 100644 index 000000000..dd2b5c4ff --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/CONTRIBUTING.md @@ -0,0 +1,219 @@ +Checklist (and a short version for the impatient) +================================================= + + * Commits: + + - Make commits of logical units. + + - Check for unnecessary whitespace with "git diff --check" before + committing. + + - Commit using Unix line endings (check the settings around "crlf" in + git-config(1)). + + - Do not check in commented out code or unneeded files. + + - The first line of the commit message should be a short + description (50 characters is the soft limit, excluding ticket + number(s)), and should skip the full stop. + + - Associate the issue in the message. The first line should include + the issue number in the form "(#XXXX) Rest of message". + + - The body should provide a meaningful commit message, which: + + - uses the imperative, present tense: "change", not "changed" or + "changes". + + - includes motivation for the change, and contrasts its + implementation with the previous behavior. + + - Make sure that you have tests for the bug you are fixing, or + feature you are adding. + + - Make sure the test suites passes after your commit: + `bundle exec rspec spec/acceptance` More information on [testing](#Testing) below + + - When introducing a new feature, make sure it is properly + documented in the README.md + + * Submission: + + * Pre-requisites: + + - Make sure you have a [GitHub account](https://github.com/join) + + - [Create a ticket](https://tickets.puppet.com/secure/CreateIssue!default.jspa), or [watch the ticket](https://tickets.puppet.com/browse/) you are patching for. + + * Preferred method: + + - Fork the repository on GitHub. + + - Push your changes to a topic branch in your fork of the + repository. (the format ticket/1234-short_description_of_change is + usually preferred for this project). + + - Submit a pull request to the repository in the puppetlabs + organization. + +The long version +================ + + 1. Make separate commits for logically separate changes. + + Please break your commits down into logically consistent units + which include new or changed tests relevant to the rest of the + change. The goal of doing this is to make the diff easier to + read for whoever is reviewing your code. In general, the easier + your diff is to read, the more likely someone will be happy to + review it and get it into the code base. + + If you are going to refactor a piece of code, please do so as a + separate commit from your feature or bug fix changes. + + We also really appreciate changes that include tests to make + sure the bug is not re-introduced, and that the feature is not + accidentally broken. + + Describe the technical detail of the change(s). If your + description starts to get too long, that is a good sign that you + probably need to split up your commit into more finely grained + pieces. + + Commits which plainly describe the things which help + reviewers check the patch and future developers understand the + code are much more likely to be merged in with a minimum of + bike-shedding or requested changes. Ideally, the commit message + would include information, and be in a form suitable for + inclusion in the release notes for the version of Puppet that + includes them. + + Please also check that you are not introducing any trailing + whitespace or other "whitespace errors". You can do this by + running "git diff --check" on your changes before you commit. + + 2. Sending your patches + + To submit your changes via a GitHub pull request, we _highly_ + recommend that you have them on a topic branch, instead of + directly on "master". + It makes things much easier to keep track of, especially if + you decide to work on another thing before your first change + is merged in. + + GitHub has some pretty good + [general documentation](http://help.github.com/) on using + their site. They also have documentation on + [creating pull requests](http://help.github.com/send-pull-requests/). + + In general, after pushing your topic branch up to your + repository on GitHub, you can switch to the branch in the + GitHub UI and click "Pull Request" towards the top of the page + in order to open a pull request. + + + 3. Update the related GitHub issue. + + If there is a GitHub issue associated with the change you + submitted, then you should update the ticket to include the + location of your branch, along with any other commentary you + may wish to make. + +Testing +======= + +Getting Started +--------------- + +Our puppet modules provide [`Gemfile`](./Gemfile)s which can tell a ruby +package manager such as [bundler](http://bundler.io/) what Ruby packages, +or Gems, are required to build, develop, and test this software. + +Please make sure you have [bundler installed](http://bundler.io/#getting-started) +on your system, then use it to install all dependencies needed for this project, +by running + +```shell +% bundle install +Fetching gem metadata from https://rubygems.org/........ +Fetching gem metadata from https://rubygems.org/.. +Using rake (10.1.0) +Using builder (3.2.2) +-- 8><-- many more --><8 -- +Using rspec-system-puppet (2.2.0) +Using serverspec (0.6.3) +Using rspec-system-serverspec (1.0.0) +Using bundler (1.3.5) +Your bundle is complete! +Use `bundle show [gemname]` to see where a bundled gem is installed. +``` + +NOTE some systems may require you to run this command with sudo. + +If you already have those gems installed, make sure they are up-to-date: + +```shell +% bundle update +``` + +With all dependencies in place and up-to-date we can now run the tests: + +```shell +% rake spec +``` + +This will execute all the [rspec tests](http://rspec-puppet.com/) tests +under [spec/defines](./spec/defines), [spec/classes](./spec/classes), +and so on. rspec tests may have the same kind of dependencies as the +module they are testing. While the module defines in its [Modulefile](./Modulefile), +rspec tests define them in [.fixtures.yml](./fixtures.yml). + +Some puppet modules also come with [beaker](https://github.com/puppetlabs/beaker) +tests. These tests spin up a virtual machine under +[VirtualBox](https://www.virtualbox.org/)) with, controlling it with +[Vagrant](http://www.vagrantup.com/) to actually simulate scripted test +scenarios. In order to run these, you will need both of those tools +installed on your system. + +You can run them by issuing the following command + +```shell +% rake spec_clean +% rspec spec/acceptance +``` + +This will now download a pre-fabricated image configured in the [default node-set](./spec/acceptance/nodesets/default.yml), +install puppet, copy this module and install its dependencies per [spec/spec_helper_acceptance.rb](./spec/spec_helper_acceptance.rb) +and then run all the tests under [spec/acceptance](./spec/acceptance). + +Writing Tests +------------- + +XXX getting started writing tests. + +If you have commit access to the repository +=========================================== + +Even if you have commit access to the repository, you will still need to +go through the process above, and have someone else review and merge +in your changes. The rule is that all changes must be reviewed by a +developer on the project (that did not write the code) to ensure that +all changes go through a code review process. + +Having someone other than the author of the topic branch recorded as +performing the merge is the record that they performed the code +review. + + +Additional Resources +==================== + +* [Getting additional help](http://puppet.com/community/get-help) + +* [Writing tests](https://docs.puppet.com/guides/module_guides/bgtm.html#step-three-module-testing) + +* [General GitHub documentation](http://help.github.com/) + +* [GitHub pull request documentation](http://help.github.com/send-pull-requests/) + + diff --git a/modules/utilities/windows/repository_managers/chocolatey/Gemfile b/modules/utilities/windows/repository_managers/chocolatey/Gemfile new file mode 100644 index 000000000..0c629e701 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/Gemfile @@ -0,0 +1,152 @@ +#This file is generated by ModuleSync, do not edit. + +source ENV['GEM_SOURCE'] || "https://rubygems.org" + +# Determines what type of gem is requested based on place_or_version. +def gem_type(place_or_version) + if place_or_version =~ /^git:/ + :git + elsif place_or_version =~ /^file:/ + :file + else + :gem + end +end + +# Find a location or specific version for a gem. place_or_version can be a +# version, which is most often used. It can also be git, which is specified as +# `git://somewhere.git#branch`. You can also use a file source location, which +# is specified as `file://some/location/on/disk`. +def location_for(place_or_version, fake_version = nil) + if place_or_version =~ /^(git[:@][^#]*)#(.*)/ + [fake_version, { :git => $1, :branch => $2, :require => false }].compact + elsif place_or_version =~ /^file:\/\/(.*)/ + ['>= 0', { :path => File.expand_path($1), :require => false }] + else + [place_or_version, { :require => false }] + end +end + +# Used for gem conditionals +supports_windows = true + +# The following gems are not included by default as they require DevKit on Windows. +# You should probably include them in a Gemfile.local or a ~/.gemfile +#gem 'pry' #this may already be included in the gemfile +#gem 'pry-stack_explorer', :require => false +#if RUBY_VERSION =~ /^2/ +# gem 'pry-byebug' +#else +# gem 'pry-debugger' +#end + +group :development do + gem 'rake', :require => false + gem 'rspec', '~>3.0', :require => false + gem 'puppet-lint', :require => false + gem 'puppetlabs_spec_helper', '~>0.10.3', :require => false + gem 'puppet_facts', :require => false + gem 'mocha', '~>0.10.5', :require => false + gem 'pry', :require => false + gem 'json_pure', '<= 2.0.1', :require => false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0') +end + +group :system_tests do + gem 'beaker', *location_for(ENV['BEAKER_VERSION'] || '~> 2.20') + gem 'master_manipulator', '~> 1.2', :require => false + gem 'beaker-windows', '~> 0.6', :require => false + gem 'beaker-hostgenerator', '~> 0.6', :require => false +end + +gem 'puppet', *location_for(ENV['PUPPET_GEM_VERSION']) + +# Only explicitly specify Facter/Hiera if a version has been specified. +# Otherwise it can lead to strange bundler behavior. If you are seeing weird +# gem resolution behavior, try setting `DEBUG_RESOLVER` environment variable +# to `1` and then run bundle install. +gem 'facter', *location_for(ENV['FACTER_GEM_VERSION']) if ENV['FACTER_GEM_VERSION'] +gem 'hiera', *location_for(ENV['HIERA_GEM_VERSION']) if ENV['HIERA_GEM_VERSION'] + +# For Windows dependencies, these could be required based on the version of +# Puppet you are requiring. Anything greater than v3.5.0 is going to have +# Windows-specific dependencies dictated by the gem itself. The other scenario +# is when you are faking out Puppet to use a local file path / git path. +explicitly_require_windows_gems = false +puppet_gem_location = gem_type(ENV['PUPPET_GEM_VERSION']) +# This is not a perfect answer to the version check +if puppet_gem_location != :gem || (ENV['PUPPET_GEM_VERSION'] && Gem::Version.correct?(ENV['PUPPET_GEM_VERSION']) && Gem::Requirement.new('< 3.5.0').satisfied_by?(Gem::Version.new(ENV['PUPPET_GEM_VERSION'].dup))) + if Gem::Platform.local.os == 'mingw32' + explicitly_require_windows_gems = true + end + if puppet_gem_location == :gem + # If facterversion hasn't been specified and we are + # looking for a Puppet Gem version less than 3.5.0, we + # need to ensure we get a good Facter for specs. + gem "facter",">= 1.6.11","<= 1.7.5",:require => false unless ENV['FACTER_GEM_VERSION'] + # If hieraversion hasn't been specified and we are + # looking for a Puppet Gem version less than 3.5.0, we + # need to ensure we get a good Hiera for specs. + gem "hiera",">= 1.0.0","<= 1.3.0",:require => false unless ENV['HIERA_GEM_VERSION'] + end +end + +if explicitly_require_windows_gems + # This also means Puppet Gem less than 3.5.0 - this has been tested back + # to 3.0.0. Any further back is likely not supported. + if puppet_gem_location == :gem + gem "ffi", "1.9.0", :require => false + gem "win32-eventlog", "0.5.3","<= 0.6.5", :require => false + gem "win32-process", "0.6.5","<= 0.7.5", :require => false + gem "win32-security", "~> 0.1.2","<= 0.2.5", :require => false + gem "win32-service", "0.7.2","<= 0.8.8", :require => false + gem "minitar", "0.5.4", :require => false + else + gem "ffi", "~> 1.9.0", :require => false + gem "win32-eventlog", "~> 0.5","<= 0.6.5", :require => false + gem "win32-process", "~> 0.6","<= 0.7.5", :require => false + gem "win32-security", "~> 0.1","<= 0.2.5", :require => false + gem "win32-service", "~> 0.7","<= 0.8.8", :require => false + gem "minitar", "~> 0.5.4", :require => false + end + + gem "win32-dir", "~> 0.3","<= 0.4.9", :require => false + gem "win32console", "1.3.2", :require => false if RUBY_VERSION =~ /^1\./ + + # sys-admin was removed in Puppet 3.7.0+, and doesn't compile + # under Ruby 2.3 - so restrict it to Ruby 1.x + gem "sys-admin", "1.5.6", :require => false if RUBY_VERSION =~ /^1\./ + + # Puppet less than 3.7.0 requires these. + # Puppet 3.5.0+ will control the actual requirements. + # These are listed in formats that work with all versions of + # Puppet from 3.0.0 to 3.6.x. After that, these were no longer used. + # We do not want to allow newer versions than what came out after + # 3.6.x to be used as they constitute some risk in breaking older + # functionality. So we set these to exact versions. + gem "win32-api", "1.4.8", :require => false + gem "win32-taskscheduler", "0.2.2", :require => false + gem "windows-api", "0.4.3", :require => false + gem "windows-pr", "1.2.3", :require => false +else + if Gem::Platform.local.os == 'mingw32' + # If we're using a Puppet gem on windows, which handles its own win32-xxx gem dependencies (Pup 3.5.0 and above), set maximum versions + # Required due to PUP-6445 + gem "win32-dir", "<= 0.4.9", :require => false + gem "win32-eventlog", "<= 0.6.5", :require => false + gem "win32-process", "<= 0.7.5", :require => false + gem "win32-security", "<= 0.2.5", :require => false + gem "win32-service", "<= 0.8.8", :require => false + end +end + +# Evaluate Gemfile.local if it exists +if File.exists? "#{__FILE__}.local" + eval(File.read("#{__FILE__}.local"), binding) +end + +# Evaluate ~/.gemfile if it exists +if File.exists?(File.join(Dir.home, '.gemfile')) + eval(File.read(File.join(Dir.home, '.gemfile')), binding) +end + +# vim:ft=ruby diff --git a/modules/utilities/windows/repository_managers/chocolatey/LICENSE b/modules/utilities/windows/repository_managers/chocolatey/LICENSE new file mode 100644 index 000000000..7a4a3ea24 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/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. \ No newline at end of file diff --git a/modules/utilities/windows/repository_managers/chocolatey/MAINTAINERS.md b/modules/utilities/windows/repository_managers/chocolatey/MAINTAINERS.md new file mode 100644 index 000000000..980e355ee --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/MAINTAINERS.md @@ -0,0 +1,6 @@ +## Maintenance + +Maintainers: + - Puppet Windows Team `windows |at| puppet |dot| com` + +Tickets: https://tickets.puppet.com/browse/MODULES. Make sure to set component to `chocolatey`. \ No newline at end of file diff --git a/modules/utilities/windows/repository_managers/chocolatey/NOTICE b/modules/utilities/windows/repository_managers/chocolatey/NOTICE new file mode 100644 index 000000000..e69de29bb diff --git a/modules/utilities/windows/repository_managers/chocolatey/README.md b/modules/utilities/windows/repository_managers/chocolatey/README.md new file mode 100644 index 000000000..73bdbbf6d --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/README.md @@ -0,0 +1,783 @@ +# Chocolatey Package Provider for Puppet + +### Chocolatey for Business Now Available! + +We're excited for you to learn more about what's available in the [Business editions](https://chocolatey.org/compare)! + +## Build Status + +Travis | AppVeyor +------------- | ------------- +[![Build Status](https://api.travis-ci.org/puppetlabs/puppetlabs-chocolatey.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-chocolatey) | [![Build status](https://ci.appveyor.com/api/projects/status/uosorvcyhnayv70m/branch/master?svg=true)](https://ci.appveyor.com/project/puppetlabs/puppetlabs-chocolatey/branch/master) + +#### Table of Contents + +1. [Overview](#overview) +2. [Module Description - What the chocolatey module does and why it is useful](#module-description) + * [Why Chocolatey](#why-chocolatey) +3. [Setup - The basics of getting started with chocolatey](#setup) + * [What chocolatey affects](#what-chocolatey-affects) + * [Setup requirements](#setup-requirements) + * [Beginning with Chocolatey provider](#beginning-with-chocolatey-provider) +4. [Usage - Configuration options and additional functionality](#usage) +5. [Reference](#reference) + * [Classes](#public-classes) + * [Facts](#facts) + * [Types/Providers](#typesproviders) + * [Package provider: Chocolatey](#package-provider-chocolatey) + * [Chocolatey source configuration](#chocolateysource) + * [Chocolatey feature configuration](#chocolateyfeature) + * [Chocolatey config configuration](#chocolateyconfig) + * [Class: chocolatey](#class-chocolatey) +6. [Limitations - OS compatibility, etc.](#limitations) + * [Known Issues](#known-issues) +7. [Development - Guide for contributing to the module](#development) +8. [Attributions](#attributions) + +## Overview + +This is a [Puppet](http://docs.puppet.com/) package provider for +[Chocolatey](https://github.com/chocolatey/chocolatey), which is +like apt-get, but for Windows. Check the module's metadata.json for +compatible Puppet and Puppet Enterprise versions. + +## Module Description + +This is the official module for working with the [Chocolatey](https://chocolatey.org/about) +package manager. + +This module supports all editions of Chocolatey, including FOSS, [Professional](https://chocolatey.org/compare) and [Chocolatey for Business](https://chocolatey.org/compare). + +This module is able to: + +* Install Chocolatey +* Work with custom location installations +* Configure Chocolatey +* Use Chocolatey as a package provider + +### Why Chocolatey + +Chocolatey closely mimics how package managers on other operating systems work. If you can imagine the built-in provider for +Windows versus Chocolatey, take a look at the use case of installing git: + +~~~puppet +# Using built-in provider +package { "Git version 1.8.4-preview20130916": + ensure => installed, + source => 'C:\temp\Git-1.8.4-preview20130916.exe', + install_options => ['/VERYSILENT'] +} +~~~ + +~~~puppet +# Using Chocolatey (set as default for Windows) +package { 'git': + ensure => latest, +} +~~~ + +With the built-in provider: + * The [package name must match ***exactly***](https://docs.puppet.com/puppet/latest/reference/resources_package_windows.html#package-name-must-be-the-displayname) the name from installed programs. + * The package name has issues with unicode characters. + * The [source must point to the location](https://docs.puppet.com/puppet/latest/reference/resources_package_windows.html#the-source-attribute-is-required) of the executable installer. + * It cannot `ensure => latest`. Read about [handling versions and upgrades](https://docs.puppet.com/puppet/latest/reference/resources_package_windows.html#handling-versions-and-upgrades) in the Puppet documentation. + +With Chocolatey's provider: + * The package name only has to match the name of the package, which can be whatever you choose. + * The package knows how to install the software silently. + * The package knows where to get the executable installer. + * The source is able to specify different Chocolatey feeds. + * Chocolatey makes `package` more platform agnostic, because it looks exactly like other platforms. + +For reference, read about the [provider features available](https://docs.puppet.com/references/latest/type.html#package-provider-features) from the built-in provider, compared to other package managers: + +| Provider | holdable | install options | installable | package settings | purgeable | reinstallable | uninstall options | uninstallable | upgradeable | versionable | virtual packages | +|------------|----------|-----------------|-------------|------------------|-----------|---------------|-------------------|---------------|-------------|-------------|------------------| +| Windows | | x | x | | | | x | x | | x | | +| Chocolatey | x | x | x | | | | x | x | x | x | | +| apt | x | x | x | | x | | | x | x | x | | +| yum | | x | x | | x | | | x | x | x | x | + +## Setup + +### What Chocolatey affects + +Chocolatey affects your system and what software is installed on it, ranging +from tools and portable software, to natively installed applications. + +### Setup Requirements + +Chocolatey requires the following components: + + * Powershell v2+ (Installed on most systems by default) + * .NET Framework v4+ + +### Beginning with Chocolatey provider + +Install this module via any of these approaches: + +* [Puppet Forge](http://forge.puppet.com/chocolatey/chocolatey) +* git-submodule ([tutorial](http://goo.gl/e9aXh)) +* [librarian-puppet](https://github.com/rodjek/librarian-puppet) +* [r10k](https://github.com/puppetlabs/r10k) + +## Usage + +### Manage Chocolatey installation + +Ensure Chocolatey is installed and configured: + +~~~puppet +include chocolatey +~~~ + +#### Override default Chocolatey install location + +~~~puppet +class {'chocolatey': + choco_install_location => 'D:\secured\choco', +} +~~~ + +**NOTE:** This will affect suitability on first install. There are also +special considerations for `C:\Chocolatey` as an install location, see +[`choco_install_location`](#choco_install_location) for details. + +#### Use an internal chocolatey.nupkg for Chocolatey installation + +~~~puppet +class {'chocolatey': + chocolatey_download_url => 'https://internalurl/to/chocolatey.nupkg', + use_7zip => false, + choco_install_timeout_seconds => 2700, +} +~~~ + +#### Use a file chocolatey.0.9.9.9.nupkg for installation + +~~~puppet +class {'chocolatey': + chocolatey_download_url => 'file:///c:/location/of/chocolatey.0.9.9.9.nupkg', + use_7zip => false, + choco_install_timeout_seconds => 2700, +} +~~~ + +#### Specify the version of chocolatey by class parameters + +~~~puppet +class {'chocolatey': + chocolatey_download_url => 'file:///c:/location/of/chocolatey.0.9.9.9.nupkg', + use_7zip => false, + choco_install_timeout_seconds => 2700, + chocolatey_version => '0.9.9.9', +} +~~~ + + +#### Log chocolatey bootstrap installer script output + +~~~puppet +class {'chocolatey': + log_output => true, +} +~~~ + + +### Configuration + +If you have Chocolatey 0.9.9.x or above, you can take advantage of configuring different aspects of Chocolatey. + +#### Sources Configuration + +You can specify sources that Chocolatey uses by default, along with priority. + +Requires Chocolatey v0.9.9.0+. + +##### Disable the default community repository source + +~~~puppet +chocolateysource {'chocolatey': + ensure => disabled, +} +~~~ + +##### Set a priority on a source + +~~~puppet +chocolateysource {'chocolatey': + ensure => present, + location => 'https://chocolatey.org/api/v2', + priority => 1, +} +~~~ + +##### Add credentials to a source + +~~~puppet +chocolateysource {'sourcename': + ensure => present, + location => 'https://internal/source', + user => 'username', + password => 'password', +} +~~~ + +**NOTE:** Chocolatey encrypts the password in a way that is not +verifiable. If you need to rotate passwords, you cannot use this +resource to do so unless you also change the location, user, or priority +(because those are ensurable properties). + +#### Features Configuration + +You can configure features that Chocolatey has available. Run +`choco feature list` to see the available configuration features. + +Requires Chocolatey v0.9.9.0+. + +##### Enable Auto Uninstaller + +Uninstall from Programs and Features without requiring an explicit +uninstall script. + +~~~puppet +chocolateyfeature {'autouninstaller': + ensure => enabled, +} +~~~ + +##### Disable Use Package Exit Codes + +Requires 0.9.10+ for this feature. + +**Use Package Exit Codes** - Allows package scripts to provide exit codes. With +this enabled, Chocolatey uses package exit codes for exit when +non-zero (this value can come from a dependency package). Chocolatey +defines valid exit codes as 0, 1605, 1614, 1641, 3010. With this feature +disabled, Chocolatey exits with a 0 or a 1 (matching previous behavior). + +~~~puppet +chocolateyfeature {'usepackageexitcodes': + ensure => disabled, +} +~~~ + +##### Enable Virus Check + +Requires 0.9.10+ and [Chocolatey Pro / Business](https://chocolatey.org/compare) +for this feature. + +**Virus Check** - Performs virus checking on downloaded files. *(Licensed versions only.)* + +~~~puppet +chocolateyfeature {'viruscheck': + ensure => enabled, +} +~~~ + +##### Enable FIPS Compliant Checksums + +Requires 0.9.10+ for this feature. + +**Use FIPS Compliant Checksums** - Ensures checksumming done by Chocolatey uses +FIPS compliant algorithms. *Not recommended unless required by FIPS Mode.* +Enabling on an existing installation could have unintended consequences +related to upgrades or uninstalls. + +~~~puppet +chocolateyfeature {'usefipscompliantchecksums': + ensure => enabled, +} +~~~ + +#### Config configuration + +You can configure config values that Chocolatey has available. Run +`choco config list` to see the config settings available (just the +config settings section). + +Requires Chocolatey v0.9.10.0+. + +##### Set cache location + +The cache location defaults to the TEMP directory. You can set an explicit directory +to cache downloads to instead of the default. + +~~~puppet +chocolateyconfig {'cachelocation': + value => "c:\\downloads", +} +~~~ + +##### Unset cache location + +Removes cache location setting, returning the setting to its default. + +~~~puppet +chocolateyconfig {'cachelocation': + ensure => absent, +} +~~~ + +##### Use an explicit proxy + +When using Chocolatey behind a proxy, set `proxy` and optionally +`proxyUser` and `proxyPassword`. + +**NOTE:** The `proxyPassword` value is not verifiable. + +~~~puppet +chocolateyconfig {'proxy': + value => 'https://someproxy.com', +} + +chocolateyconfig {'proxyUser': + value => 'bob', +} + +# not verifiable +chocolateyconfig {'proxyPassword': + value => 'securepassword', +} +~~~ + +#### Set Chocolatey as Default Windows Provider + +If you want to set this provider as the site-wide default, +add to your `site.pp`: + +~~~puppet +if $::kernel == 'windows' { + Package { provider => chocolatey, } +} + +# OR + +case $operatingsystem { + 'windows': { + Package { provider => chocolatey, } + } +} +~~~ + +### Packages + +#### With all options + +~~~puppet +package { 'notepadplusplus': + ensure => installed|latest|'1.0.0'|absent, + provider => 'chocolatey', + install_options => ['-pre','-params','"','param1','param2','"'], + uninstall_options => ['-r'], + source => 'https://myfeed.example.com/api/v2', +} +~~~ + +* Supports `installable` and `uninstallable`. +* Supports `versionable` so that `ensure => '1.0'` works. +* Supports `upgradeable`. +* Supports `latest` (checks upstream), `absent` (uninstall). +* Supports `install_options` for pre-release, and other command-line options. +* Supports `uninstall_options` for pre-release, and other command-line options. +* Supports `holdable`, requires Chocolatey v0.9.9.0+. + +#### Simple install + +~~~puppet +package { 'notepadplusplus': + ensure => installed, + provider => 'chocolatey', +} +~~~ + +#### To always ensure using the newest version available + +~~~puppet +package { 'notepadplusplus': + ensure => latest, + provider => 'chocolatey', +} +~~~ + +#### To ensure a specific version + +~~~puppet +package { 'notepadplusplus': + ensure => '6.7.5', + provider => 'chocolatey', +} +~~~ + +#### To specify custom source + +~~~puppet +package { 'notepadplusplus': + ensure => '6.7.5', + provider => 'chocolatey', + source => 'C:\local\folder\packages', +} +~~~ + +~~~puppet +package { 'notepadplusplus': + ensure => '6.7.5', + provider => 'chocolatey', + source => '\\unc\source\packages', +} +~~~ + +~~~puppet +package { 'notepadplusplus': + ensure => '6.7.5', + provider => 'chocolatey', + source => 'https://custom.nuget.odata.feed/api/v2/', +} +~~~ + +~~~puppet +package { 'notepadplusplus': + ensure => '6.7.5', + provider => 'chocolatey', + source => 'C:\local\folder\packages;https://chocolatey.org/api/v2/', +} +~~~ + +#### Install options with spaces + +Spaces in arguments **must always** be covered with a separation. Shown +below is an example of how you configure `-installArgs "/VERYSILENT /NORESTART"`. + +~~~puppet +package {'launchy': + ensure => installed, + provider => 'chocolatey', + install_options => ['-override', '-installArgs', '"', '/VERYSILENT', '/NORESTART', '"'], +} +~~~ + +#### Install options with quotes or spaces + +The underlying installer may need quotes passed to it. This is possible, but not +as intuitive. The example below covers passing `/INSTALLDIR="C:\Program Files\somewhere"`. + +For this to be passed through with Chocolatey, you need a set of double +quotes surrounding the argument and two sets of double quotes surrounding the +item that must be quoted (see [how to pass/options/switches](https://github.com/chocolatey/choco/wiki/CommandsReference#how-to-pass-options--switches)). This makes the +string look like `-installArgs "/INSTALLDIR=""C:\Program Files\somewhere"""` for +proper use with Chocolatey. + +Then, for Puppet to handle that appropriately, you must split on ***every*** space. +Yes, on **every** space you must split the string or the result comes out +incorrectly. This means it will look like the following: + +~~~puppet +install_options => ['-installArgs', + '"/INSTALLDIR=""C:\Program', 'Files\somewhere"""'] +~~~ + +Make sure you have all of the right quotes - start it off with a single double +quote, then two double quotes, then close it all by closing the two double +quotes and then the single double quote or a possible three double quotes at +the end. + +~~~puppet +package {'mysql': + ensure => latest, + provider => 'chocolatey', + install_options => ['-override', '-installArgs', + '"/INSTALLDIR=""C:\Program', 'Files\somewhere"""'], +} +~~~ + +You can split it up a bit for readability if it suits you: + +~~~puppet +package {'mysql': + ensure => latest, + provider => 'chocolatey', + install_options => ['-override', '-installArgs', '"' + '/INSTALLDIR=""C:\Program', 'Files\somewhere""', + '"'], +} +~~~ + +**Note:** The above is for Chocolatey v0.9.9+. You may need to look for an +alternative method to pass args if you have 0.9.8.x and below. + +## Reference + +### Classes + +#### Public classes + +* [`chocolatey`](#class-chocolatey) + +#### Private classes + +* `chocolatey::install.pp`: Ensures Chocolatey is installed. +* `chocolatey::config.pp`: Ensures Chocolatey is configured. + +### Facts + +* `chocolateyversion` - The version of the installed Chocolatey client (could also be provided by class parameter `chocolatey_version`). +* `choco_install_path` - The location of the installed Chocolatey client (could also be provided by class parameter `choco_install_location`). + +### Types/Providers + +* [Chocolatey provider](#package-provider-chocolatey) +* [Chocolatey source configuration](#chocolateysource) +* [Chocolatey feature configuration](#chocolateyfeature) + + +### Package provider: Chocolatey + +Chocolatey implements a [package type](http://docs.puppet.com/references/latest/type.html#package) with a resource provider, which is built into Puppet. + +This provider supports the `install_options` and `uninstall_options` attributes, +which allow command-line options to be passed to the `choco` command. These options +should be specified as documented below. + + * Required binaries: `choco.exe`, usually found in `C:\Program Data\chocolatey\bin\choco.exe`. + * The binary is searched for using the environment variable `ChocolateyInstall`, then by two known locations (`C:\Chocolatey\bin\choco.exe` and `C:\ProgramData\chocolatey\bin\choco.exe`). + * Supported features: `install_options`, `installable`, `uninstall_options`, +`uninstallable`, `upgradeable`, `versionable`. + +**NOTE**: the root of `C:\` is not a secure location by default, so you may want to update the security on the folder. + +#### Properties/Parameters + +##### `ensure` + +(**Property**: This attribute represents a concrete state on the target system.) + +Specifies what state the package should be in. You can choose which package to retrieve by +specifying a version number or `latest` as the ensure value. Valid options: `present` (also called `installed`), `absent`, `latest`, +`held` or a version number. Default: `installed`. + +##### `install_options` + +Specifies an array of additional options to pass when installing a package. These options are +package-specific, and should be documented by the software vendor. One commonly +implemented option is `INSTALLDIR`: + +~~~puppet +package {'launchy': + ensure => installed, + provider => 'chocolatey', + install_options => ['-installArgs', '"', '/VERYSILENT', '/NORESTART', '"'], +} +~~~ + +**NOTE:** The above method of single quotes in an array is the only method you should use +in passing `install_options` with the Chocolatey provider. There are other ways +to do it, but they are passed through to Chocolatey in ways that may not be +sufficient. + +This is the **only** place in Puppet where backslash separators should be used. +Note that backslashes in double-quoted strings *must* be double-escaped and +backslashes in single-quoted strings *may* be double-escaped. + +##### `name` + +Specifies the package name. This is the name that the packaging system uses internally. Valid options: String. Default: The resource's title. + +##### `provider` + +**Required.** Sets the specific backend to use for the `package` resource. Chocolatey is not the +default provider for Windows, so it must be specified (or by using a resource +default, shown in the Usage section above). Valid options: `'chocolatey'`. + +##### `source` + +Specifies where to find the package file. Use this to override the default +source(s). Valid options: String of either an absolute path to a local +directory containing packages stored on the target system, a URL (to OData feeds), or a network +drive path. Chocolatey maintains default sources in its configuration file that it uses by default. + +Puppet will not automatically retrieve source files for you, and +usually just passes the value of the source to the package installation command. +You can use a `file` resource if you need to manually copy package files to the +target system. + +##### `uninstall_options` + +Specifies an array of additional options to pass when uninstalling a package. These options +are package-specific, and should be documented by the software vendor. + +~~~puppet +package {'launchy': + ensure => absent, + provider => 'chocolatey', + uninstall_options => ['-uninstallargs', '"', '/VERYSILENT', '/NORESTART', '"'], +} +~~~ + +The above method of single quotes in an array is the only method you should use +in passing `uninstall_options` with the Chocolatey provider. There are other ways +to do it, but they are passed to Chocolatey in ways that may not be +sufficient. + +**NOTE:** This is the **only** place in Puppet where backslash separators should be used. +Backslashes in double-quoted strings *must* be double-escaped and +backslashes in single-quoted strings *may* be double-escaped. + + +### ChocolateySource + +Allows managing default sources for Chocolatey. A source can be a folder, a CIFS share, +a NuGet Http OData feed, or a full Package Gallery. Learn more about sources at +[How To Host Feed](https://chocolatey.org/docs/how-to-host-feed). Requires +Chocolatey v0.9.9.0+. + +#### Properties/Parameters + +##### `name` + +Specifies the name of the source. Used for uniqueness. Also sets the `location` to this value if `location` is unset. Valid options: String. Default: The resource's title. + +##### `ensure` + +(**Property**: This parameter represents a concrete state on the target system.) + +Specifies what state the source should be in. Default: `present`. Valid options: `present`, `disabled`, or `absent`. `disabled` should only be used with existing sources. + +##### `location` + +(**Property**: This parameter represents a concrete state on the target system.) + +Specifies the location of the source repository. Valid options: String of a URL pointing to an OData feed (such as chocolatey/chocolatey_server), a CIFS (UNC) share, or a local folder. Required when `ensure => present` (`present` is default value for `ensure`). + +##### `user` + +(**Property**: This parameter represents a concrete state on the target system.) + +Specifies an optional user name for authenticated feeds. Requires at least Chocolatey v0.9.9.0. Default: `nil`. Specifying an empty value is the same as setting the value to `nil` or not specifying the property at all. + +##### `password` + +Specifies an optional user password for authenticated feeds. Not ensurable. Value cannot be checked with current value. If you need to update the password, update another setting as well to force the update. Requires at least Chocolatey v0.9.9.0. Default: `nil`. Specifying an empty value is the same as setting the value to `nil` or not specifying the property at all. + +##### `priority` + +(**Property**: This parameter represents a concrete state on the target system.) + +Specifies an optional priority for explicit feed order when searching for packages across multiple feeds. The lower the number, the higher the priority. Sources with a 0 priority are considered no priority and are added after other sources with a priority number. Requires at least Chocolatey v0.9.9.9. Default: `0`. + +### ChocolateyFeature + +Allows managing features for Chocolatey. Features are configurations that +act as switches to turn on or off certain aspects of how +Chocolatey works. Learn more about features in the +[Chocolatey documentation](https://chocolatey.org/docs/commands-feature). Requires +Chocolatey v0.9.9.0+. + +#### Properties/Parameters + +##### `name` + +Specifies the name of the feature. Used for uniqueness. Valid options: String. Default: The resource's title. + +##### `ensure` + +(**Property**: This parameter represents a concrete state on the target system.) + +Specifies what state the feature should be in. Valid options: `enabled` or `disabled`. Default: `disabled`. + + +### ChocolateyConfig + +Allows managing config settings for Chocolatey. Configuration values +provide settings for users to configure aspects of Chocolatey and the +way it functions. Similar to features, except allow for user configured +values. Learn more about config settings at +[Config](https://chocolatey.org/docs/commands-config). Requires +Chocolatey v0.9.9.9+. + +#### Properties/Parameters + +##### `name` + +(**Namevar**: If ommitted, this parameter's value will default to the resource's +title.) + +Specifies the name of the config setting. Used for uniqueness. Puppet is not able to +easily manage any values that include "password" in the key name because they +will be encrypted in the configuration file. + +##### `ensure` + +(**Property**: This parameter represents a concrete state on the target system.) + +Specifies what state the config should be in. Valid options: `present` or `absent`. Default: `present`. + +##### `value` + +(**Property**: This parameter represents a concrete state on the target system.) + +Specifies the value of the config setting. If the name includes "password", then the value +is not ensurable due to being encrypted in the configuration file. + + +### Class: chocolatey + +Manages installation and configuration of Chocolatey itself. + +#### Parameters + +##### `choco_install_location` + +Specifies where Chocolatey install should be located. Valid options: Must be an absolute path starting with a drive letter, for example: `c:\`. Default: The currently detected install location based on the `ChocolateyInstall` environment variable. If not specified, falls back to `'C:\ProgramData\chocolatey'`. + +**NOTE:** Puppet can install Chocolatey and configure Chocolatey install packages during the same run *UNLESS* you specify this setting. This is due to the way the providers search for suitability of the command, falling back to the default install for the executable when none is found. Because environment variables and commands do not refresh during the same Puppet run (due somewhat to a Windows limitation with updating environment information for currently running processes), installing to a directory that is not the default won't be detected until the next time Puppet runs. So unless you really want this installed elsewhere and don't have a current existing install in that non-default location, do not set this value. + +Specifying `C:\Chocolatey` as the install directory will trigger Chocolatey to attempt to upgrade that directory. This is due to that location being the original install location for Chocolatey before it was moved to another directory and subsequently locked down. If you need this to be the installation directory, please define an environment variable `ChocolateyAllowInsecureRootDirectory` and set it to `'true'`. For more information, please see the [CHANGELOG for 0.9.9](https://github.com/chocolatey/choco/blob/master/CHANGELOG.md#099-march-3-2015). + +If you override the default installation directory you need to set appropriate permissions on that install location, because Chocolatey does not restrict access to the custom directory to only Administrators. Chocolatey only restricts access to the directory in the default install location, to avoid permissions issues with custom locations, among other reasons. See ["Can I install Chocolatey to another location?"](https://chocolatey.org/install#can-i-install-chocolatey-to-another-location) for more information. + +##### `use_7zip` + +Specifies whether to use the built-in shell or allow the installer to download 7zip to extract `chocolatey.nupkg` during installation. Valid options: `true`, `false`. Default: `false`. + +##### `choco_install_timeout_seconds` + +Specifies how long in seconds should be allowed for the install of Chocolatey (including .NET Framework 4 if necessary). Valid options: Number. Default: `1500` (25 minutes). + +##### `chocolatey_download_url` + +Specifies the URL that returns `chocolatey.nupkg`. Valid options: String of URL, not necessarily from an OData feed. Any URL location will work, but it must result in the chocolatey nupkg file being downloaded. Default: `'https://chocolatey.org/api/v2/package/chocolatey/'`. + +##### `enable_autouninstaller` + +*Only for 0.9.9.x users. Chocolatey 0.9.10.x+ ignores this setting.* Specifies whether auto uninstaller is enabled. Auto uninstaller allows Chocolatey to automatically manage the uninstall of software from Programs and Features without necessarily requiring a `chocolateyUninstall.ps1` file in the package. Valid options: `true`, `false`. Default: `true`. + +##### `log_output` + +Specifies whether to log output from the installer. Valid options: `true`, `false`. Default: `false`. + + +## Limitations + +1. Works with Windows only. +2. If you override an existing install location of Chocolatey using `choco_install_location =>` in the Chocolatey class, it does not bring any of the existing packages with it. You will need to handle that through some other means. +3. Overriding the install location will also not allow Chocolatey to be configured or install packages on the same run that it is installed on. See [`choco_install_location`](#choco_install_location) for details. + +### Known Issues + +1. This module doesn't support side by side scenarios. +2. This module may have issues upgrading Chocolatey itself using the package resource. +3. If .NET 4.0 is not installed, it may have trouble installing Chocolatey. Chocolatey version 0.9.9.9+ helps alleviate this issue. +4. If there is an error in the installer (`InstallChocolatey.ps1.erb`), it may not show as an error. This may be an issue with the PowerShell provider and is still under investigation. + +## Development + +Puppet Inc modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can’t access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve. + +We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things. + +For more information, see our [module contribution guide.](https://docs.puppet.com/forge/contributing.html) + +## Attributions + +A special thanks goes out to [Rich Siegel](https://github.com/rismoney) and [Rob Reynolds](https://github.com/ferventcoder) who wrote the original +provider and continue to contribute to the development of this provider. diff --git a/modules/utilities/windows/repository_managers/chocolatey/Rakefile b/modules/utilities/windows/repository_managers/chocolatey/Rakefile new file mode 100644 index 000000000..8e029301c --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/Rakefile @@ -0,0 +1,104 @@ +require 'rake' +require 'rspec/core/rake_task' +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet' + +begin + require 'beaker/tasks/test' unless RUBY_PLATFORM =~ /win32/ +rescue LoadError + #Do nothing, only installed with system_tests group +end + + +# If puppet does not support symlinks (e.g., puppet <= 3.5) we cannot use +# puppetlabs_spec_helper's `rake spec` task because it requires symlink +# support. Redefine `rake spec` to avoid calling `rake spec_prep` (requires +# symlinks to place fixtures) and restrict the pattern match only files under +# the 'unit' directory (tests in other dirs require fixtures). +if Puppet::Util::Platform.windows? and !Puppet::FileSystem.respond_to?(:symlink) + ENV["SPEC"] = "./spec/{unit,integration}/**/*_spec.rb" + Rake::Task[:spec].clear if Rake::Task.task_defined?(:spec) + task :spec do + Rake::Task[:spec_standalone].invoke + Rake::Task[:spec_clean].invoke + end +end + +# These lint exclusions are in puppetlabs_spec_helper but needs a version above 0.10.3 +# Line length test is 80 chars in puppet-lint 1.1.0 +PuppetLint.configuration.send('disable_80chars') +# Line length test is 140 chars in puppet-lint 2.x +PuppetLint.configuration.send('disable_140chars') + +task :default => [:spec] + +desc 'Generate code coverage' +RSpec::Core::RakeTask.new(:coverage) do |t| + t.rcov = true + t.rcov_opts = ['--exclude', 'spec'] +end + + +platform = ENV["PLATFORM"] + +# Create the directory, if it exists already you'll get an error, but this should not stop the execution +begin + sh 'mkdir tests/configs' +rescue => e + puts e.message +end + +desc 'Executes reference tests (agent only) intended for use in CI' +task :reference_tests do + command = "bundle exec beaker-hostgenerator --global-config {masterless=true} #{platform} > tests/configs/#{platform}" # should we assume the "configs" directory is present? + sh command + + command =<<-EOS +bundle exec beaker \ + --debug \ + --preserve-hosts never \ + --config tests/configs/$PLATFORM \ + --keyfile ~/.ssh/id_rsa-acceptance \ + --load-path tests/lib \ + --type aio \ + --pre-suite tests/reference/pre-suite \ + --tests tests/reference/tests + EOS + sh command +end + +desc 'Executes acceptance tests (master and agent) intended for use in CI' +task :acceptance_tests do + command = "bundle exec beaker-hostgenerator #{platform} > tests/configs/#{platform}" + sh command + + command =<<-EOS +bundle exec beaker \ + --debug \ + --preserve-hosts never \ + --config tests/configs/$PLATFORM \ + --keyfile ~/.ssh/id_rsa-acceptance \ + --load-path tests/lib \ + --pre-suite tests/acceptance/pre-suite \ + --tests tests/acceptance/tests + EOS + sh command +end + +task :acceptance_tests => [:basic_enviroment_variable_check, :acceptance_enviroment_varible_check] +task :reference_tests => [:basic_enviroment_variable_check] + +task :basic_enviroment_variable_check do + abort('PLATFORM variable not present, aborting test.') unless ENV["PLATFORM"] + abort('MODULE_VERSION variable not present, aborting test.') unless ENV["MODULE_VERSION"] +end + +task :acceptance_enviroment_varible_check do + if ENV["BEAKER_PE_DIR"] && ENV["PE_DIST_DIR"] + abort('Either BEAKER_PE_DIR or PE_DIST_DIR variable should be set but not both, aborting test.') + end + if !ENV["BEAKER_PE_DIR"] && !ENV["PE_DIST_DIR"] + abort('Neither BEAKER_PE_DIR or PE_DIST_DIR variable is set, aborting test.') + end +end + diff --git a/modules/utilities/windows/repository_managers/chocolatey/appveyor.yml b/modules/utilities/windows/repository_managers/chocolatey/appveyor.yml new file mode 100644 index 000000000..543c81d2b --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/appveyor.yml @@ -0,0 +1,44 @@ +version: 1.1.x.{build} +skip_commits: + message: /^\(?doc\)?.*/ +clone_depth: 10 +init: +- SET +- 'mkdir C:\ProgramData\PuppetLabs\code && exit 0' +- 'mkdir C:\ProgramData\PuppetLabs\facter && exit 0' +- 'mkdir C:\ProgramData\PuppetLabs\hiera && exit 0' +- 'mkdir C:\ProgramData\PuppetLabs\puppet\var && exit 0' +environment: + matrix: + - PUPPET_GEM_VERSION: ~> 3.0 + RUBY_VER: 193 + - PUPPET_GEM_VERSION: ~> 3.0 + RUBY_VER: 200-x64 + - PUPPET_GEM_VERSION: ~> 4.0 + RUBY_VER: 21 + - PUPPET_GEM_VERSION: ~> 4.0 + RUBY_VER: 21-x64 + - PUPPET_GEM_VERSION: ~> 4.0 + RUBY_VER: 23 + - PUPPET_GEM_VERSION: ~> 4.0 + RUBY_VER: 23-x64 + - PUPPET_GEM_VERSION: 3.0.0 + RUBY_VER: 193 +matrix: + fast_finish: true +install: +- SET PATH=C:\Ruby%RUBY_VER%\bin;%PATH% +- bundle install --jobs 4 --retry 2 --without system_tests +- type Gemfile.lock +build: off +test_script: +- bundle exec puppet -V +- ruby -v +- bundle exec rspec spec/unit -fd -b +notifications: +- provider: Email + to: + - nobody@nowhere.com + on_build_success: false + on_build_failure: false + on_build_status_changed: false diff --git a/modules/utilities/windows/repository_managers/chocolatey/checksums.json b/modules/utilities/windows/repository_managers/chocolatey/checksums.json new file mode 100644 index 000000000..4cbc88179 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/checksums.json @@ -0,0 +1,91 @@ +{ + "CHANGELOG.md": "ed75f911df877999ffe0b3d85c6d4c84", + "CONTRIBUTING.md": "2398672bb3e7c2a5ec11a9cea0f809e9", + "Gemfile": "e0713c9514c65b3bcce69e0b2bace8a7", + "LICENSE": "175792518e4ac015ab6696d16c4f607e", + "MAINTAINERS.md": "00d7777a4e0e4eed90437b4a972cdd6c", + "NOTICE": "267e1dc2b672516ff482a3fe8b857e2c", + "README.md": "a76ff6fb65c846cc273cb66333c2bbb5", + "Rakefile": "cde4be099ca764cc6bd7d706d2e37c90", + "appveyor.yml": "00752619ea15b8c6d287a7ae23a6c668", + "examples/init.pp": "1af719123c9af01ce6efd8de8465ad03", + "lib/facter/choco_install_path.rb": "36ece697e936cc950f8946ca2ac11729", + "lib/facter/chocolateyversion.rb": "ebbfc8535589aad01717852c93975ac3", + "lib/puppet/provider/chocolateyconfig/windows.rb": "048191d42df7e85cfc330569f500f88e", + "lib/puppet/provider/chocolateyfeature/windows.rb": "218b285cde1d86b2a530c194501de8d4", + "lib/puppet/provider/chocolateysource/windows.rb": "0d95da93a40c687a8a631d3c0c539609", + "lib/puppet/provider/package/chocolatey.rb": "80471c41d85faf45a521b5d8467fdd8b", + "lib/puppet/type/chocolateyconfig.rb": "1d86ef49b0faf6a321ea3ca24f9f39b1", + "lib/puppet/type/chocolateyfeature.rb": "1515df1d174d814ffc9bfff073a9051e", + "lib/puppet/type/chocolateysource.rb": "e2054da90dd124161fc64af9c11faf60", + "lib/puppet_x/chocolatey/chocolatey_common.rb": "03d3bf0cf1d2ef4a6843c3cd2e616c53", + "lib/puppet_x/chocolatey/chocolatey_install.rb": "e1e172d99659eb31882d64f88aacff60", + "lib/puppet_x/chocolatey/chocolatey_version.rb": "3155abe3c0a0b20770d322654c02e78d", + "manifests/config.pp": "307f680eb54988b9df8bd16e597a5843", + "manifests/init.pp": "984c562211c9bb0a7262531e1e5b2ef0", + "manifests/install.pp": "091c863df390704a9b01c2eb10c5b133", + "manifests/params.pp": "4a73fc3b0c6379551bdad6e5d3f357b4", + "metadata.json": "140403f7468691a05d49f54a52da9bc1", + "spec/classes/config_spec.rb": "8e6bb682200b29e2d622fa1d20e2a382", + "spec/classes/coverage_spec.rb": "5b6dfa0dd426aca0ccfae23c0a629f0b", + "spec/classes/init_spec.rb": "9d1316b761393c24fe7346aca679e69a", + "spec/classes/install_spec.rb": "76c2b4d46d8ddeac0d87ecb6612d58a4", + "spec/spec_helper.rb": "7adb146e2bdbb16f41786e325f33b1c5", + "spec/unit/facter/choco_install_path_spec.rb": "f23010110c2084aadc544b5c4d42c558", + "spec/unit/facter/chocolateyversion_spec.rb": "9ae92a85ed91c5f08edc7b8c4e8e53ac", + "spec/unit/puppet/provider/chocolateyconfig/windows_spec.rb": "ad562ea5608d75115d33111aca94b524", + "spec/unit/puppet/provider/chocolateyfeature/windows_spec.rb": "1e5bbb2cafae10e6a57b4c02f223ba80", + "spec/unit/puppet/provider/chocolateysource/windows_spec.rb": "1ad0760ce83a9590de51866f9f1de3d3", + "spec/unit/puppet/provider/package/chocolatey_spec.rb": "f6fdd633b4765f8ff0e0bc74bcd09769", + "spec/unit/puppet/type/chocolateyconfig_spec.rb": "b97b3604c59f9f8d011c4cd67cff4260", + "spec/unit/puppet/type/chocolateyfeature_spec.rb": "a2bf2e2fb8a45f8eefa43a0f289b0e40", + "spec/unit/puppet/type/chocolateysource_spec.rb": "1a71f966fac89b623decd08a401f08c6", + "spec/unit/puppet_x/chocolatey/chocolatey_common_spec.rb": "cb9087f4aa76641719bb5454fb474aa3", + "spec/unit/puppet_x/chocolatey/chocolatey_install_spec.rb": "5af79f6838ea628b1f55afcce1020279", + "spec/unit/puppet_x/chocolatey/chocolatey_version_spec.rb": "3f8e5abf71112d84a5be8ad096aad6ca", + "templates/InstallChocolatey.ps1.erb": "2adb1ce976d25907164b15cf1f16fd02", + "tests/acceptance/pre-suite/00_pe_install.rb": "cfe3fa761b0560792eacb872442dc9c7", + "tests/acceptance/pre-suite/01_chocolatey_module.install.rb": "9d11cc217d7f53ddffa36de7610c09b7", + "tests/acceptance/pre-suite/02_chocolatey_application_install.rb": "15205c3858c4d0a9c098541d9e0a7191", + "tests/acceptance/tests/hello.rb": "44c8a17a9a8ace86055fca4cf66d5a90", + "tests/lib/chocolatey_helper.rb": "c12b7e4bb5f06046bffc1031a866dd6b", + "tests/reference/pre-suite/00_install_certs.rb": "0814e2c5639947378749d0001ada530a", + "tests/reference/pre-suite/01_puppet_agent_install.rb": "34107ab52e53672aebe2f11b0759d9d3", + "tests/reference/pre-suite/02_chocolatey_module_install.rb": "515a96abf6a9660a113bcee882c7dd9c", + "tests/reference/pre-suite/03_chocolatey_application_install.rb": "33e65471ef20e5a34fdad72142c4a6b0", + "tests/reference/tests/chocolateyconfig/add_new_config_item.rb": "ca7e6cb60da8f6e41d1bb039a0f08af3", + "tests/reference/tests/chocolateyconfig/add_value_to_existing_config.rb": "407e1ea27b86a7e255f60330e7d3410e", + "tests/reference/tests/chocolateyconfig/change_config_value.rb": "3e6184e3a44a5ef3e82ac88e4c2da54b", + "tests/reference/tests/chocolateyconfig/ensure_config_value_with_password_in_name.rb": "c1171b2d053318df65af8fa7641b6334", + "tests/reference/tests/chocolateyconfig/fail_to_appy_bad_manifest.rb": "cc4261382302a4b18cbceedcb6bccdb1", + "tests/reference/tests/chocolateyconfig/fail_to_set_present_without_value.rb": "eb9093717f14d2102140d9a995321e60", + "tests/reference/tests/chocolateyconfig/remove_config_value_with_password_in_name.rb": "123e9d59bd3e1e449d0e9ec2eaae1f86", + "tests/reference/tests/chocolateyconfig/remove_value_from_config.rb": "1d4f7f8dc78e728b1d582e29845bc9d7", + "tests/reference/tests/chocolateyfeature/disable_disabled_feature.rb": "b0e6527d227f49b1baf67082891ab43e", + "tests/reference/tests/chocolateyfeature/disable_enabled_feature.rb": "201db0be084202704ec41967eda28865", + "tests/reference/tests/chocolateyfeature/enable_disabled_feature.rb": "87a8704e1c5b70bca03f1d2a715198b4", + "tests/reference/tests/chocolateyfeature/enable_enabled_feature.rb": "eedaf5068e428db99e409a3f912cae97", + "tests/reference/tests/chocolateyfeature/fail_to_enable_nonexistent_feature.rb": "8000a68d7ccb62e5f6b472facb7065a1", + "tests/reference/tests/chocolateyfeature/fail_to_remove_feature.rb": "aea6bb681d46924fe98d34295cf07807", + "tests/reference/tests/chocolateypackage/install_and_remove_good_package.rb": "b1a25035d4dad0ac42caeb1becfd56f1", + "tests/reference/tests/chocolateypackage/install_and_remove_good_package_utf-8.rb": "ea75ffbe326df41a35e4731fe08a3b61", + "tests/reference/tests/chocolateysource/add_priority_to_existing_source.rb": "c6788dd1224006c819549de936076be2", + "tests/reference/tests/chocolateysource/add_source_all_options.rb": "47c6aa9fc3f062e3fdc638b001051636", + "tests/reference/tests/chocolateysource/add_source_minimal.rb": "bbc7ed0b2d3faaae707872d6d73fdd09", + "tests/reference/tests/chocolateysource/add_source_normal.rb": "29fbe2335387aa97d54e994dffe26cae", + "tests/reference/tests/chocolateysource/add_user_pass_to_existing_source.rb": "e2cbd76cc086b16d1fde5a85ac7c1fb7", + "tests/reference/tests/chocolateysource/change_existing_priority.rb": "81f5bfe7f7f2d42ce0907abbf9513185", + "tests/reference/tests/chocolateysource/change_existing_source_location.rb": "afdadbae4c3373620eef0d23ff001716", + "tests/reference/tests/chocolateysource/change_user_pass.rb": "6e6af759af2de6429cd49d9c19564934", + "tests/reference/tests/chocolateysource/disable_existing_source.rb": "bf860a4876de665781735f370d23aa6f", + "tests/reference/tests/chocolateysource/disable_existing_source_two_runs.rb": "2ecb9c4b684ab92ba2af5ea8bdc3323d", + "tests/reference/tests/chocolateysource/fail_to_apply_source_without_location.rb": "7ebcb851a3402b93b8ca99dce2afacb6", + "tests/reference/tests/chocolateysource/fail_to_appy_bad_manifest.rb": "c81e640adf6b408db72dd2216819bfe9", + "tests/reference/tests/chocolateysource/fail_to_set_password_without_user.rb": "c27cbaadb8f2df3edebf4beca8aca73c", + "tests/reference/tests/chocolateysource/fail_to_set_user_without_password.rb": "2abfeb800092c7217d7e36dcbab75d78", + "tests/reference/tests/chocolateysource/remove_existing_source.rb": "e5fa96e486e522300e03270caf3bc613", + "tests/reference/tests/chocolateysource/remove_priority_from_existing_source.rb": "d49e25470cf51d9bc69d8670c0b600ad", + "tests/reference/tests/chocolateysource/remove_user_pass_from_existing_source.rb": "87920f736ad9958ce152944629292ffc", + "tests/test_run_scripts/acceptance_tests.sh": "d7bdd1185f73fd28389a6d60da0f0d69", + "tests/test_run_scripts/reference_tests.sh": "22220232bde40afa6c90fcdfc46943e0" +} \ No newline at end of file diff --git a/modules/utilities/windows/repository_managers/chocolatey/chocolatey.pp b/modules/utilities/windows/repository_managers/chocolatey/chocolatey.pp new file mode 100644 index 000000000..0e42ca6db --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/chocolatey.pp @@ -0,0 +1 @@ +include chocolatey \ No newline at end of file diff --git a/modules/utilities/windows/repository_managers/chocolatey/examples/init.pp b/modules/utilities/windows/repository_managers/chocolatey/examples/init.pp new file mode 100644 index 000000000..8154edd19 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/examples/init.pp @@ -0,0 +1,23 @@ +# The baseline for module testing used by Puppet Labs is that each manifest +# should have a corresponding test manifest that declares that class or defined +# type. +# +# Tests are then run by using puppet apply --noop (to check for compilation errors +# and view a log of events) or by fully applying the test in a virtual environment +# (to compare the resulting system state to the desired state). +# +# Learn more about module testing here: http://docs.puppetlabs.com/guides/tests_smoke.html +# +# With symlinks on Windows, please run the following command an administrative command prompt (substituting the proper directories): + +package { $pkg: + ensure => 'latest', + provider => 'chocolatey', +} + +# mklink /D C:\ProgramData\PuppetLabs\puppet\etc\modules\chocolatey C:\code\puppetlabs\puppetlabs-chocolatey +# mklink /D C:\ProgramData\PuppetLabs\code\environments\production\modules\chocolatey C:\code\puppetlabs\puppetlabs-chocolatey + +chocolateysource { 'local': + location => 'c:\packages', +} diff --git a/modules/utilities/windows/repository_managers/chocolatey/lib/facter/choco_install_path.rb b/modules/utilities/windows/repository_managers/chocolatey/lib/facter/choco_install_path.rb new file mode 100644 index 000000000..3301fd0ba --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/lib/facter/choco_install_path.rb @@ -0,0 +1,9 @@ +require 'pathname' +require Pathname.new(__FILE__).dirname + '../' + 'puppet_x/chocolatey/chocolatey_install' + +Facter.add('choco_install_path') do + confine :osfamily => :windows + setcode do + PuppetX::Chocolatey::ChocolateyInstall.install_path || 'C:\ProgramData\chocolatey' + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/lib/facter/chocolateyversion.rb b/modules/utilities/windows/repository_managers/chocolatey/lib/facter/chocolateyversion.rb new file mode 100644 index 000000000..3d049c53b --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/lib/facter/chocolateyversion.rb @@ -0,0 +1,9 @@ +require 'pathname' +require Pathname.new(__FILE__).dirname + '../' + 'puppet_x/chocolatey/chocolatey_version' + +Facter.add('chocolateyversion') do + confine :osfamily => :windows + setcode do + PuppetX::Chocolatey::ChocolateyVersion.version || '0' + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/chocolateyconfig/windows.rb b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/chocolateyconfig/windows.rb new file mode 100644 index 000000000..69d3ffaa3 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/chocolateyconfig/windows.rb @@ -0,0 +1,144 @@ +require 'puppet/type' +require 'pathname' +require 'rexml/document' + +Puppet::Type.type(:chocolateyconfig).provide(:windows) do + confine :operatingsystem => :windows + defaultfor :operatingsystem => :windows + + require Pathname.new(__FILE__).dirname + '../../../' + 'puppet_x/chocolatey/chocolatey_common' + include PuppetX::Chocolatey::ChocolateyCommon + + CONFIG_MINIMUM_SUPPORTED_CHOCO_VERSION = '0.9.10.0' + + commands :chocolatey => PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command + + def initialize(value={}) + super(value) + @property_flush = {} + end + + def properties + if @property_hash.empty? + @property_hash = query || { :ensure => ( :absent )} + @property_hash[:ensure] = :absent if @property_hash.empty? + end + @property_hash.dup + end + + def query + self.class.configs.each do |config| + return config.properties if @resource[:name][/\A\S*/].downcase == config.name.downcase + end + + return {} + end + + def self.get_configs + PuppetX::Chocolatey::ChocolateyCommon.set_env_chocolateyinstall + + choco_config = PuppetX::Chocolatey::ChocolateyCommon.choco_config_file + raise Puppet::ResourceError, "Config file not found for Chocolatey. Please make sure you have Chocolatey installed." if choco_config.nil? + raise Puppet::ResourceError, "An install was detected, but was unable to locate config file at #{choco_config}." unless PuppetX::Chocolatey::ChocolateyCommon.file_exists?(choco_config) + + Puppet.debug("Gathering sources from '#{choco_config}'.") + config = REXML::Document.new File.new(choco_config, 'r') + + config.elements.to_a( '//add' ) + end + + def self.get_config(element) + config = {} + return config if element.nil? + + config[:name] = element.attributes['key'] if element.attributes['key'] + config[:value] = element.attributes['value'] if element.attributes['value'] + config[:description] = element.attributes['description'] if element.attributes['description'] + + config[:ensure] = :present + + Puppet.debug("Loaded config '#{config.inspect}'.") + + config + end + + def self.configs + @configs ||= get_configs.collect do |item| + config = get_config(item) + new(config) + end + end + + def self.refresh_configs + @configs = nil + self.configs + end + + def self.instances + configs + end + + def self.prefetch(resources) + instances.each do |provider| + if (resource = resources[provider.name]) + resource.provider = provider + end + end + end + + def create + @property_flush[:ensure] = :present + end + + def exists? + @property_hash[:ensure] == :present + end + + def destroy + @property_flush[:ensure] = :absent + end + + def validate + choco_version = Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version) + if PuppetX::Chocolatey::ChocolateyCommon.file_exists?(PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command) && choco_version < Gem::Version.new(CONFIG_MINIMUM_SUPPORTED_CHOCO_VERSION) + raise Puppet::ResourceError, "Chocolatey version must be '#{CONFIG_MINIMUM_SUPPORTED_CHOCO_VERSION}' to manage configuration values. Detected '#{choco_version}' as your version. Please upgrade Chocolatey." + end + end + + mk_resource_methods + + def flush + choco_version = Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version) + + args = [] + args << 'config' + + # look at the hash, then flush if present. + # If all else fails, looks at resource[:ensure] + property_ensure = @property_hash[:ensure] + property_ensure = @property_flush[:ensure] if @property_flush[:ensure] + property_ensure = resource[:ensure] if property_ensure.nil? + + command = 'set' + command = 'unset' if property_ensure == :absent + + args << command + args << '--name' << resource[:name] + + if property_ensure != :absent + args << '--value' << resource[:value] + end + + begin + Puppet::Util::Execution.execute([command(:chocolatey), *args]) + rescue Puppet::ExecutionFailure => e + raise Puppet::Error, "An error occurred running choco. Unable to set Chocolateyconfig[#{self.name}]: #{e}" + end + + @property_hash.clear + @property_flush.clear + + self.class.refresh_configs + @property_hash = query + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/chocolateyfeature/windows.rb b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/chocolateyfeature/windows.rb new file mode 100644 index 000000000..de0ccfd22 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/chocolateyfeature/windows.rb @@ -0,0 +1,126 @@ +require 'puppet/type' +require 'pathname' +require 'rexml/document' + +Puppet::Type.type(:chocolateyfeature).provide(:windows) do + confine :operatingsystem => :windows + defaultfor :operatingsystem => :windows + + require Pathname.new(__FILE__).dirname + '../../../' + 'puppet_x/chocolatey/chocolatey_common' + include PuppetX::Chocolatey::ChocolateyCommon + + FEATURE_MINIMUM_SUPPORTED_CHOCO_VERSION = '0.9.9.0' + + commands :chocolatey => PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command + + def initialize(value={}) + super(value) + @property_flush = {} + end + + def properties + if @property_hash.empty? + @property_hash = query + end + @property_hash.dup + end + + def query + self.class.features.each do |feature| + return feature.properties if @resource[:name][/\A\S*/].downcase == feature.name.downcase + end + + return {} + end + + def self.get_features + PuppetX::Chocolatey::ChocolateyCommon.set_env_chocolateyinstall + + choco_config = PuppetX::Chocolatey::ChocolateyCommon.choco_config_file + raise Puppet::ResourceError, "Config file not found for Chocolatey. Please make sure you have Chocolatey installed." if choco_config.nil? + raise Puppet::ResourceError, "An install was detected, but was unable to locate config file at #{choco_config}." unless PuppetX::Chocolatey::ChocolateyCommon.file_exists?(choco_config) + + Puppet.debug("Gathering features from '#{choco_config}'.") + config = REXML::Document.new File.new(choco_config, 'r') + + config.elements.to_a( '//feature' ) + end + + def self.get_feature(element) + feature = {} + return feature if element.nil? + + feature[:name] = element.attributes['name'].downcase if element.attributes['name'] + feature[:description] = element.attributes['description'].downcase if element.attributes['description'] + + enabled = false + enabled = element.attributes['enabled'].downcase == 'true' if element.attributes['enabled'] + + feature[:ensure] = :disabled + feature[:ensure] = :enabled if enabled + + Puppet.debug("Loaded feature '#{feature.inspect}'.") + + feature + end + + def self.features + get_features.collect do |item| + feature = get_feature(item) + new(feature) + end + end + + def self.instances + features + end + + def self.prefetch(resources) + instances.each do |provider| + if (resource = resources[provider.name]) + resource.provider = provider + end + end + end + + def enable + @property_flush[:ensure] = :enabled + end + + def exists? + @property_hash[:ensure] == :enabled + end + + def disable + @property_flush[:ensure] = :disabled + end + + def validate + choco_version = Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version) + if PuppetX::Chocolatey::ChocolateyCommon.file_exists?(PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command) && choco_version < Gem::Version.new(FEATURE_MINIMUM_SUPPORTED_CHOCO_VERSION) + raise Puppet::ResourceError, "Chocolatey version must be '#{FEATURE_MINIMUM_SUPPORTED_CHOCO_VERSION}' to manage configuration values with Puppet. Detected '#{choco_version}' as your version. Please upgrade Chocolatey to use this resource." + end + end + + mk_resource_methods + + def flush + args = [] + args << 'feature' + + command = 'enable' + command = 'disable' if @property_flush[:ensure] == :disabled + + args << command + args << '--name' << resource[:name] + + Puppet::Util::Execution.execute([command(:chocolatey), *args]) + + @property_hash.clear + @property_flush.clear + + self.class.features + @property_hash = query + end + +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/chocolateysource/windows.rb b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/chocolateysource/windows.rb new file mode 100644 index 000000000..784dfc511 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/chocolateysource/windows.rb @@ -0,0 +1,197 @@ +require 'puppet/type' +require 'pathname' +require 'rexml/document' + +Puppet::Type.type(:chocolateysource).provide(:windows) do + confine :operatingsystem => :windows + defaultfor :operatingsystem => :windows + + require Pathname.new(__FILE__).dirname + '../../../' + 'puppet_x/chocolatey/chocolatey_common' + include PuppetX::Chocolatey::ChocolateyCommon + + MINIMUM_SUPPORTED_CHOCO_VERSION = '0.9.9.0' + MINIMUM_SUPPORTED_CHOCO_VERSION_PRIORITY = '0.9.9.9' + + commands :chocolatey => PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command + + def initialize(value={}) + super(value) + @property_flush = {} + end + + def properties + if @property_hash.empty? + @property_hash = query || { :ensure => ( :absent )} + @property_hash[:ensure] = :absent if @property_hash.empty? + end + @property_hash.dup + end + + def query + self.class.sources.each do |source| + return source.properties if @resource[:name][/\A\S*/].downcase == source.name.downcase + end + + return {} + end + + def self.get_sources + PuppetX::Chocolatey::ChocolateyCommon.set_env_chocolateyinstall + + choco_config = PuppetX::Chocolatey::ChocolateyCommon.choco_config_file + raise Puppet::ResourceError, "Config file not found for Chocolatey. Please make sure you have Chocolatey installed." if choco_config.nil? + raise Puppet::ResourceError, "An install was detected, but was unable to locate config file at #{choco_config}." unless PuppetX::Chocolatey::ChocolateyCommon.file_exists?(choco_config) + + Puppet.debug("Gathering sources from '#{choco_config}'.") + config = REXML::Document.new File.new(choco_config, 'r') + + config.elements.to_a( '//source' ) + end + + def self.get_source(element) + source = {} + return source if element.nil? + + source[:name] = element.attributes['id'].downcase if element.attributes['id'] + source[:location] = element.attributes['value'].downcase if element.attributes['value'] + + disabled = false + disabled = element.attributes['disabled'].downcase == 'true' if element.attributes['disabled'] + source[:ensure] = :present + source[:ensure] = :disabled if disabled + + source[:priority] = 0 + source[:priority] = element.attributes['priority'].downcase if element.attributes['priority'] + + source[:user] = '' + source[:user] = element.attributes['user'].downcase if element.attributes['user'] + + Puppet.debug("Loaded source '#{source.inspect}'.") + + source + end + + def self.sources + @sources ||= get_sources.collect do |item| + source = get_source(item) + new(source) + end + end + + def self.refresh_sources + @sources = nil + self.sources + end + + def self.instances + sources + end + + def self.prefetch(resources) + instances.each do |provider| + if (resource = resources[provider.name]) + resource.provider = provider + end + end + end + + def create + @property_flush[:ensure] = :present + end + + def exists? + @property_hash[:ensure] == :present + end + + def disable + @property_flush[:ensure] = :disabled + end + + def destroy + @property_flush[:ensure] = :absent + end + + def validate + choco_version = Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version) + if PuppetX::Chocolatey::ChocolateyCommon.file_exists?(PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command) && choco_version < Gem::Version.new(MINIMUM_SUPPORTED_CHOCO_VERSION) + raise Puppet::ResourceError, "Chocolatey version must be '#{MINIMUM_SUPPORTED_CHOCO_VERSION}' to manage configuration values with Puppet. Detected '#{choco_version}' as your version. Please upgrade Chocolatey to use this resource." + end + + if choco_version < Gem::Version.new(MINIMUM_SUPPORTED_CHOCO_VERSION_PRIORITY) && resource[:priority] && resource[:priority] != 0 + Puppet.warning("Chocolatey is unable to manage priority for sources when version is less than #{MINIMUM_SUPPORTED_CHOCO_VERSION_PRIORITY}. The value you set will be ignored.") + end + + # location is always filled in with puppet resource, but + # resource[:location] is always empty (because it has a different + # code path where validation occurs before all properties/params + # have been set), resulting in errors + # location is always :absent when a manifest runs this with a missing + # `location => value` + location_check = location + # location could be :absent, which mk_resource_method will set it to + # resource[:location] is nil when running puppet resource + # if you remove `location => value` + location_check = resource[:location] if location_check == :absent + if (resource[:ensure] == :present && (location_check.nil? || location_check.strip == '')) + raise ArgumentError, "A non-empty location must be specified when ensure => present." + end + + if resource[:password] && resource[:password] != '' + Puppet.debug("The password is not ensurable, so Puppet is unable to change the value using chocolateysource resource. As a workaround, a password change can be in the form of an exec. Reference Chocolateysource[#{resource[:name]}]") + end + end + + mk_resource_methods + + def flush + args = [] + args << 'source' + + # look at the hash, then flush if present. + # If all else fails, looks at resource[:ensure] + property_ensure = @property_hash[:ensure] + property_ensure = @property_flush[:ensure] if @property_flush[:ensure] + property_ensure = resource[:ensure] if property_ensure.nil? + + command = 'add' + command = 'remove' if property_ensure == :absent + command = 'disable' if property_ensure == :disabled + + args << command + args << '--name' << resource[:name] + + if command == 'add' + args << '--source' << resource[:location] + + if resource[:user] && resource[:user] != '' + args << '--user' << resource[:user] + args << '--password' << resource[:password] + end + + choco_gem_version = Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version) + if choco_gem_version >= Gem::Version.new(MINIMUM_SUPPORTED_CHOCO_VERSION_PRIORITY) + args << '--priority' << resource[:priority] + end + end + + begin + Puppet::Util::Execution.execute([command(:chocolatey), *args]) + rescue Puppet::ExecutionFailure + raise Puppet::Error, "An error occurred running choco. Unable to set Chocolatey source configuration for #{self.inspect}" + end + + if property_ensure == :present + begin + Puppet::Util::Execution.execute([command(:chocolatey), 'source', 'enable', '--name', resource[:name]]) + rescue Puppet::ExecutionFailure + raise Puppet::Error, "An error occurred running choco. Unable to set Chocolatey source configuration for #{self.inspect}" + end + end + + @property_hash.clear + @property_flush.clear + + self.class.refresh_sources + @property_hash = query + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/package/chocolatey.rb b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/package/chocolatey.rb new file mode 100644 index 000000000..d01ad0d5a --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/provider/package/chocolatey.rb @@ -0,0 +1,280 @@ +require 'puppet/provider/package' +require 'pathname' +require Pathname.new(__FILE__).dirname + '../../../' + 'puppet_x/chocolatey/chocolatey_install' + +Puppet::Type.type(:package).provide(:chocolatey, :parent => Puppet::Provider::Package) do + + desc "Manages packages using Chocolatey (Windows package manager). + + The syntax for Chocolatey using the puppet provider is a much + closer match to *nix package managers, bringing a more agnostic + approach to package management across platforms. Chocolatey packages + usually contain all of the logic to install software silently on a + Windows machine, much like RPM (yum) or DPKG (apt). + + Installs can be as simple as + + package {'git': + ensure => latest, + } + + See the ReadMe for more information." + + confine :operatingsystem => :windows + has_feature :installable + has_feature :uninstallable + has_feature :upgradeable + has_feature :versionable + has_feature :install_options + has_feature :uninstall_options + has_feature :holdable + #has_feature :package_settings + + require Pathname.new(__FILE__).dirname + '../../../' + 'puppet_x/chocolatey/chocolatey_common' + include PuppetX::Chocolatey::ChocolateyCommon + + commands :chocolatey => PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command + + def initialize(value={}) + super(value) + end + + def print() + notice("The value is: '${name}'") + end + + def self.is_compiled_choco? + Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version) >= Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon::FIRST_COMPILED_CHOCO_VERSION) + end + + def is_compiled_choco? + self.class.is_compiled_choco? + end + + def install + PuppetX::Chocolatey::ChocolateyCommon.set_env_chocolateyinstall + choco_exe = is_compiled_choco? + + # always unhold on install + unhold if choco_exe + + args = [] + + # also will need to address -sidebyside or -m in the install args to allow + # multiple versions to be installed. + args << 'install' + + should = @resource.should(:ensure) + case should + when true, false, Symbol + args << @resource[:name][/\A\S*/] + else + args.clear + if choco_exe + args << 'upgrade' + else + args << 'update' + end + + # Add the package version + args << @resource[:name][/\A\S*/] << '-version' << @resource[:ensure] + end + + if choco_exe + args << '-y' + end + + if @resource[:source] + args << '-source' << @resource[:source] + end + + args << @resource[:install_options] + + if Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version) >= Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon::MINIMUM_SUPPORTED_CHOCO_VERSION_EXIT_CODES) + args << '--ignore-package-exit-codes' + end + + chocolatey(*args) + end + + def uninstall + PuppetX::Chocolatey::ChocolateyCommon.set_env_chocolateyinstall + choco_exe = is_compiled_choco? + + # always unhold on uninstall + unhold if choco_exe + + args = 'uninstall', @resource[:name][/\A\S*/] + + if choco_exe + args << '-fy' + end + + choco_version = Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version) + if !choco_exe || choco_version >= Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon::MINIMUM_SUPPORTED_CHOCO_UNINSTALL_SOURCE) + if @resource[:source] + args << '-source' << @resource[:source] + end + end + + args << @resource[:uninstall_options] + + if Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version) >= Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon::MINIMUM_SUPPORTED_CHOCO_VERSION_EXIT_CODES) + args << '--ignore-package-exit-codes' + end + + chocolatey(*args) + end + + def update + PuppetX::Chocolatey::ChocolateyCommon.set_env_chocolateyinstall + choco_exe = is_compiled_choco? + + # always unhold on upgrade + unhold if choco_exe + + if choco_exe + args = 'upgrade', @resource[:name][/\A\S*/], '-y' + else + args = 'update', @resource[:name][/\A\S*/] + end + + if @resource[:source] + args << '-source' << @resource[:source] + end + + args << @resource[:install_options] + + if Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version) >= Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon::MINIMUM_SUPPORTED_CHOCO_VERSION_EXIT_CODES) + args << '--ignore-package-exit-codes' + end + + if self.query + chocolatey(*args) + else + self.install + end + end + + # from puppet-dev mailing list + # Puppet will call the query method on the instance of the package + # provider resource when checking if the package is installed already or + # not. + # It's a determination for one specific package, the package modeled by + # the resource the method is called on. + # Query provides the information for the single package identified by @Resource[:name]. + def query + self.class.instances.each do |package| + return package.properties if @resource[:name][/\A\S*/].downcase == package.name.downcase + end + + return nil + end + + def self.listcmd + args = [] + args << 'list' + args << '-lo' + if is_compiled_choco? + args << '-r' + end + + [command(:chocolatey), *args] + end + + def self.instances + packages = [] + PuppetX::Chocolatey::ChocolateyCommon.set_env_chocolateyinstall + choco_exe = is_compiled_choco? + begin + pins = [] + pin_output = nil unless choco_exe + #don't add -r yet, as there is an issue in 0.9.9.9/0.9.9.10 that returns full list plus pins + pin_output = Puppet::Util::Execution.execute([command(:chocolatey), 'pin', 'list']) if choco_exe + unless pin_output.nil? + pin_output.split("\n").each { |pin| pins << pin.split('|')[0] } + end + + execpipe(listcmd) do |process| + process.each_line do |line| + line.chomp! + if line.empty? or line.match(/Reading environment variables.*/); next; end + raise Puppet::Error, "At least one source must be enabled." if line.match(/Unable to search for packages.*/) + if choco_exe + values = line.split('|') + else + values = line.split(' ') + end + values[1] = :held if pins.include? values[0] + packages << new({ :name => values[0].downcase, :ensure => values[1], :provider => self.name }) + end + end + rescue Puppet::ExecutionFailure + return nil + end + + packages + end + + def latestcmd + choco_exe = is_compiled_choco? + if choco_exe + args = 'upgrade', '--noop', @resource[:name][/\A\S*/], '-r' + else + args = 'version', @resource[:name][/\A\S*/] + end + + if @resource[:source] + args << '-source' << @resource[:source] + end + + unless choco_exe + args << '| findstr /R "latest" | findstr /V "latestCompare"' + end + + [command(:chocolatey), *args] + end + + def latest + package_ver = '' + PuppetX::Chocolatey::ChocolateyCommon.set_env_chocolateyinstall + begin + execpipe(latestcmd) do |process| + process.each_line do |line| + line.chomp! + if line.empty?; next; end + if is_compiled_choco? + values = line.split('|') + package_ver = values[2] + else + # Example: ( latest : 2013.08.19.155043 ) + values = line.split(':').collect(&:strip).delete_if(&:empty?) + package_ver = values[1] + end + end + end + rescue Puppet::ExecutionFailure + return nil + end + + package_ver + end + + def hold + raise ArgumentError, 'Only choco v0.9.9+ can use ensure => held' unless is_compiled_choco? + + install + + args = 'pin', 'add', '-n', @resource[:name][/\A\S*/] + + chocolatey(*args) + end + + def unhold + return unless is_compiled_choco? + + Puppet::Util::Execution.execute([command(:chocolatey), 'pin','remove', '-n', @resource[:name][/\A\S*/]], :failonfail => false) + end + + +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/type/chocolateyconfig.rb b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/type/chocolateyconfig.rb new file mode 100644 index 000000000..ba4d4a65a --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/type/chocolateyconfig.rb @@ -0,0 +1,85 @@ +require 'puppet/type' +require 'pathname' + +Puppet::Type.newtype(:chocolateyconfig) do + + @doc = <<-'EOT' + Allows managing config settings for Chocolatey. + Configuration values provide settings for users + to configure aspects of Chocolatey and the way it + functions. Similar to features, except allow for user + configured values. Requires 0.9.10+. Learn more about + config at https://chocolatey.org/docs/commands-config + EOT + + ensurable do + newvalue(:present) { provider.create } + newvalue(:absent) { provider.destroy } + defaultto :present + + def retrieve + provider.properties[:ensure] + end + + end + + newparam(:name) do + desc "The name of the config setting. Used for uniqueness. + Puppet is not able to easily manage any values that + include Password in the key name in them as they + will be encrypted in the configuration file." + + validate do |value| + if value.nil? or value.empty? + raise ArgumentError, "A non-empty name must be specified." + end + end + + isnamevar + + munge do |value| + value.downcase + end + + def insync?(is) + is.downcase == should.downcase + end + end + + newproperty(:value) do + desc "The value of the config setting. If the + name includes 'password', then the value is + not ensurable due to being encrypted in the + configuration file." + + validate do |value| + if value.nil? or value.empty? + raise ArgumentError, "A non-empty value must be specified. To unset value, use ensure => absent" + end + end + + def insync?(is) + if (resource[:name] =~ /password/i) + # If name contains password, it is + # always in sync if there is a value + return (is.nil? || is.empty?) == (should.nil? || should.empty?) + else + return is.downcase == should.downcase + end + end + end + + validate do + if self[:ensure] != :absent + raise ArgumentError, "Unless ensure => absent, value is required." if self[:value].nil? || self[:value].empty? + end + + if provider.respond_to?(:validate) + provider.validate + end + end + + autorequire(:exec) do + ['install_chocolatey_official'] + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/type/chocolateyfeature.rb b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/type/chocolateyfeature.rb new file mode 100644 index 000000000..da5ebcc7f --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/type/chocolateyfeature.rb @@ -0,0 +1,57 @@ +require 'puppet/type' +require 'pathname' + +Puppet::Type.newtype(:chocolateyfeature) do + + @doc = <<-'EOT' + Allows managing features for Chocolatey. Features are + configuration that act as feature flippers to turn on or + off certain aspects of how Chocolatey works. + Learn more about features at + https://chocolatey.org/docs/commands-feature + + EOT + + newparam(:name) do + desc "The name of the feature. Used for uniqueness." + + validate do |value| + if value.nil? or value.empty? + raise ArgumentError, "A non-empty name must be specified." + end + end + + isnamevar + + munge do |value| + value.downcase + end + + def insync?(is) + is.downcase == should.downcase + end + end + + ensurable do + newvalue(:enabled) { provider.enable } + newvalue(:disabled) { provider.disable } + + def retrieve + provider.properties[:ensure] + end + end + + validate do + if self[:ensure].nil? && provider.properties[:ensure].nil? + raise ArgumentError, "Invalid value for ensure. Valid values are enabled or disabled." + end + + if provider.respond_to?(:validate) + provider.validate + end + end + + autorequire(:exec) do + ['install_chocolatey_official'] + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/type/chocolateysource.rb b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/type/chocolateysource.rb new file mode 100644 index 000000000..fcd4531b9 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet/type/chocolateysource.rb @@ -0,0 +1,141 @@ +require 'puppet/type' +require 'pathname' + +Puppet::Type.newtype(:chocolateysource) do + + @doc = <<-'EOT' + Allows managing sources for Chocolatey. A source can be a + folder, a CIFS share, a NuGet Http OData feed, or a full + Package Gallery. Learn more about sources at + https://chocolatey.org/docs/how-to-host-feed + + EOT + + ensurable do + newvalue(:present) { provider.create } + newvalue(:disabled) { provider.disable } + newvalue(:absent) { provider.destroy } + defaultto :present + + def retrieve + provider.properties[:ensure] + end + + end + + newparam(:name) do + desc "The name of the source. Used for uniqueness." + + validate do |value| + if value.nil? or value.empty? + raise ArgumentError, "A non-empty name must be specified." + end + end + + isnamevar + + munge do |value| + value.downcase + end + + def insync?(is) + is.downcase == should.downcase + end + end + + newproperty(:location) do + desc "The location of the source repository. Can be a url pointing to + an OData feed (like chocolatey/chocolatey_server), a CIFS (UNC) share, + or a local folder. Required when `ensure => present` (the default for + `ensure`)." + + validate do |value| + if value.nil? or value.empty? + raise ArgumentError, "A non-empty location must be specified." + end + end + + def insync?(is) + is.downcase == should.downcase + end + end + + newproperty(:user) do + desc "Optional user name for authenticated feeds. + Requires at least Chocolatey v0.9.9.0. + Defaults to `nil`. Specifying an empty value is the + same as setting the value to nil or not specifying + the property at all." + + def insync?(is) + is.downcase == should.downcase + end + + defaultto '' + end + + newparam(:password) do + desc "Optional user password for authenticated feeds. + Not ensurable. Value is not able to be checked + with current value. If you need to update the password, + update another setting as well. + Requires at least Chocolatey v0.9.9.0. + Defaults to `nil`. Specifying an empty value is the + same as setting the value to nil or not specifying + the property at all." + + defaultto '' + end + + newproperty(:priority) do + desc "Optional priority for explicit feed order when + searching for packages across multiple feeds. + The lower the number the higher the priority. + Sources with a 0 priority are considered no priority + and are added after other sources with a priority + number. + Requires at least Chocolatey v0.9.9.9. + Defaults to 0." + + validate do |value| + if value.nil? + raise ArgumentError, "A non-empty priority must be specified." + end + raise ArgumentError, "An integer is necessary for priority. Specify 0 or remove for no priority." unless resource.is_numeric?(value) + end + + defaultto(0) + end + + validate do + if (!self[:user].nil? && self[:user].strip != '' && (self[:password].nil? || self[:password] == '')) || ((self[:user].nil? || self[:user].strip == '') && !self[:password].nil? && self[:password] != '') + raise ArgumentError, "If specifying user/password, you must specify both values." + end + + if provider.respond_to?(:validate) + provider.validate + end + end + + autorequire(:exec) do + ['install_chocolatey_official'] + end + + def munge_boolean(value) + case value + when true, "true", :true + :true + when false, "false", :false + :false + else + fail("munge_boolean only takes booleans") + end + end + + def is_numeric?(value) + # this is what stdlib does. Not sure if we want to emulate or not. + #numeric = %r{^-?(?:(?:[1-9]\d*)|0)$} + #if value.is_a? Integer or (value.is_a? String and value.match numeric) + Float(value) != nil rescue false + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/lib/puppet_x/chocolatey/chocolatey_common.rb b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet_x/chocolatey/chocolatey_common.rb new file mode 100644 index 000000000..ebebceee2 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet_x/chocolatey/chocolatey_common.rb @@ -0,0 +1,90 @@ +require 'pathname' +require Pathname.new(__FILE__).dirname + 'chocolatey_version' +require Pathname.new(__FILE__).dirname + 'chocolatey_install' + +module PuppetX + module Chocolatey + module ChocolateyCommon + + ## determines if C# version of choco + FIRST_COMPILED_CHOCO_VERSION = '0.9.9.0' + MINIMUM_SUPPORTED_CHOCO_VERSION_EXIT_CODES = '0.9.10.0' + MINIMUM_SUPPORTED_CHOCO_UNINSTALL_SOURCE = '0.9.10.0' + + def file_exists?(path) + File.exist?(path) + end + module_function :file_exists? + + def chocolatey_command + if Puppet::Util::Platform.windows? + # When attempting to find the choco command executable, the following + # paths are checked: + # - Start with the install_path. If choco is found with environment + # variables through the registry or a check on the + # ChocolateyInstall env var (first install of Choco may only have + # this), then use that path. + # - Next look to the most commonly used install location (ProgramData) + # - Fall back to the older install location for older installations + # - If all else fails, attempt to find Chocolatey in the default place + # it installs + chocoInstallPath = PuppetX::Chocolatey::ChocolateyInstall.install_path + + chocopath = (chocoInstallPath if (chocoInstallPath && file_exists?("#{chocoInstallPath}\\bin\\choco.exe"))) || + ('C:\ProgramData\chocolatey' if file_exists?('C:\ProgramData\chocolatey\bin\choco.exe')) || + ('C:\Chocolatey' if file_exists?('C:\Chocolatey\bin\choco.exe')) || + "#{ENV['ALLUSERSPROFILE']}\\chocolatey" + + chocopath += '\bin\choco.exe' + else + chocopath = 'choco.exe' + end + + chocopath + end + module_function :chocolatey_command + + def set_env_chocolateyinstall + ENV['ChocolateyInstall'] = PuppetX::Chocolatey::ChocolateyInstall.install_path + end + module_function :set_env_chocolateyinstall + + def choco_version + @chocoversion ||= self.strip_beta_from_version(PuppetX::Chocolatey::ChocolateyVersion.version) + end + module_function :choco_version + + def self.strip_beta_from_version(value) + return nil if value.nil? + + value.split(/-/)[0] + end + + def choco_config_file + chocoInstallPath = PuppetX::Chocolatey::ChocolateyInstall.install_path + choco_config = "#{chocoInstallPath}\\config\\chocolatey.config" + + # choco may be installed, but a config file doesn't exist until the + # first run of choco - trigger that by checking the version + choco_run_ensure_config = choco_version + + return choco_config if file_exists?(choco_config) + + old_choco_config = "#{chocoInstallPath}\\chocolateyinstall\\chocolatey.config" + + return old_choco_config if file_exists?(old_choco_config) + + return nil + end + module_function :choco_config_file + + # clears the cached values + def clear_cached_values + @chocoversion = nil + @compiled_choco = nil + end + module_function :clear_cached_values + + end + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/lib/puppet_x/chocolatey/chocolatey_install.rb b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet_x/chocolatey/chocolatey_install.rb new file mode 100644 index 000000000..66c835af1 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet_x/chocolatey/chocolatey_install.rb @@ -0,0 +1,34 @@ +module PuppetX + module Chocolatey + class ChocolateyInstall + + def self.install_path + value = nil + + if Puppet::Util::Platform.windows? + require 'win32/registry' + + begin + hive = Win32::Registry::HKEY_LOCAL_MACHINE + hive.open('SYSTEM\CurrentControlSet\Control\Session Manager\Environment', Win32::Registry::KEY_READ | 0x100) do |reg| + value = reg['ChocolateyInstall'] + end + rescue Win32::Registry::Error => e + value = nil + end + end + + # If machine level is not set, use process or user as the intended + # location where Chocolatey would be installed. + # Since it is technically possible that Chocolatey could exist on + # non-Windows installations, we don't want to confine this + # to just Windows. + if value.nil? + value = ENV['ChocolateyInstall'] + end + + value + end + end + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/lib/puppet_x/chocolatey/chocolatey_version.rb b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet_x/chocolatey/chocolatey_version.rb new file mode 100644 index 000000000..5e3478484 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/lib/puppet_x/chocolatey/chocolatey_version.rb @@ -0,0 +1,32 @@ +require 'pathname' +require Pathname.new(__FILE__).dirname + 'chocolatey_install' + +module PuppetX + module Chocolatey + class ChocolateyVersion + + OLD_CHOCO_MESSAGE = "Please run chocolatey /? or chocolatey help - chocolatey v" + + def self.version + version = nil + choco_path = "#{PuppetX::Chocolatey::ChocolateyInstall.install_path}\\bin\\choco.exe" + if Puppet::Util::Platform.windows? && File.exist?(choco_path) + begin + # call `choco -v` + # - new choco will output a single value e.g. `0.9.9` + # - old choco is going to return the default output e.g. `Please run chocolatey /?` + version = Puppet::Util::Execution.execute("#{choco_path} -v").gsub(OLD_CHOCO_MESSAGE,'') + # - other messages, such as upgrade warnings or warnings about + # installing the licensed extension once the license is installed + # may show up when running this comamnd. Remove those as well + version = version.split(/\r\n|\n|\r/).last.strip unless version.nil? + rescue StandardError => e + version = '0' + end + end + + version + end + end + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/manifests/config.pp b/modules/utilities/windows/repository_managers/chocolatey/manifests/config.pp new file mode 100644 index 000000000..bd51307bc --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/manifests/config.pp @@ -0,0 +1,34 @@ +# chocolatey::config - Private class used for configuration +class chocolatey::config { + assert_private() + + # this will require a second converge when choco is not + # installed the first time through. This is on purpose + # as we don't want to try to set these values for a + # version less than 0.9.9 and we don't know what the + # user may link to - it could be an older version of + # Chocolatey + + $_choco_version = $chocolatey::chocolatey_version ? { + undef => '0', + default => $chocolatey::chocolatey_version + } + +# lint:ignore:80chars + if versioncmp($_choco_version, '0.9.9.0') >= 0 and versioncmp($_choco_version, '0.9.10.0') < 0 { + $_choco_exe_path = "${chocolatey::choco_install_location}\\bin\\choco.exe" + + $_enable_autouninstaller = $chocolatey::enable_autouninstaller ? { + false => 'disable', + default => 'enable' + } + + exec { "chocolatey_autouninstaller_${_enable_autouninstaller}": + path => $::path, + command => "${_choco_exe_path} feature -r ${_enable_autouninstaller} -n autoUninstaller", + unless => "cmd.exe /c ${_choco_exe_path} feature list -r | findstr /B /I /C:\"autoUninstaller - [${_enable_autouninstaller}d]\"", + environment => ["ChocolateyInstall=${::chocolatey::choco_install_location}"] + } + } +# lint:endignore +} diff --git a/modules/utilities/windows/repository_managers/chocolatey/manifests/init.pp b/modules/utilities/windows/repository_managers/chocolatey/manifests/init.pp new file mode 100644 index 000000000..d2729dc12 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/manifests/init.pp @@ -0,0 +1,104 @@ +# chocolatey - Used for managing installation and configuration +# of Chocolatey itself. +# +# @author Rob Reynolds, Rich Siegel, and puppet-chocolatey contributors +# +# @example Default - This will by default ensure Chocolatey is installed and ready for use. +# include chocolatey +# +# @example Override default install location +# class {'chocolatey': +# choco_install_location => 'D:\secured\choco', +# } +# +# @example Use an internal Chocolatey.nupkg for installation +# class {'chocolatey': +# chocolatey_download_url => 'https://internalurl/to/chocolatey.nupkg', +# use_7zip => false, +# choco_install_timeout_seconds => 2700, +# } +# +# @example Use a file chocolatey.0.9.9.9.nupkg for installation +# class {'chocolatey': +# chocolatey_download_url => 'file:///c:/location/of/chocolatey.0.9.9.9.nupkg', +# use_7zip => false, +# choco_install_timeout_seconds => 2700, +# } +# +# @example Log chocolatey bootstrap installer script output +# class {'chocolatey': +# log_output => true, +# } +# +# @example Disable autouninstaller (use when less than 0.9.9.8) +# class {'chocolatey': +# enable_autouninstaller => false, +# } +# +# @param [String] choco_install_location Where Chocolatey install should be +# located. This needs to be an absolute path starting with a drive letter +# e.g. `c:\`. Defaults to the currently detected install location based on +# the `ChocolateyInstall` environment variable, falls back to +# `'C:\ProgramData\chocolatey'`. +# @param [Boolean] use_7zip Whether to use built-in shell or allow installer +# to download 7zip to extract `chocolatey.nupkg` during installation. +# Defaults to `false`. +# @param [Integer] choco_install_timeout_seconds How long in seconds should +# be allowed for the install of Chocolatey (including .NET Framework 4 if +# necessary). Defaults to `1500` (25 minutes). +# @param [String] chocolatey_download_url A url that will return +# `chocolatey.nupkg`. This must be a url, but not necessarily an OData feed. +# Any old url location will work. Defaults to +# `'https://chocolatey.org/api/v2/package/chocolatey/'`. +# @param [Boolean] enable_autouninstaller [Deprecated] - Should auto +# uninstaller be turned on? Auto uninstaller is what allows Chocolatey to +# automatically manage the uninstall of software from Programs and Features +# without necessarily requiring a `chocolateyUninstall.ps1` file in the +# package. Defaults to `true`. Setting is ignored in Chocolatey v0.9.10+. +# @param [Boolean] log_output Log output from the installer. Defaults to +# `false`. +# @param [String] chocolatey_version chocolatey version, falls back to +# `$::chocolateyversion`. +class chocolatey ( + $choco_install_location = $::chocolatey::params::install_location, + $use_7zip = $::chocolatey::params::use_7zip, + $choco_install_timeout_seconds = $::chocolatey::params::install_timeout_seconds, + $chocolatey_download_url = $::chocolatey::params::download_url, + $enable_autouninstaller = $::chocolatey::params::enable_autouninstaller, + $log_output = false, + $chocolatey_version = $::chocolatey::params::chocolatey_version +) inherits ::chocolatey::params { + + +validate_string($choco_install_location) +# lint:ignore:140chars +validate_re($choco_install_location, '^\w\:', +"Please use a full path for choco_install_location starting with a local drive. Reference choco_install_location => '${choco_install_location}'." +) +# lint:endignore + + validate_bool($use_7zip) + validate_integer($choco_install_timeout_seconds) + + validate_string($chocolatey_download_url) +# lint:ignore:140chars + validate_re($chocolatey_download_url,['^http\:\/\/','^https\:\/\/','file\:\/\/\/'], + "For chocolatey_download_url, if not using the default '${::chocolatey::params::download_url}', please use a Http/Https/File Url that downloads 'chocolatey.nupkg'." + ) +# lint:endignore + + validate_bool($enable_autouninstaller) + + if ((versioncmp($::clientversion, '3.4.0') >= 0) and (!defined('$::serverversion') or versioncmp($::serverversion, '3.4.0') >= 0)) { + class { '::chocolatey::install': } -> + class { '::chocolatey::config': } + + contain '::chocolatey::install' + contain '::chocolatey::config' + } else { + anchor {'before_chocolatey':} -> + class { '::chocolatey::install': } -> + class { '::chocolatey::config': } -> + anchor {'after_chocolatey':} + } +} diff --git a/modules/utilities/windows/repository_managers/chocolatey/manifests/install.pp b/modules/utilities/windows/repository_managers/chocolatey/manifests/install.pp new file mode 100644 index 000000000..4a7fb9c76 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/manifests/install.pp @@ -0,0 +1,27 @@ +# chocolatey::install - Private class used for install of Chocolatey +class chocolatey::install { + assert_private() + + $download_url = $::chocolatey::chocolatey_download_url + $unzip_type = $::chocolatey::use_7zip ? { + true => '7zip', + default => 'windows' + } + + registry_value { 'ChocolateyInstall environment value': + ensure => present, + path => 'HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\ChocolateyInstall', + type => 'string', + data => $chocolatey::choco_install_location, + } + + exec { 'install_chocolatey_official': + command => template('chocolatey/InstallChocolatey.ps1.erb'), + creates => "${::chocolatey::choco_install_location}\\bin\\choco.exe", + provider => powershell, + timeout => $::chocolatey::choco_install_timeout_seconds, + logoutput => $::chocolatey::log_output, + environment => ["ChocolateyInstall=${::chocolatey::choco_install_location}"], + require => Registry_value['ChocolateyInstall environment value'], + } +} diff --git a/modules/utilities/windows/repository_managers/chocolatey/manifests/params.pp b/modules/utilities/windows/repository_managers/chocolatey/manifests/params.pp new file mode 100644 index 000000000..5d6f91be8 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/manifests/params.pp @@ -0,0 +1,9 @@ +# chocolatey::params - Default parameters +class chocolatey::params { + $install_location = $::choco_install_path # default is C:\ProgramData\chocolatey + $download_url = 'https://chocolatey.org/api/v2/package/chocolatey/' + $use_7zip = false + $install_timeout_seconds = 1500 + $enable_autouninstaller = true + $chocolatey_version = $::chocolateyversion +} diff --git a/modules/utilities/windows/repository_managers/chocolatey/metadata.json b/modules/utilities/windows/repository_managers/chocolatey/metadata.json new file mode 100644 index 000000000..5701a6278 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/metadata.json @@ -0,0 +1,53 @@ +{ + "name": "puppetlabs-chocolatey", + "version": "2.0.1", + "author": "Puppet Inc", + "summary": "Chocolatey package provider for Puppet", + "license": "Apache-2.0", + "source": "https://github.com/puppetlabs/puppetlabs-chocolatey", + "project_page": "https://github.com/puppetlabs/puppetlabs-chocolatey", + "issues_url": "https://tickets.puppet.com/browse/MODULES", + "dependencies": [ + {"name":"puppetlabs/stdlib","version_requirement":">= 4.6.0 < 5.0.0"}, + {"name":"puppetlabs/powershell","version_requirement":">= 1.0.1 < 3.0.0"}, + {"name":"puppetlabs/registry","version_requirement":">= 1.0.0 < 3.0.0"} + ], + "data_provider": null, + "description": "Chocolatey package provider for Puppet", + "tags": [ + "microsoft", + "powershell", + ".NET Framework", + ".Net", + "dot_net", + "chocolatey", + "package", + "package manager", + "chocolatey for business", + "chocolatey professional" + ], + "requirements": [ + { + "name": "pe", + "version_requirement": ">= 3.0.0 < 2016.4.0" + }, + { + "name": "puppet", + "version_requirement": ">= 3.0.0 < 5.0.0" + } + ], + "operatingsystem_support": [ + { + "operatingsystem": "Windows", + "operatingsystemrelease": [ + "Server 2008", + "Server 2008 R2", + "Server 2012", + "Server 2012 R2", + "7", + "8.1", + "10" + ] + } + ] +} diff --git a/modules/utilities/windows/repository_managers/chocolatey/secgen_metadata.xml b/modules/utilities/windows/repository_managers/chocolatey/secgen_metadata.xml new file mode 100644 index 000000000..7484a39c0 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/secgen_metadata.xml @@ -0,0 +1,17 @@ + + + + Chocolatey install + Jason Keighley + Apache v2 + A Chocolatey installation + + repository_managers + windows + + + + + \ No newline at end of file diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/classes/config_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/classes/config_spec.rb new file mode 100644 index 000000000..e85f69b07 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/classes/config_spec.rb @@ -0,0 +1,77 @@ +require 'spec_helper' + +RSpec.describe 'chocolatey' do + context 'contains config.pp' do + context 'with older choco installed' do + let(:facts) { + { + :chocolateyversion => '0.9.8.33', + :choco_install_path => 'C:\ProgramData\chocolatey', + } + } + + [true, false].each do |param_value| + feature_enable = 'enable' + feature_enable = 'disable' if !param_value + + context "enable_autouninstaller => #{param_value}" do + let(:params) {{ :enable_autouninstaller => param_value }} + + it { is_expected.not_to contain_exec("chocolatey_autouninstaller_#{feature_enable}") } + + it { + is_expected.not_to contain_exec("chocolatey_autouninstaller_#{feature_enable}").with_command("C:\\ProgramData\\chocolatey\\bin\\choco.exe feature -r #{feature_enable} -n autoUninstaller") + } + end + end + end + + context 'without choco installed' do + let(:facts) { + { + :chocolateyversion => '0', + :choco_install_path => 'C:\ProgramData\chocolatey', + } + } + + [true, false].each do |param_value| + feature_enable = 'enable' + feature_enable = 'disable' if !param_value + + context "enable_autouninstaller => #{param_value}" do + let(:params) {{ :enable_autouninstaller => param_value }} + + it { is_expected.not_to contain_exec("chocolatey_autouninstaller_#{feature_enable}") } + + it { + is_expected.not_to contain_exec("chocolatey_autouninstaller_#{feature_enable}").with_command("C:\\ProgramData\\chocolatey\\bin\\choco.exe feature -r #{feature_enable} -n autoUninstaller") + } + end + end + end + + context 'with choco.exe installed' do + let(:facts) { + { + :chocolateyversion => '0.9.9.8', + :choco_install_path => 'C:\ProgramData\chocolatey', + } + } + + [true, false].each do |param_value| + feature_enable = 'enable' + feature_enable = 'disable' if !param_value + + context "enable_autouninstaller => #{param_value}" do + let(:params) {{ :enable_autouninstaller => param_value }} + + it { is_expected.to contain_exec("chocolatey_autouninstaller_#{feature_enable}") } + + it { + is_expected.to contain_exec("chocolatey_autouninstaller_#{feature_enable}").with_command("C:\\ProgramData\\chocolatey\\bin\\choco.exe feature -r #{feature_enable} -n autoUninstaller") + } + end + end + end + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/classes/coverage_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/classes/coverage_spec.rb new file mode 100644 index 000000000..12513b83c --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/classes/coverage_spec.rb @@ -0,0 +1 @@ +at_exit { RSpec::Puppet::Coverage.report! } diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/classes/init_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/classes/init_spec.rb new file mode 100644 index 000000000..180903928 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/classes/init_spec.rb @@ -0,0 +1,200 @@ +require 'spec_helper' + +describe 'chocolatey' do + let(:facts) { + { + :chocolateyversion => '0.9.9.8', + :choco_install_path => 'C:\ProgramData\chocolatey', + } + } + + [{}].each do |params| + context "#{params}" do + let(:params) { params } + + it 'should compile successfully' do + catalogue + end + + #it { is_expected.to compile } + #it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_class('chocolatey') } + it { is_expected.to contain_class('chocolatey::params') } + it { is_expected.to contain_class('chocolatey::install') } + it { is_expected.to contain_class('chocolatey::config') } + end + end + + context "chocolatey_download_url =>" do + ['https://chocolatey.org/api/v2/package/chocolatey/','http://location','file:///c:/somwhere/chocolatey.nupkg'].each do |param_value| + context "#{param_value}" do + let (:params) {{ + :chocolatey_download_url => param_value + }} + + it 'should compile successfully' do + catalogue + end + end + end + + if Puppet.version < '4.0.0' + invalid_url_values = ['\\\\ciflocation\\share','bob',"4",'',3] + not_a_string_values = [false] + else + invalid_url_values = ['\\\\ciflocation\\share','bob',"4",''] + not_a_string_values = [false, 3] + end + + invalid_url_values.each do |param_value| + context "#{param_value} (invalid scenario)" do + let (:params) {{ + :chocolatey_download_url => param_value + }} + + let(:error_message) { /use a Http\/Https\/File Url that downloads/ } + it { + expect { catalogue }.to raise_error(Puppet::Error, error_message) + } + end + end + + not_a_string_values.each do |param_value| + context "#{param_value} (invalid scenario)" do + let (:params) {{ + :chocolatey_download_url => param_value + }} + + let(:error_message) { /is not a string/ } + it { + expect { catalogue }.to raise_error(Puppet::Error, error_message) + } + end + end + end + + context "choco_install_location =>" do + ['C:\\ProgramData\\chocolatey','D:\\somewhere'].each do |param_value| + context "#{param_value}" do + let (:params) {{ + :choco_install_location => param_value + }} + + it 'should compile successfully' do + catalogue + end + end + end + + if Puppet.version < '4.0.0' + [false].each do |param_value| + context "#{param_value} (invalid scenario)" do + let (:params) {{ + :choco_install_location => param_value + }} + + let(:error_message) { /is not a string/ } + it { + expect { catalogue }.to raise_error(Puppet::Error, error_message) + } + end + end + + #1 is actually a string before v4. + [1,'https://somewhere','\\\\overhere',''].each do |param_value| + context "#{param_value} (invalid scenario)" do + let (:params) {{ + :choco_install_location => param_value + }} + + let(:error_message) { /Please use a full path for choco_install_location/ } + it { + expect { catalogue }.to raise_error(Puppet::Error, error_message) + } + end + end + else + [1,false].each do |param_value| + context "#{param_value} (invalid scenario)" do + let (:params) {{ + :choco_install_location => param_value + }} + + let(:error_message) { /is not a string/ } + it { + expect { catalogue }.to raise_error(Puppet::Error, error_message) + } + end + end + + ['https://somewhere','\\\\overhere',''].each do |param_value| + context "#{param_value} (invalid scenario)" do + let (:params) {{ + :choco_install_location => param_value + }} + + let(:error_message) { /Please use a full path for choco_install_location/ } + it { + expect { catalogue }.to raise_error(Puppet::Error, error_message) + } + end + end + end + end + + context "choco_install_timeout_seconds =>" do + [1500,8000,"1",'30'].each do |param_value| + context "#{param_value}" do + let (:params) {{ + :choco_install_timeout_seconds => param_value + }} + + it 'should compile successfully' do + catalogue + end + end + end + + ['string',false,''].each do |param_value| + context "#{param_value} (invalid scenario)" do + let (:params) {{ + :choco_install_timeout_seconds => param_value + }} + + let(:error_message) { /Expected first argument to be an Integer/ } + it { + expect { catalogue }.to raise_error(Puppet::Error, error_message) + } + end + end + end + + ['use_7zip','enable_autouninstaller'].each do |boolean_param| + context "#{boolean_param} =>" do + [true, false].each do |param_value| + context "#{param_value}" do + let (:params) {{ + boolean_param.to_sym => param_value + }} + + it 'should compile successfully' do + catalogue + end + end + end + + ['true','false','bob',3,"4",''].each do |param_value| + context "#{param_value} (invalid scenario)" do + let (:params) {{ + boolean_param.to_sym => param_value + }} + + let(:error_message) { /is not a boolean./ } + it { + expect { catalogue }.to raise_error(Puppet::Error, error_message) + } + end + end + end + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/classes/install_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/classes/install_spec.rb new file mode 100644 index 000000000..b1a14e6ef --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/classes/install_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +RSpec.describe 'chocolatey' do + + let(:facts) { + { + :chocolateyversion => '0.9.9.8', + :choco_install_path => 'C:\ProgramData\chocolatey', + } + } + + context 'contains install.pp' do + ['c:\local_folder', "C:\\ProgramData\\chocolatey"].each do |param_value| + context "choco_install_location => #{param_value}" do + let(:params) {{ :choco_install_location => param_value }} + + it { is_expected.to contain_exec('install_chocolatey_official').with_creates("#{param_value}\\bin\\choco.exe") } + end + end + + + [1500, 35].each do |param_value| + context "choco_install_timeout_seconds => #{param_value}" do + let(:params) {{ :choco_install_timeout_seconds => param_value }} + + it { is_expected.to contain_exec('install_chocolatey_official').with_timeout("#{param_value}") } + end + end + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/spec_helper.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/spec_helper.rb new file mode 100644 index 000000000..72c407699 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/spec_helper.rb @@ -0,0 +1,64 @@ +#require 'ruby-prof' +#RubyProf.start + +IDEAL_CONSOLE_WIDTH = 72 +def horizontal_rule(width = 5) + '=' * [width, IDEAL_CONSOLE_WIDTH].min +end + +require 'puppetlabs_spec_helper/module_spec_helper' + +# require dependencies +gems = [ + #'minitest/autorun', # http://docs.seattlerb.org/minitest/ + #'minitest/unit', # https://github.com/freerange/mocha#bundler + 'mocha', # http://gofreerange.com/mocha/docs/Mocha/Configuration.html + 'puppet', +] +begin + gems.each {|gem| require gem} +rescue => e + # http://goo.gl/r3nFG + # emphasize dependency failures in case a task spews lots of output + warn horizontal_rule(e.message.length) + warn e.class + warn e.message + warn horizontal_rule(e.message.length) + exit(1) +end + +RSpec.configure do |c| + # set the environment variable before files are loaded, otherwise it is too late + ENV['ChocolateyInstall'] = 'c:\blah' + + begin + Win32::Registry.any_instance.stubs(:[]).with('Bind') + Win32::Registry.any_instance.stubs(:[]).with('Domain') + Win32::Registry.any_instance.stubs(:[]).with('ChocolateyInstall').raises(Win32::Registry::Error.new(2), 'file not found yo') + rescue + # we don't care + end + + # https://www.relishapp.com/rspec/rspec-core/v/2-12/docs/mock-framework-integration/mock-with-mocha! + c.mock_framework = :mocha + # see output for all failures + c.fail_fast = false + c.expect_with :rspec do |e| + e.syntax = [:should, :expect] + end + c.raise_errors_for_deprecations! + + c.after :suite do + #result = RubyProf.stop + # Print a flat profile to text + #printer = RubyProf::FlatPrinter.new(result) + #printer.print(STDOUT) + end +end + +# We need this because the RAL uses 'should' as a method. This +# allows us the same behaviour but with a different method name. +class Object + alias :must :should + alias :must_not :should_not +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/unit/facter/choco_install_path_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/facter/choco_install_path_spec.rb new file mode 100644 index 000000000..fb1869558 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/facter/choco_install_path_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' +require 'facter' +require 'puppet_x/chocolatey/chocolatey_install' + +describe 'choco_install_path fact' do + subject(:fact) { Facter.fact(:choco_install_path) } + + before :each do + Facter.clear + Facter.clear_messages + end + + context "on Windows", :if => Puppet::Util::Platform.windows? do + it "should return the output of PuppetX::Chocolatey::ChocolateyInstall.install_path" do + expected_value = 'C:\somewhere' + PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns(expected_value) + + subject.value.must == expected_value + end + + it "should return the default path when PuppetX::Chocolatey::ChocolateyInstall.install_path is nil" do + PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns(nil) + + subject.value.must == 'C:\ProgramData\chocolatey' + end + end + + after :each do + Facter.clear + Facter.clear_messages + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/unit/facter/chocolateyversion_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/facter/chocolateyversion_spec.rb new file mode 100644 index 000000000..c6f6f143a --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/facter/chocolateyversion_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' +require 'facter' +require 'puppet_x/chocolatey/chocolatey_version' + +describe 'chocolateyversion fact' do + subject(:fact) { Facter.fact(:chocolateyversion) } + + before :each do + Facter.clear + Facter.clear_messages + end + + context "on Windows", :if => Puppet::Util::Platform.windows? do + it "should return the output of PuppetX::Chocolatey::ChocolateyVersion.version" do + expected_value = '1.2.3' + PuppetX::Chocolatey::ChocolateyVersion.expects(:version).returns(expected_value) + + subject.value.must == expected_value + end + + it "should return the default of 0 when PuppetX::Chocolatey::ChocolateyVersion.version is nil" do + PuppetX::Chocolatey::ChocolateyVersion.expects(:version).returns(nil) + + subject.value.must == '0' + end + end + + after :each do + Facter.clear + Facter.clear_messages + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/chocolateyconfig/windows_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/chocolateyconfig/windows_spec.rb new file mode 100644 index 000000000..696181351 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/chocolateyconfig/windows_spec.rb @@ -0,0 +1,268 @@ +require 'spec_helper' +require 'stringio' +require 'puppet/type/chocolateyconfig' +require 'puppet/provider/chocolateyconfig/windows' +require 'rexml/document' + +provider = Puppet::Type.type(:chocolateyconfig).provider(:windows) +describe provider do + let (:name) { 'configItem' } + let (:resource) { Puppet::Type.type(:chocolateyconfig).new(:provider => :windows, :name => name, :value => "yes") } + let (:choco_config) { 'c:\choco.config' } + let (:choco_install_path) { 'c:\dude\bin\choco.exe' } + let (:choco_config_contents) { <<-'EOT' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + EOT + } + + + let (:minimum_supported_version) {'0.9.10.0'} + let (:last_unsupported_version) {'0.9.9.12'} + + before :each do + PuppetX::Chocolatey::ChocolateyInstall.stubs(:install_path).returns('c:\dude') + PuppetX::Chocolatey::ChocolateyCommon.stubs(:choco_version).returns(minimum_supported_version) + + @provider = provider.new(resource) + resource.provider = @provider + + # Stub all file and config tests + provider.stubs(:healthcheck) + end + + context "verify provider" do + it "should be an instance of Puppet::Type::Chocolateyconfig::ProviderWindows" do + @provider.must be_an_instance_of Puppet::Type::Chocolateyconfig::ProviderWindows + end + + it "should have a create method" do + @provider.should respond_to(:create) + end + + it "should have an exists? method" do + @provider.should respond_to(:exists?) + end + + it "should have a destroy method" do + @provider.should respond_to(:destroy) + end + + it "should have a properties method" do + @provider.should respond_to(:properties) + end + + it "should have a query method" do + @provider.should respond_to(:query) + end + end + + context "properties" do + context ":value" do + #it "should default to nil" do + # resource[:value].should be_nil + #end + + it "should accept c:\\cache" do + resource[:value] = 'c:\cache' + end + + it "should accept 2700" do + resource[:value] = '2700' + end + + it "should accept 'value with spaces'" do + resource[:value] = 'value with spaces' + end + end + end + + context "self.get_configs" do + before :each do + PuppetX::Chocolatey::ChocolateyCommon.expects(:set_env_chocolateyinstall) + end + + it "should error when the config file location is null" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(nil) + + expect { + provider.get_configs + }.to raise_error(Puppet::ResourceError, /Config file not found for Chocolatey/) + end + + it "should error when the config file is not found" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(false) + + expect { + provider.get_configs + }.to raise_error(Puppet::ResourceError, /was unable to locate config file at/) + end + + context "when getting configs from the config file" do + configs = [] + + before :each do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(true) + File.expects(:new).with(choco_config,"r").returns choco_config_contents + + configs = provider.get_configs + end + + it "should match the count of configs in the config" do + configs.count.must eq 11 + + end + + it "should contain xml elements" do + configs[0].must be_an_instance_of REXML::Element + end + end + end + + context "self.get_config" do + let (:element) { REXML::Element.new('add') } + element_key = "cacheLocation" + element_value= "c:\\cache" + element_description = "Cache location if not TEMP folder." + + before :each do + element.add_attributes( { "key" => element_key, + "value" => element_value, + "description" => element_description, + } ) + end + + it "should return nil config when element is nil" do + provider.get_config(nil).must be == {} + end + + it "should convert an element to a config" do + config = provider.get_config(element) + + config[:name].must eq element_key + config[:value].must eq element_value + config[:description].must eq element_description + config[:ensure].must eq :present + end + end + + context ".validation" do + it "should not error when Chocolatey is not installed" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).returns(false).at_least(0) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_install_path).returns(false).at_least(0) + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns('') + + resource.provider.validate + end + + it "should not error when the minimum version is met" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).returns(false).at_least(0) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_install_path).returns(true).at_least(0) + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version) + + resource.provider.validate + end + + it "should error when the minimum version is not met" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).returns(true).at_least(0) + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(last_unsupported_version) + + expect { + resource.provider.validate + }.to raise_error(Puppet::ResourceError, /Chocolatey version must be '0.9.10.0' to manage configuration values. Detected '#{last_unsupported_version}'/) + end + end + + context ".flush" do + resource_name = "yup" + resource_value = "this" + resource_ensure = :present + + before :each do + PuppetX::Chocolatey::ChocolateyCommon.expects(:set_env_chocolateyinstall).at_most_once + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config).at_most_once + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(true).at_most_once + File.expects(:new).with(choco_config,"r").returns(choco_config_contents).at_most_once + + resource[:name] = resource_name + resource[:value] = resource_value + resource[:ensure] = resource_ensure + end + + it "should ensure a config setting is set" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version) + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'config', 'set', + '--name', resource_name, + '--value', resource_value + ]) + + resource.flush + end + + it "should ensure a config setting is removed" do + resource.provider.destroy + + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version) + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'config', 'unset', + '--name', resource_name + ]) + + resource.flush + end + + it "should provide an error message when choco execution fails" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version) + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'config', 'set', + '--name', resource_name, + '--value', resource_value + ]).raises(Puppet::ExecutionFailure, "Nooooo") + + expect { resource.flush }.to raise_error(Puppet::Error, /Unable to set Chocolateyconfig/) + end + + + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/chocolateyfeature/windows_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/chocolateyfeature/windows_spec.rb new file mode 100644 index 000000000..c5ac9dd67 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/chocolateyfeature/windows_spec.rb @@ -0,0 +1,170 @@ +require 'spec_helper' +require 'stringio' +require 'puppet/type/chocolateyfeature' +require 'puppet/provider/chocolateyfeature/windows' +require 'rexml/document' + +provider = Puppet::Type.type(:chocolateyfeature).provider(:windows) +describe provider do + let (:name) { 'allowglobalconfirmation' } + let (:resource) { Puppet::Type.type(:chocolateyfeature).new(:provider => :windows, :name => name, :ensure => 'enabled' ) } + let (:choco_config) { 'c:\choco.config' } + let (:choco_install_path) { 'c:\dude\bin\choco.exe' } + let (:choco_config_contents) { <<-'EOT' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + EOT + } + + let (:minimum_supported_version) {'0.9.9.0'} + + before :each do + PuppetX::Chocolatey::ChocolateyInstall.stubs(:install_path).returns('c:\dude') + PuppetX::Chocolatey::ChocolateyCommon.stubs(:choco_version).returns(minimum_supported_version) + + @provider = provider.new(resource) + resource.provider = @provider + + # Stub all file and config tests + provider.stubs(:healthcheck) + end + + context "verify provider" do + it "should be an instance of Puppet::Type::Chocolateyfeature::ProviderWindows" do + + @provider.must be_an_instance_of Puppet::Type::Chocolateyfeature::ProviderWindows + end + + it "should have a enable method" do + @provider.should respond_to(:enable) + end + + it "should have an exists? method" do + @provider.should respond_to(:exists?) + end + + it "should have a disable method" do + @provider.should respond_to(:disable) + end + + it "should have a properties method" do + @provider.should respond_to(:properties) + end + + it "should have a query method" do + @provider.should respond_to(:query) + end + end + + context "self.get_features" do + before :each do + PuppetX::Chocolatey::ChocolateyCommon.expects(:set_env_chocolateyinstall) + end + + it "should error when the config file location is null" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(nil) + + expect { + provider.get_features + }.to raise_error(Puppet::ResourceError, /Config file not found for Chocolatey/) + end + + it "should error when the config file is not found" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(false) + + expect { + provider.get_features + }.to raise_error(Puppet::ResourceError, /was unable to locate config file at/) + end + + context "when getting features from the config file" do + features = [] + + before :each do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(true) + File.expects(:new).with(choco_config,"r").returns choco_config_contents + + features = provider.get_features + end + + it "should match the count of features in the config" do + features.count.must eq 14 + + end + + it "should contain xml elements" do + features[0].must be_an_instance_of REXML::Element + end + end + end + + context "self.get_feature" do + let (:element) { REXML::Element.new('feature') } + element_name = "default" + element_enabled = 'true' + + before :each do + element.add_attributes( { "name" => element_name, "enabled" => element_enabled, } ) + end + + it "should return nil feature when element is nil" do + provider.get_feature(nil).must be == {} + end + + it "should convert an element to a feature" do + feature = provider.get_feature(element) + + feature[:name].must eq element_name + feature[:ensure].must eq :enabled + end + + it "when feature is disabled" do + element.delete_attribute('enabled') + element.add_attribute('enabled', 'false') + + feature = provider.get_feature(element) + feature[:ensure].must eq :disabled + end + end + +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/chocolateysource/windows_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/chocolateysource/windows_spec.rb new file mode 100644 index 000000000..d27d3290d --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/chocolateysource/windows_spec.rb @@ -0,0 +1,607 @@ +require 'spec_helper' +require 'stringio' +require 'puppet/type/chocolateysource' +require 'puppet/provider/chocolateysource/windows' +require 'rexml/document' + +provider = Puppet::Type.type(:chocolateysource).provider(:windows) +describe provider do + let (:name) { 'sourcename' } + let (:location) { 'c:\packages' } + let (:resource) { Puppet::Type.type(:chocolateysource).new(:provider => :windows, :name => name, :location => location) } + let (:choco_config) { 'c:\choco.config' } + let (:choco_install_path) { 'c:\dude\bin\choco.exe' } + let (:choco_config_contents) { <<-'EOT' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + EOT + } + + let (:newer_choco_version) {'0.9.10.0'} + let (:minimum_supported_version_priority) {'0.9.9.9'} + let (:last_unsupported_version_priority) {'0.9.9.8'} + let (:minimum_supported_version) {'0.9.9.0'} + let (:last_unsupported_version) {'0.9.8.33'} + + before :each do + PuppetX::Chocolatey::ChocolateyInstall.stubs(:install_path).returns('c:\dude') + PuppetX::Chocolatey::ChocolateyCommon.stubs(:choco_version).returns(minimum_supported_version) + + @provider = provider.new(resource) + resource.provider = @provider + + # Stub all file and config tests + provider.stubs(:healthcheck) + end + + context "verify provider" do + it "should be an instance of Puppet::Type::Chocolateysource::ProviderWindows" do + + @provider.must be_an_instance_of Puppet::Type::Chocolateysource::ProviderWindows + end + + it "should have a create method" do + @provider.should respond_to(:create) + end + + it "should have an exists? method" do + @provider.should respond_to(:exists?) + end + + it "should have a disable method" do + @provider.should respond_to(:disable) + end + + it "should have a destroy method" do + @provider.should respond_to(:destroy) + end + + it "should have a properties method" do + @provider.should respond_to(:properties) + end + + it "should have a query method" do + @provider.should respond_to(:query) + end + end + + context "properties" do + + context ":location" do + it "should accept c:\\packages" do + resource[:location] = 'c:\packages' + end + + it "should accept http://somelocation/packages" do + resource[:location] = 'http://somelocation/packages' + end + + it "should accept \\\\unc\\share\\packages" do + resource[:location] = '\\unc\share\packages' + end + end + + context ":user" do + it "should accept 'bob'" do + resource[:user] = 'bob' + end + + it "should accept 'domain\\bob'" do + resource[:user] = 'domain\bob' + end + + it "should accept api keys like 'api123-456-243 d123'" do + resource[:user] = 'api123-456-243 d123' + end + end + + context ":password" do + it "should accept 'bob'" do + resource[:password] = 'bob' + end + + it "should accept api keys like 'api123-456-243 d123'" do + resource[:password] = 'api123-456-243 d123' + end + end + end + + context "self.get_sources" do + before :each do + PuppetX::Chocolatey::ChocolateyCommon.expects(:set_env_chocolateyinstall) + end + + it "should error when the config file location is null" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(nil) + + expect { + provider.get_sources + }.to raise_error(Puppet::ResourceError, /Config file not found for Chocolatey/) + end + + it "should error when the config file is not found" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(false) + + expect { + provider.get_sources + }.to raise_error(Puppet::ResourceError, /was unable to locate config file at/) + end + + context "when getting sources from the config file" do + sources = [] + + before :each do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(true) + File.expects(:new).with(choco_config,"r").returns choco_config_contents + + sources = provider.get_sources + end + + it "should match the count of sources in the config" do + sources.count.must eq 3 + + end + + it "should contain xml elements" do + sources[0].must be_an_instance_of REXML::Element + end + end + end + + context "self.get_source" do + let (:element) { REXML::Element.new('source') } + element_id = "default" + element_value= "c:\\packages" + element_disabled = "false" + element_priority = "10" + element_user = "thisguy" + element_password = "super/encrypted+value==" + + + before :each do + element.add_attributes( { "id" => element_id, + "value" => element_value, + "disabled" => element_disabled, + "priority" => element_priority, + "user" => element_user, + "password" => element_password + } ) + end + + it "should return nil source when element it nil" do + provider.get_source(nil).must be == {} + end + + it "should convert an element to a source" do + source = provider.get_source(element) + + source[:name].must eq element_id + source[:location].must eq element_value + source[:priority].must eq element_priority + source[:user].must eq element_user + source[:ensure].must eq :present + end + + it "should convert a bare bones element to a source" do + element.delete_attribute('disabled') + element.delete_attribute('priority') + element.delete_attribute('user') + element.delete_attribute('password') + + source = provider.get_source(element) + + source[:name].must eq element_id + source[:location].must eq element_value + source[:ensure].must eq :present + end + + it "when source is disabled" do + element.delete_attribute('disabled') + element.add_attribute('disabled', 'true') + + source = provider.get_source(element) + source[:ensure].must eq :disabled + end + end + + context ".validation" do + before :each do + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).returns(true).at_least(0) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_install_path).returns(true).at_least(0) + end + + it "should not warn when both user/password are empty" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version) + Puppet.expects(:warning).never + Puppet.expects(:debug).never + + resource.provider.validate + end + + it "should throw when choco version is less than the minimum supported version" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(last_unsupported_version) + + expect { + resource.provider.validate + }.to raise_error(Puppet::Error, /Chocolatey version must be '0.9.9.0' to manage configuration values with Puppet/) + end + + it "should write a debug message on password when password is not empty" do + resource[:user] = 'tim' + resource[:password] = 'tim' + + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version) + Puppet.expects(:warning).never + Puppet.expects(:debug).with("The password is not ensurable, so Puppet is unable to change the value using chocolateysource resource. As a workaround, a password change can be in the form of an exec. Reference Chocolateysource[#{name}]") + + resource.provider.validate + end + + it "should not warn on user/password on newer choco versions" do + resource[:user] = 'tim' + resource[:password] = 'tim' + + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version) + Puppet.expects(:warning).never + + resource.provider.validate + end + + it "should not warn on user/password when choco version is the minimum supported version" do + resource[:user] = 'tim' + resource[:password] = 'tim' + + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version) + Puppet.expects(:warning).never + + resource.provider.validate + end + + it "should not warn if priority is not set" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version) + Puppet.expects(:warning).never + + resource.provider.validate + end + + it "should not warn if priority is not set on older unsupported versions" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(last_unsupported_version_priority) + Puppet.expects(:warning).never + + resource.provider.validate + end + + it "should not warn if priority is 0 on unsupported versions" do + resource[:priority] = 0 + + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(last_unsupported_version_priority) + Puppet.expects(:warning).never + + resource.provider.validate + end + + it "should not warn on priority when choco version is newer than the minimum supported version" do + resource[:priority] = 10 + + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version) + Puppet.expects(:warning).never + + resource.provider.validate + end + + it "should not warn on priority when choco version is the minimum supported version" do + resource[:priority] = 10 + + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version_priority) + Puppet.expects(:warning).never + + resource.provider.validate + end + + it "should warn on priority when choco version is less than the minimum supported version" do + resource[:priority] = 10 + + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(last_unsupported_version_priority) + Puppet.expects(:warning).with("Chocolatey is unable to manage priority for sources when version is less than 0.9.9.9. The value you set will be ignored.") + + resource.provider.validate + end + + it "should pass when ensure is not present and location is empty" do + no_location_resource = Puppet::Type.type(:chocolateysource).new(:name => 'source', :ensure => :disabled ) + no_location_resource.provider = provider.new(no_location_resource) + + no_location_resource.provider.validate + end + + it "should fail when ensure => present and location is empty" do + expect { + no_location_resource = Puppet::Type.type(:chocolateysource).new(:name => 'source') + no_location_resource.provider = provider.new(no_location_resource) + + no_location_resource.provider.validate + }.to raise_error(Exception, /non-empty location/) + # check for just an exception here + # In some versions of Puppet, this comes back as ArgumentError + # In other versions of Puppet, this comes back as Puppet::Error + end + end + + context ".flush" do + resource_name = "yup" + resource_location = "loc" + resource_ensure = :present + resource_priority = 10 + resource_user = "thatguy" + resource_password = "secrets!" + + before :each do + PuppetX::Chocolatey::ChocolateyCommon.expects(:set_env_chocolateyinstall).at_most_once + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config).at_most_once + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(true).at_most_once + File.expects(:new).with(choco_config,"r").returns(choco_config_contents).at_most_once + + resource[:name] = resource_name + resource[:location] = resource_location + resource[:ensure] = resource_ensure + end + + it "should ensure a source is present with minimal values set" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version) + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'add', + '--name', resource_name, + '--source', resource_location, + '--priority', 0, + ]) + + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'enable', + '--name', 'yup' + ]) + + resource.flush + end + + it "should ensure a source is present with all values set" do + resource[:priority] = resource_priority + resource[:user] = resource_user + resource[:password] = resource_password + + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version) + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'add', + '--name', resource_name, + '--source', resource_location, + '--user', resource_user, + '--password', resource_password, + '--priority', resource_priority, + ]) + + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'enable', + '--name', resource_name + ]) + + resource.flush + end + + it "should set priority when present" do + resource[:priority] = resource_priority + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version) + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'add', + '--name', resource_name, + '--source', resource_location, + '--priority', resource_priority, + ]) + + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'enable', + '--name', resource_name + ]) + + resource.flush + end + + it "should set user and password when user is present" do + resource[:user] = resource_user + resource[:password] = resource_password + + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version) + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'add', + '--name', resource_name, + '--source', resource_location, + '--user', resource_user, + '--password', resource_password, + '--priority', 0, + ]) + + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'enable', + '--name', resource_name + ]) + + resource.flush + end + + it "should set user and password when choco version is newer than the minimum supported version" do + resource[:user] = resource_user + resource[:password] = resource_password + + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version) + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'add', + '--name', resource_name, + '--source', resource_location, + '--user', resource_user, + '--password', resource_password, + '--priority', 0, + ]) + + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'enable', + '--name', resource_name + ]) + + resource.flush + end + + it "should set user and password when choco version is the minimum supported version" do + resource[:user] = resource_user + resource[:password] = resource_password + + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version) + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'add', + '--name', resource_name, + '--source', resource_location, + '--user', resource_user, + '--password', resource_password, + ]) + + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'enable', + '--name', resource_name + ]) + + resource.flush + end + + it "should set priority when choco version is newer than the minimum supported version" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version) + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'add', + '--name', resource_name, + '--source', resource_location, + '--priority', 0, + ]) + + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'enable', + '--name', resource_name, + ]) + + resource.flush + end + + it "should set priority when choco version is the minimum supported version" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version_priority) + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'add', + '--name', resource_name, + '--source', resource_location, + '--priority', 0, + ]) + + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'enable', + '--name', resource_name, + ]) + + resource.flush + end + + it "should not set priority when choco version is less than the minimum supported version" do + resource[:priority] = resource_priority + + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(last_unsupported_version_priority) + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'add', + '--name', resource_name, + '--source', resource_location, + ]) + + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'enable', + '--name', resource_name, + ]) + + resource.flush + end + + it "should disable a source when ensure => disabled" do + resource[:ensure] = :disabled + resource[:name] = 'chocolatey' + resource.provider.disable + + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'disable', + '--name', 'chocolatey' + ]) + + resource.flush + end + + it "should remove a source when ensure => absent" do + resource[:ensure] = :absent + resource.provider.destroy + + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).never + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'remove', + '--name', resource_name, + ]) + + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'enable', + '--name', 'yup' + ]).never + + resource.flush + end + + it "should provide an error message when choco execution fails" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version) + Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey), + 'source', 'add', + '--name', resource_name, + '--source', resource_location, + '--priority', 0, + ]).raises(Puppet::ExecutionFailure, "Nooooo") + + expect { resource.flush }.to raise_error(Puppet::Error, /Unable to set Chocolatey source/) + end + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/package/chocolatey_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/package/chocolatey_spec.rb new file mode 100644 index 000000000..e6fa57be1 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/provider/package/chocolatey_spec.rb @@ -0,0 +1,514 @@ +require 'spec_helper' +require 'stringio' +require 'puppet/type/package' +require 'puppet/provider/package/chocolatey' + +provider = Puppet::Type.type(:package).provider(:chocolatey) + +describe provider do + let (:resource) { Puppet::Type.type(:package).new(:provider => :chocolatey, :name => "chocolatey") } + let (:first_compiled_choco_version) {'0.9.9.0'} + let (:newer_choco_version) {'0.9.10.0'} + let (:last_posh_choco_version) {'0.9.8.33'} + let (:minimum_supported_choco_uninstall_source) {'0.9.10.0'} + let (:minimum_supported_choco_exit_codes) {'0.9.10.0'} + let (:choco_zero_ten_zero) {'0.10.0'} + + before :each do + @provider = provider.new(resource) + resource.provider = @provider + + # Stub all file and config tests + provider.stubs(:healthcheck) + Puppet::Util::Execution.stubs(:execute) + end + + it "should be an instance of Puppet::Type::Package::ProviderChocolatey" do + @provider.must be_an_instance_of Puppet::Type::Package::ProviderChocolatey + end + + it "should have an install method" do + @provider.should respond_to(:install) + end + + it "should have a latest method" do + @provider.should respond_to(:uninstall) + end + + it "should have an update method" do + @provider.should respond_to(:update) + end + + it "should have a latest method" do + @provider.should respond_to(:latest) + end + + context "parameter :source" do + it "should default to nil" do + resource[:source].should be_nil + end + + it "should accept c:\\packages" do + resource[:source] = 'c:\packages' + end + + it "should accept http://somelocation/packages" do + resource[:source] = 'http://somelocation/packages' + end + + it "should accept \\\\unc\\share\\packages" do + resource[:source] = '\\unc\share\packages' + end + end + + context "when installing" do + context "with compiled choco client" do + before :each do + @provider.class.stubs(:is_compiled_choco?).returns(true) + PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns('c:\dude') + PuppetX::Chocolatey::ChocolateyCommon.stubs(:file_exists?).with('c:\dude\bin\choco.exe').returns(true) + PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(first_compiled_choco_version) + # unhold is called in installs on compiled choco + Puppet::Util::Execution.stubs(:execute) + end + + it "should use install command without versioned package" do + resource[:ensure] = :present + @provider.expects(:chocolatey).with('install', 'chocolatey','-y', nil) + + @provider.install + end + + it "should call with ignore package exit codes when = 0.9.10" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_choco_exit_codes).at_least_once + resource[:ensure] = :present + @provider.expects(:chocolatey).with('install', 'chocolatey','-y', nil, '--ignore-package-exit-codes') + + @provider.install + end + + it "should call with ignore package exit codes when > 0.9.10" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(choco_zero_ten_zero).at_least_once + resource[:ensure] = :present + @provider.expects(:chocolatey).with('install', 'chocolatey','-y', nil, '--ignore-package-exit-codes') + + @provider.install + end + + it "should use upgrade command with versioned package" do + resource[:ensure] = '1.2.3' + @provider.expects(:chocolatey).with('upgrade', 'chocolatey', '-version', '1.2.3', '-y', nil) + + @provider.install + end + + it "should call install instead of upgrade if package name ends with .config" do + resource[:name] = "packages.config" + resource[:ensure] = :present + @provider.expects(:chocolatey).with('install', 'packages.config','-y', nil) + + @provider.install + end + + it "should use source if it is specified" do + resource[:source] = 'c:\packages' + @provider.expects(:chocolatey).with('install','chocolatey','-y', '-source', 'c:\packages', nil) + + @provider.install + end + end + + context "with posh choco client" do + before :each do + @provider.class.stubs(:is_compiled_choco?).returns(false) + PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns('c:\dude') + PuppetX::Chocolatey::ChocolateyCommon.stubs(:file_exists?).with('c:\dude\bin\choco.exe').returns(true) + PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(last_posh_choco_version) + end + + it "should use install command without versioned package" do + resource[:ensure] = :present + @provider.expects(:chocolatey).with('install', 'chocolatey', nil) + + @provider.install + end + + it "should use update command with versioned package" do + resource[:ensure] = '1.2.3' + @provider.expects(:chocolatey).with('update', 'chocolatey', '-version', '1.2.3', nil) + + @provider.install + end + + it "should use source if it is specified" do + resource[:source] = 'c:\packages' + @provider.expects(:chocolatey).with('install','chocolatey', '-source', 'c:\packages', nil) + + @provider.install + end + end + end + + context "when holding" do + context "with compiled choco client" do + before :each do + @provider.class.stubs(:is_compiled_choco?).returns(true) + PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns('c:\dude') + PuppetX::Chocolatey::ChocolateyCommon.stubs(:file_exists?).with('c:\dude\bin\choco.exe').returns(true) + PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(first_compiled_choco_version) + # unhold is called in installs on compiled choco + Puppet::Util::Execution.stubs(:execute) + end + + it "should use install command with held package" do + resource[:ensure] = :held + @provider.expects(:chocolatey).with('install', 'chocolatey','-y', nil) + @provider.expects(:chocolatey).with('pin', 'add', '-n', 'chocolatey') + + @provider.hold + end + end + + context "with posh choco client" do + before :each do + @provider.class.stubs(:is_compiled_choco?).returns(false) + end + + it "should throw an argument error with held package" do + resource[:ensure] = :held + + expect { @provider.hold }.to raise_error(ArgumentError, "Only choco v0.9.9+ can use ensure => held") + end + end + end + + context "when uninstalling" do + context "with compiled choco client" do + before :each do + @provider.class.stubs(:is_compiled_choco?).returns(true) + PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(first_compiled_choco_version) + # unhold is called in installs on compiled choco + Puppet::Util::Execution.stubs(:execute) + end + + it "should call the remove operation" do + @provider.expects(:chocolatey).with('uninstall', 'chocolatey','-fy', nil) + + @provider.uninstall + end + + it "should call with ignore package exit codes when = 0.9.10" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_choco_exit_codes).at_least_once + @provider.expects(:chocolatey).with('uninstall', 'chocolatey','-fy', nil, '--ignore-package-exit-codes') + + @provider.uninstall + end + + it "should call with ignore package exit codes when > 0.9.10" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(choco_zero_ten_zero).at_least_once + @provider.expects(:chocolatey).with('uninstall', 'chocolatey','-fy', nil, '--ignore-package-exit-codes') + + @provider.uninstall + end + + it "should use ignore source if it is specified and the version is less than 0.9.10" do + resource[:source] = 'c:\packages' + @provider.expects(:chocolatey).with('uninstall','chocolatey','-fy', nil) + + @provider.uninstall + end + + it "should use source if it is specified and the version is at least 0.9.10" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_choco_uninstall_source).at_least_once + resource[:source] = 'c:\packages' + @provider.expects(:chocolatey).with('uninstall','chocolatey', '-fy', '-source', 'c:\packages', nil, '--ignore-package-exit-codes') + + @provider.uninstall + end + + it "should use source if it is specified and the version is greater than 0.9.10" do + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(choco_zero_ten_zero).at_least_once + resource[:source] = 'c:\packages' + @provider.expects(:chocolatey).with('uninstall','chocolatey', '-fy', '-source', 'c:\packages', nil, '--ignore-package-exit-codes') + + @provider.uninstall + end + end + + context "with posh choco client" do + before :each do + @provider.class.stubs(:is_compiled_choco?).returns(false) + PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(last_posh_choco_version) + end + + it "should call the remove operation" do + @provider.expects(:chocolatey).with('uninstall', 'chocolatey', nil) + + @provider.uninstall + end + + it "should use source if it is specified" do + resource[:source] = 'c:\packages' + @provider.expects(:chocolatey).with('uninstall','chocolatey', '-source', 'c:\packages', nil) + + @provider.uninstall + end + end + end + + context "when updating" do + context "with compiled choco client" do + before :each do + @provider.class.stubs(:is_compiled_choco?).returns(true) + PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(first_compiled_choco_version) + # unhold is called in installs on compiled choco + Puppet::Util::Execution.stubs(:execute) + end + + it "should use `chocolatey upgrade` when ensure latest and package present" do + provider.stubs(:instances).returns [provider.new({ + :ensure => "1.2.3", + :name => "chocolatey", + :provider => :chocolatey, + })] + @provider.expects(:chocolatey).with('upgrade', 'chocolatey', '-y', nil) + + @provider.update + end + + it "should call with ignore package exit codes when = 0.9.10" do + provider.stubs(:instances).returns [provider.new({ + :ensure => "1.2.3", + :name => "chocolatey", + :provider => :chocolatey, + })] + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_choco_exit_codes).at_least_once + resource[:ensure] = :present + @provider.expects(:chocolatey).with('upgrade', 'chocolatey','-y', nil, '--ignore-package-exit-codes') + + @provider.update + end + + it "should call with ignore package exit codes when > 0.9.10" do + provider.stubs(:instances).returns [provider.new({ + :ensure => "1.2.3", + :name => "chocolatey", + :provider => :chocolatey, + })] + PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(choco_zero_ten_zero).at_least_once + resource[:ensure] = :present + @provider.expects(:chocolatey).with('upgrade', 'chocolatey','-y', nil, '--ignore-package-exit-codes') + + @provider.update + end + + + it "should use `chocolatey install` when ensure latest and package absent" do + provider.stubs(:instances).returns [] + @provider.expects(:chocolatey).with('install', 'chocolatey', '-y', nil) + + @provider.update + end + + it "should use source if it is specified" do + provider.expects(:instances).returns [provider.new({ + :ensure => "latest", + :name => "chocolatey", + :provider => :chocolatey, + })] + resource[:source] = 'c:\packages' + @provider.expects(:chocolatey).with('upgrade','chocolatey', '-y', '-source', 'c:\packages', nil) + + @provider.update + end + end + + context "with posh choco client" do + before :each do + @provider.class.stubs(:is_compiled_choco?).returns(false) + PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(last_posh_choco_version) + end + + it "should use `chocolatey update` when ensure latest and package present" do + provider.stubs(:instances).returns [provider.new({ + :ensure => "1.2.3", + :name => "chocolatey", + :provider => :chocolatey, + })] + @provider.expects(:chocolatey).with('update', 'chocolatey', nil) + + @provider.update + end + + it "should use `chocolatey install` when ensure latest and package absent" do + provider.stubs(:instances).returns [] + @provider.expects(:chocolatey).with('install', 'chocolatey', nil) + + @provider.update + end + + it "should use source if it is specified" do + provider.expects(:instances).returns [provider.new({ + :ensure => "latest", + :name => "chocolatey", + :provider => :chocolatey, + })] + resource[:source] = 'c:\packages' + @provider.expects(:chocolatey).with('update','chocolatey', '-source', 'c:\packages', nil) + + @provider.update + end + end + end + + context "when getting latest" do + context "with compiled choco client" do + before :each do + @provider.class.stubs(:is_compiled_choco?).returns(true) + PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(first_compiled_choco_version) + end + + it "should use choco.exe arguments" do + # we don't care where choco is, we are concerned with the arguments that are passed to choco. + # + @provider.send(:latestcmd).drop(1).should == ['upgrade', '--noop', 'chocolatey','-r'] + end + + it "should use source if it is specified" do + resource[:source] = 'c:\packages' + @provider.send(:latestcmd).drop(1).should == ['upgrade', '--noop', 'chocolatey','-r', '-source', 'c:\packages'] + #@provider.expects(:chocolatey).with('upgrade', '--noop', 'chocolatey','-r', '-source', 'c:\packages') + + #@provider.latest + end + end + + context "with posh choco client" do + before :each do + @provider.class.stubs(:is_compiled_choco?).returns(false) + PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(last_posh_choco_version) + end + + it "should use posh arguments" do + @provider.send(:latestcmd).drop(1).should == ['version', 'chocolatey', '| findstr /R "latest" | findstr /V "latestCompare"'] + end + + it "should use source if it is specified" do + resource[:source] = 'c:\packages' + @provider.send(:latestcmd).drop(1).should == ['version', 'chocolatey', '-source', 'c:\packages', '| findstr /R "latest" | findstr /V "latestCompare"'] + #@provider.expects(:chocolatey).with('version', 'chocolatey', '-source', 'c:\packages', '| findstr /R "latest" | findstr /V "latestCompare"') + + #@provider.latest + end + end + end + + context "query" do + it "should return a hash when chocolatey and the package are present" do + provider.expects(:instances).returns [provider.new({ + :ensure => "1.2.5", + :name => "chocolatey", + :provider => :chocolatey, + })] + + @provider.query.should == { + :ensure => "1.2.5", + :name => "chocolatey", + :provider => :chocolatey, + } + end + + it "should return nil when the package is missing" do + provider.expects(:instances).returns [] + + @provider.query.should == nil + end + end + + context "when fetching a package list" do + it "should invoke provider listcmd" do + provider.expects(:listcmd) + + provider.instances + end + + it "should query chocolatey" do + provider.expects(:execpipe).with() do |args| + args[1] =~ /list/ + args[2] =~ /-lo/ + end + + provider.instances + end + + context "self.instances" do + it "should return nil on error" do + provider.expects(:execpipe).raises(Puppet::ExecutionFailure.new("ERROR!")) + + provider.instances.should be_nil + end + + context "with compiled choco client" do + before :each do + @provider.class.stubs(:is_compiled_choco?).returns(true) + PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(first_compiled_choco_version) + end + + it "should return installed packages with their versions" do + provider.expects(:execpipe).yields(StringIO.new(%Q(package1|1.23\n\package2|2.00\n))) + + packages = (provider.instances) + + packages.length.should == 2 + + packages[0].properties.should == { + :provider => :chocolatey, + :ensure => "1.23", + :name => 'package1' + } + + packages[1].properties.should == { + :provider => :chocolatey, + :ensure => "2.00", + :name => 'package2' + } + end + + it "should return nil on error" do + provider.expects(:execpipe).yields(StringIO.new(%Q(Unable to search for packages when there are no soures enabled for packages and none were passed as arguments.\n))) + + expect { + provider.instances + }.to raise_error(Puppet::Error, /At least one source must be enabled./) + end + end + + context "with posh choco client" do + before :each do + @provider.class.stubs(:is_compiled_choco?).returns(false) + PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(last_posh_choco_version) + end + + it "should return installed packages with their versions" do + provider.expects(:execpipe).yields(StringIO.new(%Q(package1 1.23\n\package2 2.00\n))) + + packages = (provider.instances) + + packages.length.should == 2 + + packages[0].properties.should == { + :provider => :chocolatey, + :ensure => "1.23", + :name => 'package1' + } + + packages[1].properties.should == { + :provider => :chocolatey, + :ensure => "2.00", + :name => 'package2' + } + end + end + end + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/type/chocolateyconfig_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/type/chocolateyconfig_spec.rb new file mode 100644 index 000000000..241d891c5 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/type/chocolateyconfig_spec.rb @@ -0,0 +1,103 @@ +require 'spec_helper' +require 'puppet/type/chocolateyconfig' + +describe Puppet::Type.type(:chocolateyconfig) do + let(:resource) { Puppet::Type.type(:chocolateyconfig).new(:name => "config", :ensure => :absent) } + let(:provider) { Puppet::Provider.new(resource) } + let(:catalog) { Puppet::Resource::Catalog.new } + let (:minimum_supported_version) {'0.9.10.0'} + + before :each do + PuppetX::Chocolatey::ChocolateyCommon.stubs(:choco_version).returns(minimum_supported_version) + + resource.provider = provider + end + + it "should be an instance of Puppet::Type::Chocolateyconfig" do + resource.must be_an_instance_of Puppet::Type::Chocolateyconfig + end + + it "parameter :name should be the name var" do + resource.parameters[:name].isnamevar?.should be_truthy + end + + #string values + ['name','value'].each do |param| + context "parameter :#{param}" do + let (:param_symbol) { param.to_sym } + + it "should not allow nil" do + expect { + resource[param_symbol] = nil + }.to raise_error(Puppet::Error, /Got nil value for #{param}/) + end + + it "should not allow empty" do + expect { + resource[param_symbol] = '' + }.to raise_error(Puppet::Error, /A non-empty #{param} must/) + end + + it "should accept any string value" do + resource[param_symbol] = 'value' + resource[param_symbol] = "c:/thisstring-location/value/somefile.txt" + resource[param_symbol] = "c:\\thisstring-location\\value\\somefile.txt" + end + end + end + + context "param :ensure" do + it "should accept 'present'" do + resource[:ensure] = 'present' + end + + it "should accept present" do + resource[:ensure] = :present + end + + it "should accept absent" do + resource[:ensure] = :absent + end + + it "should reject any other value" do + expect { + resource[:ensure] = :whenever + }.to raise_error(Puppet::Error, /Invalid value :whenever. Valid values are/) + end + end + + it "should autorequire Exec[install_chocolatey_official] when in the catalog" do + exec = Puppet::Type.type(:exec).new(:name => "install_chocolatey_official", :path => "nope") + catalog.add_resource resource + catalog.add_resource exec + + reqs = resource.autorequire + reqs.count.must == 1 + reqs[0].source.must == exec + reqs[0].target.must == resource + end + + context ".validate" do + it "should pass when ensure => absent with no value" do + resource[:ensure] = :absent + + resource.validate + end + + it "should pass when ensure => present with a value" do + resource[:ensure] = :present + resource[:value] = 'yo' + + resource.validate + end + + it "should fail when ensure => present with no value" do + resource[:ensure] = :present + + expect { + resource.validate + }.to raise_error(ArgumentError, /Unless ensure => absent, value is required/) + end + end + +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/type/chocolateyfeature_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/type/chocolateyfeature_spec.rb new file mode 100644 index 000000000..caac211e3 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/type/chocolateyfeature_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' +require 'puppet/type/chocolateyfeature' + +describe Puppet::Type.type(:chocolateyfeature) do + let(:resource) { Puppet::Type.type(:chocolateyfeature).new(:name => "chocolateyfeature", :ensure => "enabled" ) } + let(:provider) { Puppet::Provider.new(resource) } + let(:catalog) { Puppet::Resource::Catalog.new } + let (:minimum_supported_version) {'0.9.9.0'} + + before :each do + PuppetX::Chocolatey::ChocolateyCommon.stubs(:choco_version).returns(minimum_supported_version) + + resource.provider = provider + resource[:ensure] = 'enabled' + end + + it "should be an instance of Puppet::Type::Chocolateyfeature" do + resource.must be_an_instance_of Puppet::Type::Chocolateyfeature + end + + it "parameter :name should be the name var" do + resource.parameters[:name].isnamevar?.should be_truthy + end + + context "parameter :name" do + let (:param_symbol) { :name } + + it "should accept any string value" do + resource[param_symbol] = 'value' + resource[param_symbol] = "c:/thisstring-location/value/somefile.txt" + resource[param_symbol] = "c:\\thisstring-location\\value\\somefile.txt" + end + end + + context "param :ensure" do + it "should accept 'enabled'" do + resource[:ensure] = 'enabled' + end + + it "should accept enabled" do + resource[:ensure] = :enabled + end + + it "should accept 'disabled'" do + resource[:ensure] = 'disabled' + end + + it "should accept :disabled" do + resource[:ensure] = :disabled + end + + it "should reject any other value" do + expect { + resource[:ensure] = :whenever + }.to raise_error(Puppet::Error, /Invalid value :whenever. Valid values are/) + end + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/type/chocolateysource_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/type/chocolateysource_spec.rb new file mode 100644 index 000000000..8f38df958 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet/type/chocolateysource_spec.rb @@ -0,0 +1,129 @@ +require 'spec_helper' +require 'puppet/type/chocolateysource' + +describe Puppet::Type.type(:chocolateysource) do + let(:resource) { Puppet::Type.type(:chocolateysource).new(:name => 'source', :location => 'c:\packages') } + let(:provider) { Puppet::Provider.new(resource) } + let(:catalog) { Puppet::Resource::Catalog.new } + let (:minimum_supported_version) {'0.9.9.0'} + + before :each do + PuppetX::Chocolatey::ChocolateyCommon.stubs(:choco_version).returns(minimum_supported_version) + + resource.provider = provider + end + + it "should be an instance of Puppet::Type::Chocolateysource" do + resource.must be_an_instance_of Puppet::Type::Chocolateysource + end + + it "parameter :name should be the name var" do + resource.parameters[:name].isnamevar?.should be_truthy + end + + #string values + ['name','location','user','password'].each do |param| + context "parameter :#{param}" do + let (:param_symbol) { param.to_sym } + + it "should accept any string value" do + resource[param_symbol] = 'value' + resource[param_symbol] = "c:/thisstring-location/value/somefile.txt" + resource[param_symbol] = "c:\\thisstring-location\\value\\somefile.txt" + end + end + end + + #numeric values + ['priority'].each do |param| + context "parameter :#{param}" do + let (:param_symbol) { param.to_sym } + + it "should accept any numeric value" do + resource[param_symbol] = 0 + resource[param_symbol] = 10 + end + + it "should accept any string that represents a numeric value" do + resource[param_symbol] = '1' + resource[param_symbol] = '0' + end + + it "should not accept other string values" do + expect { + resource[param_symbol] = 'value' + }.to raise_error(Puppet::Error, /An integer is necessary for #{param}/) + end + + it "should not accept symbol values" do + expect { + resource[param_symbol] = :whenever + }.to raise_error(Puppet::Error, /An integer is necessary for #{param}/) + end + end + end + + context "param :ensure" do + it "should accept 'present'" do + resource[:ensure] = 'present' + end + + it "should accept present" do + resource[:ensure] = :present + end + + it "should accept :disabled" do + resource[:ensure] = :disabled + end + + it "should accept absent" do + resource[:ensure] = :absent + end + + it "should reject any other value" do + expect { + resource[:ensure] = :whenever + }.to raise_error(Puppet::Error, /Invalid value :whenever. Valid values are/) + end + end + + it "should autorequire Exec[install_chocolatey_official] when in the catalog" do + exec = Puppet::Type.type(:exec).new(:name => "install_chocolatey_official", :path => "nope") + catalog.add_resource resource + catalog.add_resource exec + + reqs = resource.autorequire + reqs.count.must == 1 + reqs[0].source.must == exec + reqs[0].target.must == resource + end + + context ".validate" do + it "should pass when both user/password are empty" do + resource.validate + end + + it "should pass when both user/password have a value" do + resource[:user] = 'tim' + resource[:password] = 'tim' + + resource.validate + end + + it "should fail when user has a value but password does not" do + resource[:user] = 'tim' + + expect { + resource.validate + }.to raise_error(ArgumentError, /you must specify both values/) + end + + it "should fail when password has a value but user does not" do + resource[:password] = 'tim' + + expect { + resource.validate + }.to raise_error(ArgumentError, /you must specify both values/) + end + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet_x/chocolatey/chocolatey_common_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet_x/chocolatey/chocolatey_common_spec.rb new file mode 100644 index 000000000..9e0aece4a --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet_x/chocolatey/chocolatey_common_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' +require 'puppet_x/chocolatey/chocolatey_install' +require 'puppet_x/chocolatey/chocolatey_common' + +describe 'Chocolatey Common' do + + let (:first_compiled_choco_version) {'0.9.9.0'} + let (:newer_choco_version) {'0.9.10.0'} + let (:last_posh_choco_version) {'0.9.8.33'} + + before :each do + PuppetX::Chocolatey::ChocolateyCommon.stubs(:set_env_chocolateyinstall) + end + + context ".chocolatey_command" do + it "should find chocolatey install location based on PuppetX::Chocolatey::ChocolateyInstall", :if => Puppet.features.microsoft_windows? do + PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns('c:\dude') + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with('c:\dude\bin\choco.exe').returns(true) + + PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command.should == 'c:\dude\bin\choco.exe' + end + + it "should find chocolatey install location based on default location", :if => Puppet.features.microsoft_windows? do + PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns('c:\dude') + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with('c:\dude\bin\choco.exe').returns(false) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with('C:\ProgramData\chocolatey\bin\choco.exe').returns(false) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with('C:\Chocolatey\bin\choco.exe').returns(false) + + PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command.should == "#{ENV['ALLUSERSPROFILE']}\\chocolatey\\bin\\choco.exe" + end + end + + context ".choco_version" do + it "should return PuppetX::Chocolatey::ChocolateyVersion.version" do + expected = '0.9.9.0.1' + PuppetX::Chocolatey::ChocolateyVersion.expects(:version).returns(expected) + PuppetX::Chocolatey::ChocolateyCommon.clear_cached_values + + PuppetX::Chocolatey::ChocolateyCommon.choco_version.must eq expected + end + end + + context ".choco_config_file" do + let (:choco_install_loc) { 'c:\dude' } + + it "should return the normal config file location when found" do + expected = 'c:\dude\config\chocolatey.config' + PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns(choco_install_loc) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(expected).returns(true) + + PuppetX::Chocolatey::ChocolateyCommon.choco_config_file.must eq expected + end + + it "should return the old config file location for older installs" do + expected = 'c:\dude\chocolateyinstall\chocolatey.config' + PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns(choco_install_loc) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with('c:\dude\config\chocolatey.config').returns(false) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(expected).returns(true) + + PuppetX::Chocolatey::ChocolateyCommon.choco_config_file.must eq expected + end + + it "should return nil when the config cannot be found" do + PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns(choco_install_loc) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with('c:\dude\config\chocolatey.config').returns(false) + PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with('c:\dude\chocolateyinstall\chocolatey.config').returns(false) + + PuppetX::Chocolatey::ChocolateyCommon.choco_config_file.must be_nil + end + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet_x/chocolatey/chocolatey_install_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet_x/chocolatey/chocolatey_install_spec.rb new file mode 100644 index 000000000..171438308 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet_x/chocolatey/chocolatey_install_spec.rb @@ -0,0 +1,52 @@ +require 'spec_helper' +require 'puppet_x/chocolatey/chocolatey_install' + +describe 'Chocolatey Install Location' do + + context 'on Windows', :if => Puppet::Util::Platform.windows? do + + it "should return install path from registry if it exists" do + expected_value = 'C:\somewhere' + Win32::Registry.any_instance.expects(:[]).with('ChocolateyInstall').returns(expected_value) + + PuppetX::Chocolatey::ChocolateyInstall.install_path.must == expected_value + end + + it "should return the environment variable ChocolateyInstall if it exists" do + Win32::Registry.any_instance.expects(:[]).with('ChocolateyInstall').raises(Win32::Registry::Error.new(2), 'file not found yo') + + # this is a placeholder, it is already set in spec_helper + ENV['ChocolateyInstall'] = 'c:\blah' + + PuppetX::Chocolatey::ChocolateyInstall.install_path.must == 'c:\blah' + end + + it "should return nil if the environment variable does not exist" do + Win32::Registry.any_instance.expects(:[]).with('ChocolateyInstall').raises(Win32::Registry::Error.new(2), 'file not found yo') + ENV['ChocolateyInstall'] = nil + + PuppetX::Chocolatey::ChocolateyInstall.install_path.must be_nil + end + end + + context 'on Linux', :if => Puppet.features.posix? do + it "should return the environment variable ChocolateyInstall if it exists" do + # this is a placeholder, it is already set in spec_helper + ENV['ChocolateyInstall'] = 'c:\blah' + + PuppetX::Chocolatey::ChocolateyInstall.install_path.must == 'c:\blah' + end + + it "should return nil if the ChocolateyInstall variable does not exist" do + ENV['ChocolateyInstall'] = nil + + PuppetX::Chocolatey::ChocolateyInstall.install_path.must be_nil + end + end + + after :each do + # setting the values back + ENV['ChocolateyInstall'] = 'c:\blah' + end + +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet_x/chocolatey/chocolatey_version_spec.rb b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet_x/chocolatey/chocolatey_version_spec.rb new file mode 100644 index 000000000..57e5618c7 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/spec/unit/puppet_x/chocolatey/chocolatey_version_spec.rb @@ -0,0 +1,81 @@ +require 'spec_helper' +require 'puppet_x/chocolatey/chocolatey_version' + +describe 'Chocolatey Version' do + + context 'on Windows', :if => Puppet::Util::Platform.windows? do + + context "when Chocolatey is installed" do + before :each do + PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns('c:\dude') + File.expects(:exist?).with('c:\dude\bin\choco.exe').returns(true) + end + + it "should return the value from running choco -v" do + expected_value = '1.2.3' + Puppet::Util::Execution.expects(:execute).returns(expected_value) + + PuppetX::Chocolatey::ChocolateyVersion.version.must == expected_value + end + + it "should handle cleaning up spaces" do + expected_value = '1.2.3' + Puppet::Util::Execution.expects(:execute).returns(' ' + expected_value + ' ') + + PuppetX::Chocolatey::ChocolateyVersion.version.must == expected_value + end + + it "should handle older versions of choco" do + expected_value = '1.2.3' + Puppet::Util::Execution.expects(:execute).returns('Please run chocolatey /? or chocolatey help - chocolatey v' + expected_value) + + PuppetX::Chocolatey::ChocolateyVersion.version.must == expected_value + end + + it "should handle other messages that return with version call" do + expected_value = '1.2.3' + Puppet::Util::Execution.expects(:execute).returns("Error setting some value.\nPlease set this value yourself\r\nsound good?\r" + expected_value) + + PuppetX::Chocolatey::ChocolateyVersion.version.must == expected_value + end + + it "should handle a trailing line break" do + expected_value = '1.2.3' + Puppet::Util::Execution.expects(:execute).returns(expected_value + "\r\n") + + PuppetX::Chocolatey::ChocolateyVersion.version.must == expected_value + end + + it "should handle 0.9.8.33 of choco" do + expected_value = '1.2.3' + Puppet::Util::Execution.expects(:execute).returns('!!ATTENTION!! +The next version of Chocolatey (v0.9.9) will require -y to perform + behaviors that change state without prompting for confirmation. Start + using it now in your automated scripts. + + For details on the all new Chocolatey, visit http://bit.ly/new_choco +Please run chocolatey /? or chocolatey help - chocolatey v' + expected_value) + + PuppetX::Chocolatey::ChocolateyVersion.version.must == expected_value + end + end + + context "When Chocolatey is not installed" do + before :each do + PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns(nil) + File.expects(:exist?).with('\bin\choco.exe').returns(false) + end + + it "should return nil" do + PuppetX::Chocolatey::ChocolateyVersion.version.must be_nil + end + end + + end + + context 'on Linux', :if => Puppet.features.posix? do + it "should return nil on a non-windows system" do + PuppetX::Chocolatey::ChocolateyVersion.version.must be_nil + end + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/templates/InstallChocolatey.ps1.erb b/modules/utilities/windows/repository_managers/chocolatey/templates/InstallChocolatey.ps1.erb new file mode 100644 index 000000000..5a2bff645 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/templates/InstallChocolatey.ps1.erb @@ -0,0 +1,151 @@ +# ============================================================================== +# Copyright 2011 - Present RealDimensions Software, LLC +# +# 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. +# ============================================================================== + +$ErrorActionPreference = 'Stop' + +# For some reason try/catch wrapping only ensures +# that none of this script runs at all +# https://tickets.puppetlabs.com/browse/MODULES-2634 +#try { + +# variables +$url = '<%= @download_url %>' +$unzipMethod = '<%= @unzip_type %>' +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)) {[System.IO.Directory]::CreateDirectory($tempDir)} +$file = Join-Path $tempDir "chocolatey.zip" +$chocErrorLog = Join-Path $tempDir "chocError.log" + +# 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." + +# This only works with the ConsoleHost (PowerShell InternalHost) +function Fix-PowerShellOutputRedirectionBug { + 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. Error: $_" + } +} + +Fix-PowerShellOutputRedirectionBug + +# This should help when certain organizations have issues installing Chocolatey +# 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 and/or (2) specify internal Chocolatey package location (see https://forge.puppet.com/puppetlabs/chocolatey#manage-chocolatey-installation)." +} + +function Download-File { +param ( + [string]$url, + [string]$file + ) + Write-Output "Downloading $url to $file" + $downloader = new-object System.Net.WebClient + $downloader.Proxy.Credentials=[System.Net.CredentialCache]::DefaultNetworkCredentials; + $downloader.DownloadFile($url, $file) +} + +# download the package +Download-File $url $file + +if ($unzipMethod -eq '7zip') { + # download 7zip + Write-Output "Download 7Zip commandline tool" + $7zaExe = Join-Path $tempDir '7za.exe' + + Download-File 'https://chocolatey.org/7za.exe' "$7zaExe" + + # unzip the package + Write-Output "Extracting $file to $tempDir..." + Start-Process "$7zaExe" -ArgumentList "x -o`"$tempDir`" -y `"$file`"" -Wait -NoNewWindow +} else { + if ($PSVersionTable.PSVersion.Major -lt 5) { + $shellApplication = new-object -com shell.application + $zipPackage = $shellApplication.NameSpace($file) + $destinationFolder = $shellApplication.NameSpace($tempDir) + $destinationFolder.CopyHere($zipPackage.Items(),0x10) + } else { + Expand-Archive -Path "$file" -DestinationPath "$tempDir" -Force | Out-Null + } +} + +# call chocolatey install +Write-Output "Installing chocolatey on this machine" +$toolsFolder = Join-Path $tempDir "tools" +$chocInstallPS1 = Join-Path $toolsFolder "chocolateyInstall.ps1" + +if ($PSVersionTable.PSVersion.Major -gt 2) { + & $chocInstallPS1 +} else { + $output = Invoke-Expression $chocInstallPS1 + $output + Write-Output "Any errors that occured during install or upgrade are logged here: $chocoErrorLog" + $error | out-file $chocErrorLog +} + +Write-Output 'Ensuring chocolatey commands are on the path' +$chocInstallVariableName = "ChocolateyInstall" +$chocoPath = [Environment]::GetEnvironmentVariable($chocInstallVariableName, [System.EnvironmentVariableTarget]::User) +if ($chocoPath -eq $null -or $chocoPath -eq '') { + $chocoPath = 'C:\ProgramData\Chocolatey' +} + +$chocoBinPath = Join-Path $chocoPath 'bin' + +if ($($env:Path).ToLower().Contains($($chocoBinPath).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 + +#} +#catch +#{ +# Write-Host "$($_.Exception.Message)" +# exit 1 +#} diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/pre-suite/00_pe_install.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/pre-suite/00_pe_install.rb new file mode 100644 index 000000000..40bcd4bea --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/pre-suite/00_pe_install.rb @@ -0,0 +1,20 @@ +require 'master_manipulator' +test_name 'MODULES-3138 - C48 - Install Puppet Enterprise' + +# Check for a master before continuing +if master == nil + fail_test("Master is not set, are you using a host configuration that has a master?") +end + +# Init +step 'Install PE' +install_pe + +step 'Disable Node Classifier' +disable_node_classifier(master) + +step 'Disable Environment Caching' +disable_env_cache(master) + +step 'Restart Puppet Server' +restart_puppet_server(master) diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/pre-suite/01_chocolatey_module.install.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/pre-suite/01_chocolatey_module.install.rb new file mode 100644 index 000000000..efccc025b --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/pre-suite/01_chocolatey_module.install.rb @@ -0,0 +1,25 @@ +test_name 'MODULES-3138 - C97814 - Install Pre-suite Acceptance Test' + +# Beaker option set if "BEAKER_FORGE_HOST" environment variable is present +staging = { :module_name => 'puppetlabs-chocolatey' } +if options[:forge_host] + # Check to see if module version is specified. + staging[:version] = ENV['MODULE_VERSION'] if ENV['MODULE_VERSION'] + step 'Install Chocolatey Module from Forge' + install_dev_puppet_module_on(master, staging) +else + step 'Install Chocolatey Module Dependencies' + %w(puppetlabs-stdlib puppetlabs-powershell badgerious/windows_env).each do |dep| + on(master, puppet("module install #{dep}")) + end +end + +step 'Install Chocolatey Module' +proj_root = File.expand_path(File.join(File.dirname(__FILE__), '../../../')) +local = { :module_name => 'chocolatey', :source => proj_root} + +# Check to see if module version is specified. +staging[:version] = ENV['MODULE_VERSION'] if ENV['MODULE_VERSION'] + +# in CI install from staging forge, otherwise from local +install_dev_puppet_module_on(master, local) diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/pre-suite/02_chocolatey_application_install.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/pre-suite/02_chocolatey_application_install.rb new file mode 100644 index 000000000..782d130ee --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/pre-suite/02_chocolatey_application_install.rb @@ -0,0 +1,47 @@ +require 'master_manipulator' +require 'chocolatey_helper' +test_name 'MODULES-3043 - C97739 - Install Client on Virgin System' + +chocolatey_pp = < 'file:///C:/chocolatey.nupkg', + use_7zip => false, + } +MANIFEST + +chocoVersion = /[0-9]+[\d'.']*/ + +# Setup +step 'Inject "site.pp" on Master' +site_pp = create_site_pp(master, :manifest => chocolatey_pp) +inject_site_pp(master, get_site_pp_path(master), site_pp) + +#Test +confine_block(:to, :platform => 'windows') do + + agents.each do |agent| + opts = { + :acceptable_exit_codes => [0, 2] + } + + url = get_latest_chocholatey_download_url + + step 'Download chocolatey nuget package' do + curl_on(agent, "#{url} > C:/chocolatey.nupkg") + end + + step 'should apply chocolatey manifest and install choco.exe' do + on(agent, puppet('agent -t --environment production'), opts) do |result| + assert_no_match(/Error:/, result.stderr, 'Unexpected error was detected!') + end + end + + step 'should have valid version of Chocolatey' do + on(agent, 'C:/ProgramData/chocolatey/bin/choco.exe -v', :acceptable_exit_codes => 0) do |result| + assert_match(chocoVersion, result.stdout, 'Expected: ' + chocoVersion.to_s + ' but got ' + result.stdout) + end + end + + end + +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/tests/hello.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/tests/hello.rb new file mode 100644 index 000000000..682072efb --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/acceptance/tests/hello.rb @@ -0,0 +1,7 @@ +test_name "Hello Test" + +step "Say Hello" + +hosts.each do |host| + on(host, "echo hello!") +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/configs/.gitignore b/modules/utilities/windows/repository_managers/chocolatey/tests/configs/.gitignore new file mode 100644 index 000000000..f67aa100f --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/configs/.gitignore @@ -0,0 +1,3 @@ +# Ignore all configs in this directory, they will be created by beaker-hostgenerator +* +!.gitignore diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/lib/chocolatey_helper.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/lib/chocolatey_helper.rb new file mode 100644 index 000000000..742de3fcd --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/lib/chocolatey_helper.rb @@ -0,0 +1,50 @@ +require 'net/http' +require 'uri' +require 'nokogiri' + +$chocolatey_latest_info_url = "http://nexus.delivery.puppetlabs.net/service/local/nuget/choco-pipeline-tests/Packages()?$filter=((Id%20eq%20%27chocolatey%27)%20and%20(not%20IsPrerelease))%20and%20IsLatestVersion" + +# Extract the url for the latest Puppet hosted version of Chocolatey +# +# ==== Returns +# +# +string+ - url from the feed/content->src of the $chocolatey_latest_info_url +# +# ==== Raises +# +# URI::InvalidURIError +# +# ==== Examples +# +# url = get_latest_chocholatey_download_url; + +def get_latest_chocholatey_download_url() + uri = URI.parse($chocolatey_latest_info_url) + + response = Net::HTTP.get_response(uri) + xml_str = Nokogiri::XML(response.body) + + src_url = xml_str.css('//feed//content').attr('src') + + return src_url +end + +def config_file_location + 'c:\\ProgramData\\chocolatey\\config\\chocolatey.config' +end + +def backup_config + step 'Backup default configuration file' + on(agents, "cmd.exe /c \"copy #{config_file_location} #{config_file_location}.bkp\"") +end + +def reset_config + step 'Reset configuration file to default' + on(agents, "cmd.exe /c \"move #{config_file_location}.bkp #{config_file_location}\"") +end + +def get_xml_value(xpath, file_text) + doc = Nokogiri::XML(file_text) + + doc.xpath(xpath) +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/00_install_certs.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/00_install_certs.rb new file mode 100644 index 000000000..bdcf8b99a --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/00_install_certs.rb @@ -0,0 +1,93 @@ +test_name "Install CA Certs" +confine(:to, :platform => 'windows') + +GEOTRUST_GLOBAL_CA = <<-EOM +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +-----END CERTIFICATE----- +EOM + +USERTRUST_NETWORK_CA = <<-EOM +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB +lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt +SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG +A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe +MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v +d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh +cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn +0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ +M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a +MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd +oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI +DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy +oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 +dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy +bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF +BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM +//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli +CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE +CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t +3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS +KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== +-----END CERTIFICATE----- +EOM + +EQUIFAX_CA = <<-EOM +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV +UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy +dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 +MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx +dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f +BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A +cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC +AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm +aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw +ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj +IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF +MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA +A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y +7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh +1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 +-----END CERTIFICATE----- +EOM + +hosts.each do |host| + step "Installing Geotrust CA cert" + create_remote_file(host, "geotrustglobal.pem", GEOTRUST_GLOBAL_CA) + on host, "chmod 644 geotrustglobal.pem" + on host, "cmd /c certutil -v -addstore Root `cygpath -w geotrustglobal.pem`" + + step "Installing Usertrust Network CA cert" + create_remote_file(host, "usertrust-network.pem", USERTRUST_NETWORK_CA) + on host, "chmod 644 usertrust-network.pem" + on host, "cmd /c certutil -v -addstore Root `cygpath -w usertrust-network.pem`" + + step "Installing Equifax CA cert" + create_remote_file(host, "equifax.pem", EQUIFAX_CA) + on host, "chmod 644 equifax.pem" + on host, "cmd /c certutil -v -addstore Root `cygpath -w equifax.pem`" +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/01_puppet_agent_install.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/01_puppet_agent_install.rb new file mode 100644 index 000000000..774ff4541 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/01_puppet_agent_install.rb @@ -0,0 +1,13 @@ +test_name 'Install Puppet Agent' + +confine(:to, :platform => 'windows') + +step 'Install Puppet Agent' +if ENV['BEAKER_PUPPET_AGENT_VERSION'] + install_puppet_agent_on(agents, :version => ENV['BEAKER_PUPPET_AGENT_VERSION']) +else + install_puppet_agent_on(agents) +end + +step 'Prevent Puppet Service from Running' +on(agents, puppet('resource service puppet ensure=stopped enable=false')) diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/02_chocolatey_module_install.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/02_chocolatey_module_install.rb new file mode 100644 index 000000000..ffe350b2e --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/02_chocolatey_module_install.rb @@ -0,0 +1,27 @@ +test_name 'MODULES-3138 - C97813 - Install Pre-suite Reference Test' + +confine(:to, :platform => 'windows') + +# Init +proj_root = File.expand_path(File.join(File.dirname(__FILE__), '../../../')) + +staging = { :module_name => 'puppetlabs-chocolatey' } +local = { :module_name => 'chocolatey', :source => proj_root } + +# Beaker option set if "BEAKER_FORGE_HOST" environment variable is present +agents.each do |agent| + if options[:forge_host] + # Check to see if module version is specified. + staging[:version] = ENV['MODULE_VERSION'] if ENV['MODULE_VERSION'] + step 'Install Chocolatey Module from Forge' + install_dev_puppet_module_on(agent, staging) + else + step 'Install Chocolatey Module Dependencies' + %w(puppetlabs-stdlib puppetlabs-powershell badgerious/windows_env).each do |dep| + on(agent, puppet("module install #{dep}")) + end + step 'Install Chocolatey Module from Local Source' + # in CI install from staging forge, otherwise from local + install_dev_puppet_module_on(agent, local) + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/03_chocolatey_application_install.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/03_chocolatey_application_install.rb new file mode 100644 index 000000000..9ca358d80 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/pre-suite/03_chocolatey_application_install.rb @@ -0,0 +1,39 @@ +require 'chocolatey_helper' + +test_name 'MODULES-3043 - C97739 - Install Client on Virgin System' + +confine(:to, :platform => 'windows') + +chocolatey_pp = < 'file:///C:/chocolatey.nupkg', + use_7zip => false, + } +MANIFEST + + +chocoVersion = /[0-9]+[\d'.']*/ + +agents.each do |agent| + opts = { + :acceptable_exit_codes => [0, 2] + } + + url = get_latest_chocholatey_download_url; + + step 'Download chocolatey nuget package' do + curl_on(agent, "#{url} > C:/chocolatey.nupkg") + end + + step 'should apply chocolatey manifest and install choco.exe' do + apply_manifest_on(agent, chocolatey_pp, opts) do |result| + assert_no_match(/Error:/, result.stderr, 'Unexpected error was detected!') + end + end + + step 'should have valid version of Chocolatey' do + on(agent, 'C:/ProgramData/chocolatey/bin/choco.exe -v', :acceptable_exit_codes => 0) do |result| + assert_match(chocoVersion, result.stdout, 'Expected: ' + chocoVersion.to_s + ' but got ' + result.stdout) + end + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/add_new_config_item.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/add_new_config_item.rb new file mode 100644 index 000000000..a4446b4d9 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/add_new_config_item.rb @@ -0,0 +1,29 @@ +require 'chocolatey_helper' +test_name 'MODULES-3035 - Add New Config Item' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateyconfig {'hello123': + ensure => present, + value => 'this guy', + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/this guy/, get_xml_value("//config/add[@key='hello123']/@value", result.output).to_s, 'Value did not match') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/add_value_to_existing_config.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/add_value_to_existing_config.rb new file mode 100644 index 000000000..4e707d99c --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/add_value_to_existing_config.rb @@ -0,0 +1,29 @@ +require 'chocolatey_helper' +test_name 'MODULES-3035 - Add a Value to an Existing Config Setting' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateyconfig {'proxy': + ensure => present, + value => 'https://somewhere', + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/https\:\/\/somewhere/, get_xml_value("//config/add[@key='proxy']/@value", result.output).to_s, 'Value did not match') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/change_config_value.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/change_config_value.rb new file mode 100644 index 000000000..f08b34305 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/change_config_value.rb @@ -0,0 +1,46 @@ +require 'chocolatey_helper' +test_name 'MODULES-3035 - Config Settings Change Config Value' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateyconfig {'proxyUser': + value => 'bob', + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest to setup' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify setup' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/bob/, get_xml_value("//config/add[@key='proxyUser']/@value", result.output).to_s, 'Value did not match') + end +end + +# arrange +chocolatey_src_change = <<-PP + chocolateyconfig {'proxyuser': + value => 'tim', + } +PP + +# act +step 'Apply manifest to change config setting' +apply_manifest(chocolatey_src_change, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/tim/, get_xml_value("//config/add[@key='proxyUser']/@value", result.output).to_s, 'Value did not change') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/ensure_config_value_with_password_in_name.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/ensure_config_value_with_password_in_name.rb new file mode 100644 index 000000000..e9dbd294a --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/ensure_config_value_with_password_in_name.rb @@ -0,0 +1,50 @@ +require 'chocolatey_helper' +test_name 'MODULES-3035 - Ensure Config Value with Password In Name' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateyconfig {'proxypassword': + value => 'secrect', + } +PP + +# teardown +teardown do + reset_config +end + +password = '' + +# act +step 'Apply manifest to setup proxyPassword' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify setup' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + password = get_xml_value("//config/add[@key='proxyPassword']/@value", result.output).to_s + assert_match(/.+/, password, 'Value did not match') + end +end + +# arrange +chocolatey_src_change = <<-PP + chocolateyconfig {'proxypassword': + value => 'secrect2', + } +PP + +# act +step 'Apply manifest to attempt to change proxyPassword - should have no effect' +apply_manifest(chocolatey_src_change, :catch_failures => true) + +step 'Verify results' +# should have no effect +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(password, get_xml_value("//config/add[@key='proxyPassword']/@value", result.output).to_s, 'Value should not have changed') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/fail_to_appy_bad_manifest.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/fail_to_appy_bad_manifest.rb new file mode 100644 index 000000000..a11080a10 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/fail_to_appy_bad_manifest.rb @@ -0,0 +1,25 @@ +require 'chocolatey_helper' +test_name 'MODULES-3035 - Fail to Apply Bad Manifest' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateyconfig {'bob': + ensure => sad, + value => 'yes', + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply Manifest' +apply_manifest(chocolatey_src, :expect_failures => true) do + step 'Verify Failure' + assert_match(/Error: Parameter ensure failed on Chocolateyconfig\[bob\]: Invalid value "sad"/, stderr, "stderr did not match expected") +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/fail_to_set_present_without_value.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/fail_to_set_present_without_value.rb new file mode 100644 index 000000000..6d65dc5fa --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/fail_to_set_present_without_value.rb @@ -0,0 +1,24 @@ +require 'chocolatey_helper' +test_name 'MODULES-3035 - Fail to Set Present With No Value' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateyconfig {'bob': + ensure => present, + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply Manifest' +apply_manifest(chocolatey_src, :expect_failures => true) do + step 'Verify Failure' + assert_match(/Error: Validation of Chocolateyconfig\[bob\] failed: Unless ensure => absent, value is required/, stderr, "stderr did not match expected") +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/remove_config_value_with_password_in_name.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/remove_config_value_with_password_in_name.rb new file mode 100644 index 000000000..84b1f35a6 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/remove_config_value_with_password_in_name.rb @@ -0,0 +1,50 @@ +require 'chocolatey_helper' +test_name 'MODULES-3035 - Config Settings Remove Value with Password in Name' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateyconfig {'proxypassword': + value => 'secrect', + } +PP + +# teardown +teardown do + reset_config +end + +password = '' + +# act +step 'Apply manifest to setup proxyPassword' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify setup' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + password = get_xml_value("//config/add[@key='proxyPassword']/@value", result.output).to_s + assert_match(/.+/, password, 'Value did not match') + end +end + +# arrange +chocolatey_src_change = <<-PP + chocolateyconfig {'proxypassword': + ensure => absent, + } +PP + +# act +step 'Apply manifest to remove proxyPassword' +apply_manifest(chocolatey_src_change, :catch_failures => true) + +step 'Verify results' +# should have no effect +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_not_match(/.+/, get_xml_value("//config/add[@key='proxyPassword']/@value", result.output).to_s, 'Value should have been removed') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/remove_value_from_config.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/remove_value_from_config.rb new file mode 100644 index 000000000..6bebb8d4a --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyconfig/remove_value_from_config.rb @@ -0,0 +1,28 @@ +require 'chocolatey_helper' +test_name 'MODULES-3035 - Remove Value From Config Setting' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateyconfig {'commandExecutionTimeoutSeconds': + ensure => absent, + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_not_match(/.+/, get_xml_value("//config/add[@key='commandExecutionTimeoutSeconds']/@value", result.output).to_s, 'Value did not match') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/disable_disabled_feature.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/disable_disabled_feature.rb new file mode 100644 index 000000000..80dbd9d7b --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/disable_disabled_feature.rb @@ -0,0 +1,35 @@ +require 'chocolatey_helper' +test_name 'MODULES-3034 - Disable an Already Disabled Feature' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateyfeature {'failOnAutoUninstaller': + ensure => disabled, + } +PP + +# teardown +teardown do + reset_config +end + +# verify prior +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/false/, get_xml_value("//features/feature[@name='failOnAutoUninstaller']/@enabled", result.output).to_s, 'Was not disabled by default, please adjust test to find another value.') + end +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/false/, get_xml_value("//features/feature[@name='failOnAutoUninstaller']/@enabled", result.output).to_s, 'Was not found disabled') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/disable_enabled_feature.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/disable_enabled_feature.rb new file mode 100644 index 000000000..e2ae3e515 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/disable_enabled_feature.rb @@ -0,0 +1,35 @@ +require 'chocolatey_helper' +test_name 'MODULES-3034 - Disable an Enabled Feature' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateyfeature {'checksumFiles': + ensure => disabled, + } +PP + +# teardown +teardown do + reset_config +end + +#verify prior +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/true/, get_xml_value("//features/feature[@name='checksumFiles']/@enabled", result.output).to_s, 'Was not enabled by default, please adjust test to find another value.') + end +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/false/, get_xml_value("//features/feature[@name='checksumFiles']/@enabled", result.output).to_s, 'Was not found disabled') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/enable_disabled_feature.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/enable_disabled_feature.rb new file mode 100644 index 000000000..95c2730c4 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/enable_disabled_feature.rb @@ -0,0 +1,35 @@ +require 'chocolatey_helper' +test_name 'MODULES-3034 - Enable a Disabled Feature' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateyfeature {'failOnAutoUninstaller': + ensure => enabled, + } +PP + +# teardown +teardown do + reset_config +end + +# verify prior +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/false/, get_xml_value("//features/feature[@name='failOnAutoUninstaller']/@enabled", result.output).to_s, 'Was not disabled by default, please adjust test to find another value.') + end +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/true/, get_xml_value("//features/feature[@name='failOnAutoUninstaller']/@enabled", result.output).to_s, 'Was not found enabled') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/enable_enabled_feature.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/enable_enabled_feature.rb new file mode 100644 index 000000000..9928ccc1b --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/enable_enabled_feature.rb @@ -0,0 +1,35 @@ +require 'chocolatey_helper' +test_name 'MODULES-3034 - Enable Already Enabled Feature' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateyfeature {'checksumFiles': + ensure => enabled, + } +PP + +# teardown +teardown do + reset_config +end + +#verify prior +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/true/, get_xml_value("//features/feature[@name='checksumFiles']/@enabled", result.output).to_s, 'Was not enabled by default, please adjust test to find another value.') + end +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/true/, get_xml_value("//features/feature[@name='checksumFiles']/@enabled", result.output).to_s, 'Was not found enabled') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/fail_to_enable_nonexistent_feature.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/fail_to_enable_nonexistent_feature.rb new file mode 100644 index 000000000..05367d19b --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/fail_to_enable_nonexistent_feature.rb @@ -0,0 +1,24 @@ +require 'chocolatey_helper' +test_name 'MODULES-3034 - Enable non-existent feature' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateyfeature {'idontexistfeature123123': + ensure => enabled, + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :expect_failures => true) do + step 'Verify Failure' + assert_match(/returned 1: Feature 'idontexistfeature123123' not found/, stderr, "stderr did not match expected") +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/fail_to_remove_feature.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/fail_to_remove_feature.rb new file mode 100644 index 000000000..b7be83f30 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateyfeature/fail_to_remove_feature.rb @@ -0,0 +1,25 @@ +require 'chocolatey_helper' +test_name 'MODULES-3034 - Attempt to remove feature' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateyfeature {'checksumFiles': + ensure => absent, + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :expect_failures => true) do + step 'Verify Failure' + assert_match(/Error: Parameter ensure failed on Chocolateyfeature\[checksumFiles\]: Invalid value \"absent\"/, stderr, "stderr did not match expected") +end + diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateypackage/install_and_remove_good_package.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateypackage/install_and_remove_good_package.rb new file mode 100644 index 000000000..654b3bfb5 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateypackage/install_and_remove_good_package.rb @@ -0,0 +1,62 @@ +require 'chocolatey_helper' +require 'beaker-windows' +test_name 'MODULES-3037 - 97729 Install known good package via manifest and remove via manifest' +confine(:to, :platform => 'windows') + +# arrange +package_name = 'vlc' +package_exe_path = %{C:\\'Program Files\\VideoLAN\\VLC\\vlc.exe'} +software_uninstall_command = %{cmd.exe /C C:\\'Program Files\\VideoLAN\\VLC\\uninstall.exe' /S} + +chocolatey_package_manifest = <<-PP + package { "#{package_name}": + ensure => present, + provider => chocolatey, + source => 'http://nexus.delivery.puppetlabs.net/service/local/nuget/choco-pipeline-tests/' + } +PP + +# teardown +teardown do + on(agent, exec_ps_cmd("test-path #{package_exe_path}")) do |result| + if (result.output =~ /True/i) + retry_on(agent, exec_ps_cmd(software_uninstall_command)) + end + end + #TODO: should we validate that the software was removed successfully here? +end + +#validate +step "should not have valid version of #{package_name}" +on(agent, exec_ps_cmd("test-path #{package_exe_path}")) do |result| + assert_match(/False/i, result.output, "#{package_name} was present before application of manifest.") +end + + +#act +step 'Apply manifest' +apply_manifest(chocolatey_package_manifest, :catch_failures => true) do |result| + assert_match(/Notice\: \/Stage\[main\]\/Main\/Package\[#{package_name}\]\/ensure\: created/, result.stdout, "stdout did not report package creation of #{package_name}") +end + +#validate +step "should have valid version of #{package_name}" +on(agent, exec_ps_cmd("test-path #{package_exe_path}")) do |result| + assert_match(/True/i, result.output, "#{package_name} was not present after application of manifest.") +end + +#arrange +chocolatey_package_manifest = <<-PP + package { "#{package_name}": + ensure => absent, + provider => chocolatey, + } +PP + +#act +step "Uninstall #{package_name} package via manifest" +apply_manifest(chocolatey_package_manifest, :catch_failures => true) do |result| +#validate + assert_match(/Stage\[main\]\/Main\/Package\[#{package_name}\]\/ensure\: removed/, result.stdout, "stdout did not report package removal of #{package_name}") +end + diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateypackage/install_and_remove_good_package_utf-8.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateypackage/install_and_remove_good_package_utf-8.rb new file mode 100644 index 000000000..90d01f88e --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateypackage/install_and_remove_good_package_utf-8.rb @@ -0,0 +1,65 @@ +# require 'chocolatey_helper' +# require 'beaker-windows' +# test_name 'MODULES-3037 - C97738 Install known good package with utf-8 via manifest and remove via manifest' +# confine(:to, :platform => 'windows') +# +# # arrange +# package_name = '竹ChocolateyGUIÖ' +# package_exe_path = %{C:\\'Program Files (x86)\\ChocolateyGUI\\ChocolateyGUI.exe'} +# software_uninstall_command = %{msiexec /x C:\\ProgramData\\chocolatey\\lib\\竹ChocolateyGUIÖ\\tools\\竹ChocolateyGUIÖ.msi /q}.force_encoding("ASCII-8BIT") +# +# chocolatey_package_manifest = <<-PP +# package { "#{package_name}": +# ensure => present, +# provider => chocolatey, +# source => 'http://nexus.delivery.puppetlabs.net/service/local/nuget/choco-pipeline-tests/' +# } +# PP +# +# # teardown +# teardown do +# on(agent, exec_ps_cmd("test-path #{package_exe_path}")) do |result| +# if (result.output =~ /True/i) +# on(agent, exec_ps_cmd(software_uninstall_command)) +# end +# end +# on(agent, exec_ps_cmd("test-path #{package_exe_path}")) do |result| +# assert_match(/False/i, result.output, "#{package_name} was present after uninstall.") +# end +# end +# +# #validate +# step "should not have valid version of #{package_name}" +# on(agent, exec_ps_cmd("test-path #{package_exe_path}")) do |result| +# assert_match(/False/i, result.output, "#{package_name} was present before application of manifest.") +# end +# +# +# #act +# step 'Apply manifest' +# apply_manifest(chocolatey_package_manifest, :catch_failures => true) do |result| +# assert_match(/Notice\: \/Stage\[main\]\/Main\/Package\[#{package_name}\]\/ensure\: created/, result.stdout, "stdout did not report package creation of #{package_name}") +# end +# +# #validate +# step "should have valid version of #{package_name}" +# on(agent, exec_ps_cmd("test-path #{package_exe_path}")) do |result| +# assert_match(/True/i, result.output, "#{package_name} was not present after application of manifest.") +# end +# +# #arrange +# chocolatey_package_manifest = <<-PP +# package { "#{package_name}": +# ensure => absent, +# provider => chocolatey, +# } +# PP +# +# #act +# step "Uninstall #{package_name} package via manifest" +# apply_manifest(chocolatey_package_manifest, :catch_failures => true) do |result| +# #validate +# expect_failure('Expected to fail because of MODULES-3541') do +# assert_match(/Stage\[main\]\/Main\/Package\[#{package_name}\]\/ensure\: removed/, result.stdout, "stdout did not report package removal of #{package_name}") +# end +# end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_priority_to_existing_source.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_priority_to_existing_source.rb new file mode 100644 index 000000000..98e53ae2e --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_priority_to_existing_source.rb @@ -0,0 +1,30 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Add Priority to an Existing Source' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'chocolatey': + ensure => present, + location => 'https://chocolatey.org/api/v2', + priority => 1, + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/1/, get_xml_value("//sources/source[@id='chocolatey']/@priority", result.output).to_s, 'Priority did not match') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_source_all_options.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_source_all_options.rb new file mode 100644 index 000000000..b9abee607 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_source_all_options.rb @@ -0,0 +1,36 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Add Source With All Options' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'test': + ensure => present, + location => 'c:\\packages', + priority => 2, + user => 'bob', + password => 'yes', + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/c:\\packages/, get_xml_value("//sources/source[@id='test']/@value", result.output).to_s, 'Location did not match') + assert_match(/2/, get_xml_value("//sources/source[@id='test']/@priority", result.output).to_s, 'Priority did not match') + assert_match(/bob/, get_xml_value("//sources/source[@id='test']/@user", result.output).to_s, 'User did not match') + assert_match(/.+/, get_xml_value("//sources/source[@id='test']/@password", result.output).to_s, 'Password was not saved') + assert_match(/false/, get_xml_value("//sources/source[@id='test']/@disabled", result.output).to_s, 'Disabled did not match') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_source_minimal.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_source_minimal.rb new file mode 100644 index 000000000..79f7e9df0 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_source_minimal.rb @@ -0,0 +1,29 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Add Source Minimal' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'test': + location => 'c:\\packages', + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/c:\\packages/, get_xml_value("//sources/source[@id='test']/@value", result.output).to_s, 'Location did not match') + assert_match(/false/, get_xml_value("//sources/source[@id='test']/@disabled", result.output).to_s, 'Disabled did not match') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_source_normal.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_source_normal.rb new file mode 100644 index 000000000..b7361a8e1 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_source_normal.rb @@ -0,0 +1,30 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Add Source Happy Path' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'test': + ensure => present, + location => 'c:\\packages', + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/c:\\packages/, get_xml_value("//sources/source[@id='test']/@value", result.output).to_s, 'Location did not match') + assert_match(/false/, get_xml_value("//sources/source[@id='test']/@disabled", result.output).to_s, 'Disabled did not match') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_user_pass_to_existing_source.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_user_pass_to_existing_source.rb new file mode 100644 index 000000000..7fddf95df --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/add_user_pass_to_existing_source.rb @@ -0,0 +1,33 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Add User/Password to an Existing Source' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'chocolatey': + ensure => present, + location => 'https://chocolatey.org/api/v2', + user => 'tim', + password => 'test', + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/tim/, get_xml_value("//sources/source[@id='chocolatey']/@user", result.output).to_s, 'User did not match') + # we are not able to verify password other than if it has a value - it will be encrypted in a non-verifyable way + assert_match(/.+/, get_xml_value("//sources/source[@id='chocolatey']/@password", result.output).to_s, 'Password was not saved') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/change_existing_priority.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/change_existing_priority.rb new file mode 100644 index 000000000..81e07a9e0 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/change_existing_priority.rb @@ -0,0 +1,51 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Change Existing Priority' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'chocolatey': + ensure => present, + location => 'https://chocolatey.org/api/v2', + priority => 1, + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest to set priority' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify priority setup was added' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/1/, get_xml_value("//sources/source[@id='chocolatey']/@priority", result.output).to_s, 'Priority setup did not match') + end +end + +# arrange +chocolatey_src_change = <<-PP + chocolateysource {'chocolatey': + ensure => present, + location => 'https://chocolatey.org/api/v2', + priority => 5, + } +PP + +# act +step 'Apply manifest to change priority' +apply_manifest(chocolatey_src_change, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/5/, get_xml_value("//sources/source[@id='chocolatey']/@priority", result.output).to_s, 'Priority change did not match') + end +end + diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/change_existing_source_location.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/change_existing_source_location.rb new file mode 100644 index 000000000..ca3171c7c --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/change_existing_source_location.rb @@ -0,0 +1,30 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Change Source Location for an Existing Source' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'chocolatey': + ensure => present, + location => 'c:\\packages', + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/c:\\packages/, get_xml_value("//sources/source[@id='chocolatey']/@value", result.output).to_s, 'Location did not match') + #todo should also verify there are no duplicates + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/change_user_pass.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/change_user_pass.rb new file mode 100644 index 000000000..ab23923de --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/change_user_pass.rb @@ -0,0 +1,54 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Change User/Password In an Existing Source' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'chocolatey': + ensure => present, + location => 'https://chocolatey.org/api/v2', + user => 'tim', + password => 'test', + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest to setup user/password' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify user/password setup' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/tim/, get_xml_value("//sources/source[@id='chocolatey']/@user", result.output).to_s, 'User setup did not match') + # we are not able to verify password other than if it has a value - it will be encrypted in a non-verifyable way + assert_match(/.+/, get_xml_value("//sources/source[@id='chocolatey']/@password", result.output).to_s, 'Password was not saved') + end +end + +# arrange +chocolatey_src_change = <<-PP + chocolateysource {'chocolatey': + ensure => present, + location => 'https://chocolatey.org/api/v2', + user => 'bob', + password => 'newpass', + } +PP + +# act +step 'Apply manifest to change user/password' +apply_manifest(chocolatey_src_change, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/bob/, get_xml_value("//sources/source[@id='chocolatey']/@user", result.output).to_s, 'User change did not match') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/disable_existing_source.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/disable_existing_source.rb new file mode 100644 index 000000000..1abda7a2a --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/disable_existing_source.rb @@ -0,0 +1,28 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Disable an Existing Source' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'chocolatey': + ensure => disabled, + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/true/, get_xml_value("//sources/source[@id='chocolatey']/@disabled", result.output).to_s, 'Disabled did not match') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/disable_existing_source_two_runs.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/disable_existing_source_two_runs.rb new file mode 100644 index 000000000..c8618dc46 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/disable_existing_source_two_runs.rb @@ -0,0 +1,43 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Disable an Existing Source' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'chocolatey': + ensure => disabled, + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify setup' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/true/, get_xml_value("//sources/source[@id='chocolatey']/@disabled", result.output).to_s, 'Disabled did not match') + end +end + +# act +step 'Apply manifest a second time' +apply_manifest(chocolatey_src, :catch_failures => true) do |result| + assert_not_match(/Chocolateysource\[chocolatey\]\/user\: defined 'user' as ''/, result.stdout, "User was adjusted and should not have been") +end + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/true/, get_xml_value("//sources/source[@id='chocolatey']/@disabled", result.output).to_s, 'Disabled did not match') + + end +end + diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_apply_source_without_location.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_apply_source_without_location.rb new file mode 100644 index 000000000..5a5043e8a --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_apply_source_without_location.rb @@ -0,0 +1,24 @@ +require 'chocolatey_helper' +test_name 'MODULES-3430 - Add Source Sad Path: Fail to apply manifest without location' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'chocolatey': + ensure => present, + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :expect_failures => true) do + step 'Verify failure' + assert_match(/Error: Validation of Chocolateysource\[chocolatey\] failed: A non-empty location/, stderr, "stderr did not match expected") +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_appy_bad_manifest.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_appy_bad_manifest.rb new file mode 100644 index 000000000..85d15c873 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_appy_bad_manifest.rb @@ -0,0 +1,25 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Add Source Sad Path: Fail to apply bad manifest' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'test': + ensure => sad, + location => 'c:\\packages', + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply Manifest' +apply_manifest(chocolatey_src, :expect_failures => true) do + step 'Verify Failure' + assert_match(/Error: Parameter ensure failed on Chocolateysource\[test\]: Invalid value "sad"/, stderr, "stderr did not match expected") +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_set_password_without_user.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_set_password_without_user.rb new file mode 100644 index 000000000..7648252fc --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_set_password_without_user.rb @@ -0,0 +1,26 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Add Source Sad Path: Set password with no user' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'chocolatey': + ensure => present, + location => 'https://chocolatey.org/api/v2', + password => 'test', + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply Manifest' +apply_manifest(chocolatey_src, :expect_failures => true) do + step 'Verify Failure' + assert_match(/Error: Validation of Chocolateysource\[chocolatey\] failed: If specifying user\/password, you must specify both values/, stderr, "stderr did not match expected") +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_set_user_without_password.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_set_user_without_password.rb new file mode 100644 index 000000000..db18b0002 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/fail_to_set_user_without_password.rb @@ -0,0 +1,26 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Add Source Sad Path: Set user with no password' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'chocolatey': + ensure => present, + location => 'https://chocolatey.org/api/v2', + user => 'tim', + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply Manifest' +apply_manifest(chocolatey_src, :expect_failures => true) do + step 'Verify Failure' + assert_match(/Error: Validation of Chocolateysource\[chocolatey\] failed: If specifying user\/password, you must specify both values/, stderr, "stderr did not match expected") +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/remove_existing_source.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/remove_existing_source.rb new file mode 100644 index 000000000..78552bfde --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/remove_existing_source.rb @@ -0,0 +1,28 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Remove an Existing Source' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'chocolatey': + ensure => absent, + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_not_match(/chocolatey/, get_xml_value("//sources/source[@id='chocolatey']/@id", result.output).to_s, 'Source was not removed') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/remove_priority_from_existing_source.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/remove_priority_from_existing_source.rb new file mode 100644 index 000000000..84359bb7d --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/remove_priority_from_existing_source.rb @@ -0,0 +1,50 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Remove Priority from an Existing Source' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'chocolatey': + ensure => present, + location => 'https://chocolatey.org/api/v2', + priority => 1, + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest to setup priority' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify priority setup' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/1/, get_xml_value("//sources/source[@id='chocolatey']/@priority", result.output).to_s, 'Priority did not match') + end +end + +# arrange +chocolatey_src_remove = <<-PP + chocolateysource {'chocolatey': + ensure => present, + location => 'https://chocolatey.org/api/v2', + } +PP + +# act +step 'Apply manifest to remove priority' +apply_manifest(chocolatey_src_remove, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/0/, get_xml_value("//sources/source[@id='chocolatey']/@priority", result.output).to_s, 'Priority change did not match') + end +end + diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/remove_user_pass_from_existing_source.rb b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/remove_user_pass_from_existing_source.rb new file mode 100644 index 000000000..9a2204ef6 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/reference/tests/chocolateysource/remove_user_pass_from_existing_source.rb @@ -0,0 +1,53 @@ +require 'chocolatey_helper' +test_name 'MODULES-3037 - Remove User/Password From an Existing Source' +confine(:to, :platform => 'windows') + +backup_config + +# arrange +chocolatey_src = <<-PP + chocolateysource {'chocolatey': + ensure => present, + location => 'https://chocolatey.org/api/v2', + user => 'tim', + password => 'test', + } +PP + +# teardown +teardown do + reset_config +end + +# act +step 'Apply manifest to setup user/password' +apply_manifest(chocolatey_src, :catch_failures => true) + +step 'Verify user/password setup' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_match(/tim/, get_xml_value("//sources/source[@id='chocolatey']/@user", result.output).to_s, 'User setup did not match') + # we are not able to verify password other than if it has a value - it will be encrypted in a non-verifyable way + assert_match(/.+/, get_xml_value("//sources/source[@id='chocolatey']/@password", result.output).to_s, 'Password was not saved') + end +end + +# arrange +chocolatey_src_remove = <<-PP + chocolateysource {'chocolatey': + ensure => present, + location => 'https://chocolatey.org/api/v2', + } +PP + +# act +step 'Apply manifest to remove user/password' +apply_manifest(chocolatey_src_remove, :catch_failures => true) + +step 'Verify results' +agents.each do |agent| + on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result| + assert_not_match(/.+/, get_xml_value("//sources/source[@id='chocolatey']/@user", result.output).to_s, 'User was not removed') + assert_not_match(/.+/, get_xml_value("//sources/source[@id='chocolatey']/@password", result.output).to_s, 'Password was not removed') + end +end diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/test_run_scripts/acceptance_tests.sh b/modules/utilities/windows/repository_managers/chocolatey/tests/test_run_scripts/acceptance_tests.sh new file mode 100644 index 000000000..d1c11a4e7 --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/test_run_scripts/acceptance_tests.sh @@ -0,0 +1,68 @@ +#!/bin/bash +set -e + +# Init +SCRIPT_PATH=$(pwd) +BASENAME_CMD="basename ${SCRIPT_PATH}" +SCRIPT_BASE_PATH=`eval ${BASENAME_CMD}` +declare -a ARGS + +# Argument Parsing +if [ $# -eq 0 ]; then + ARGS[0]='windows-2012r2-64mda' + ARGS[1]='http://pe-releases.puppetlabs.lan/2016.1.1/' + ARGS[2]='forge' +elif [[ $# -lt 3 || $# -gt 4 ]]; then + echo 'USAGE acceptance_tests.sh ' + exit 1 +else + ARGS=("$@") +fi + +# Figure out where we are in the directory hierarchy +if [ $SCRIPT_BASE_PATH = "test_run_scripts" ]; then + cd ../../ +fi + +# Determine if the forge is needed for the test. +if [ ${ARGS[2]} == 'forge' ]; then + echo 'Testing Module Using Forge Package' + export BEAKER_FORGE_HOST=api-module-staging.puppetlabs.com +elif [ ${ARGS[2]} == 'local' ]; then + echo 'Testing Module Using Local Code' +else + echo 'You must specify "forge" or "local" for test type!' + echo 'USAGE acceptance_tests.sh ' + exit 1 +fi + +# Determine if a module version was specified. +if [ -n "${ARGS[3]}" ]; then + echo "Using Module Version: ${ARGS[3]}" + export MODULE_VERSION=${ARGS[3]} +elif [[ $# -eq 3 && ${ARGS[2]} == 'forge' ]]; then + echo 'WARNING: Running Acceptance Tests from Forge without Module Version!' +fi + +# Sleep so the user has time to read script messages. +sleep 2 + +export pe_dist_dir=${ARGS[1]} +export GEM_SOURCE=http://rubygems.delivery.puppetlabs.net + +bundle install --without build development test --path .bundle/gems + +bundle exec beaker \ + --preserve-hosts onfail \ + --config tests/configs/${ARGS[0]} \ + --debug \ + --tests tests/acceptance/tests \ + --keyfile ~/.ssh/id_rsa-acceptance \ + --pre-suite tests/acceptance/pre-suite \ + --load-path tests/lib + +TEST_RESULT=$? + +rm -rf tmp + +exit $TEST_RESULT diff --git a/modules/utilities/windows/repository_managers/chocolatey/tests/test_run_scripts/reference_tests.sh b/modules/utilities/windows/repository_managers/chocolatey/tests/test_run_scripts/reference_tests.sh new file mode 100644 index 000000000..f48088ebd --- /dev/null +++ b/modules/utilities/windows/repository_managers/chocolatey/tests/test_run_scripts/reference_tests.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +set -e + +# Init +SCRIPT_PATH=$(pwd) +BASENAME_CMD="basename ${SCRIPT_PATH}" +SCRIPT_BASE_PATH=`eval ${BASENAME_CMD}` +declare -a ARGS + +# Argument Parsing +if [ $# -eq 0 ]; then + ARGS[0]='windows-2012r2-64a' + ARGS[1]='1.4.1' + ARGS[2]='local' +elif [[ $# -lt 3 || $# -gt 4 ]]; then + echo 'USAGE reference_tests.sh ' + exit 1 +else + ARGS=("$@") +fi + +# Figure out where we are in the directory hierarchy +if [ $SCRIPT_BASE_PATH = "test_run_scripts" ]; then + cd ../../ +fi + +# Determine if the forge is needed for the test. +if [ ${ARGS[2]} == 'forge' ]; then + echo 'Testing Module Using Forge Package' + export BEAKER_FORGE_HOST=api-module-staging.puppetlabs.com +elif [ ${ARGS[2]} == 'local' ]; then + echo 'Testing Module Using Local Code' +else + echo 'You must specify "forge" or "local" for test type!' + echo 'USAGE reference_tests.sh ' + exit 1 +fi + +# Determine if a module version was specified. +if [ -n "${ARGS[3]}" ]; then + echo "Using Module Version: ${ARGS[3]}" + export MODULE_VERSION=${ARGS[3]} +elif [[ $# -eq 3 && ${ARGS[2]} == 'forge' ]]; then + echo 'WARNING: Running Reference Tests from Forge without Module Version!' +fi + +# Sleep so the user has time to read script messages. +sleep 2 + +export BEAKER_PUPPET_AGENT_VERSION=${ARGS[1]} +export GEM_SOURCE=http://rubygems.delivery.puppetlabs.net + +bundle install --without build development test --path .bundle/gems + +bundle exec beaker \ + --preserve-hosts onfail \ + --config tests/configs/${ARGS[0]} \ + --debug \ + --tests tests/reference/tests \ + --keyfile ~/.ssh/id_rsa-acceptance \ + --pre-suite tests/reference/pre-suite \ + --load-path tests/lib \ + --type aio + \ No newline at end of file diff --git a/modules/utilities/windows/text_editor/notepadplusplus/manifests/install.pp b/modules/utilities/windows/text_editor/notepadplusplus/manifests/install.pp new file mode 100644 index 000000000..75a555700 --- /dev/null +++ b/modules/utilities/windows/text_editor/notepadplusplus/manifests/install.pp @@ -0,0 +1,12 @@ +class notepadplusplus::install { + include chocolatey + + notice('Installing notepad++') + + package { 'notepadplusplus': + ensure => installed, + provider => 'chocolatey', + } + + notice('Notepad++ install finished') +} \ No newline at end of file diff --git a/modules/utilities/windows/text_editor/notepadplusplus/notepadplusplus.pp b/modules/utilities/windows/text_editor/notepadplusplus/notepadplusplus.pp new file mode 100644 index 000000000..d17804ad6 --- /dev/null +++ b/modules/utilities/windows/text_editor/notepadplusplus/notepadplusplus.pp @@ -0,0 +1 @@ +include notepadplusplus::install \ No newline at end of file diff --git a/modules/utilities/windows/text_editor/notepadplusplus/secgen_metadata.xml b/modules/utilities/windows/text_editor/notepadplusplus/secgen_metadata.xml new file mode 100644 index 000000000..fd8e5d183 --- /dev/null +++ b/modules/utilities/windows/text_editor/notepadplusplus/secgen_metadata.xml @@ -0,0 +1,20 @@ + + + + Notepadplusplus install + Jason Keighley + Apache v2 + A Notepadplusplus installation + + text_editor + windows + + + + + + Chocolatey install + + \ No newline at end of file diff --git a/modules/utilities/windows/web_browsers/firefox/firefox.pp b/modules/utilities/windows/web_browsers/firefox/firefox.pp new file mode 100644 index 000000000..832d010f2 --- /dev/null +++ b/modules/utilities/windows/web_browsers/firefox/firefox.pp @@ -0,0 +1 @@ +include firefox::install \ No newline at end of file diff --git a/modules/utilities/windows/web_browsers/firefox/manifests/install.pp b/modules/utilities/windows/web_browsers/firefox/manifests/install.pp new file mode 100644 index 000000000..152580361 --- /dev/null +++ b/modules/utilities/windows/web_browsers/firefox/manifests/install.pp @@ -0,0 +1,10 @@ +class firefox::install { + include chocolatey + + notice('Installing Firefox') + + package { 'firefox': + ensure => installed, + provider => 'chocolatey', + } +} \ No newline at end of file diff --git a/modules/utilities/windows/web_browsers/firefox/secgen_metadata.xml b/modules/utilities/windows/web_browsers/firefox/secgen_metadata.xml new file mode 100644 index 000000000..cd1582504 --- /dev/null +++ b/modules/utilities/windows/web_browsers/firefox/secgen_metadata.xml @@ -0,0 +1,20 @@ + + + + Firefox install + Jason Keighley + Apache v2 + A Firefox installation + + web_browsers + windows + + + + + + Chocolatey install + + \ No newline at end of file diff --git a/modules/utilities/windows/web_browsers/google_chrome/google_chrome.pp b/modules/utilities/windows/web_browsers/google_chrome/google_chrome.pp new file mode 100644 index 000000000..b0f1ec41e --- /dev/null +++ b/modules/utilities/windows/web_browsers/google_chrome/google_chrome.pp @@ -0,0 +1 @@ +include google_chrome::install \ No newline at end of file diff --git a/modules/utilities/windows/web_browsers/google_chrome/manifests/configure.pp b/modules/utilities/windows/web_browsers/google_chrome/manifests/configure.pp new file mode 100644 index 000000000..3b58d75a3 --- /dev/null +++ b/modules/utilities/windows/web_browsers/google_chrome/manifests/configure.pp @@ -0,0 +1,13 @@ +class google_chrome::configure { + # Need to ensure unique to each version of Windows, + # different versions may have different install locations + exec { 'google-chrome-initialize': + require => Package[googlechrome], + command => 'C:\windows\system32\cmd.exe /C start "" "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" https://www.google.com', + } + + exec { 'google-chrome-kill-all-processes': + require => Exec[google-chrome-initialize], + command => "$cmd_executable_install_path\\cmd.exe /C \"taskkill /F /IM chrome.exe /T\"" + } +} \ No newline at end of file diff --git a/modules/utilities/windows/web_browsers/google_chrome/manifests/install.pp b/modules/utilities/windows/web_browsers/google_chrome/manifests/install.pp new file mode 100644 index 000000000..fafd6a493 --- /dev/null +++ b/modules/utilities/windows/web_browsers/google_chrome/manifests/install.pp @@ -0,0 +1,10 @@ +class google_chrome::install { + include chocolatey + + notice('Installing google chrome') + + package { 'googlechrome': + ensure => installed, + provider => 'chocolatey', + } +} \ No newline at end of file diff --git a/modules/utilities/windows/web_browsers/google_chrome/secgen_metadata.xml b/modules/utilities/windows/web_browsers/google_chrome/secgen_metadata.xml new file mode 100644 index 000000000..ecdf22d6e --- /dev/null +++ b/modules/utilities/windows/web_browsers/google_chrome/secgen_metadata.xml @@ -0,0 +1,20 @@ + + + + Google Chrome install + Jason Keighley + Apache v2 + A Google Chrome installation + + web_browsers + windows + + + + + + Chocolatey install + + \ No newline at end of file diff --git a/modules/utilities/windows/web_browsers/internet_explorer_11/internet_explorer_11.pp b/modules/utilities/windows/web_browsers/internet_explorer_11/internet_explorer_11.pp new file mode 100644 index 000000000..50706d629 --- /dev/null +++ b/modules/utilities/windows/web_browsers/internet_explorer_11/internet_explorer_11.pp @@ -0,0 +1 @@ +include internet_explorer_11::install \ No newline at end of file diff --git a/modules/utilities/windows/web_browsers/internet_explorer_11/manifests/install.pp b/modules/utilities/windows/web_browsers/internet_explorer_11/manifests/install.pp new file mode 100644 index 000000000..d265c4366 --- /dev/null +++ b/modules/utilities/windows/web_browsers/internet_explorer_11/manifests/install.pp @@ -0,0 +1,10 @@ +class internet_explorer_11::install { + include chocolatey + + notice('Installing Internet Explorer 11') + + package { 'ie11': + ensure => installed, + provider => 'chocolatey', + } +} \ No newline at end of file diff --git a/modules/utilities/windows/web_browsers/internet_explorer_11/secgen_metadata.xml b/modules/utilities/windows/web_browsers/internet_explorer_11/secgen_metadata.xml new file mode 100644 index 000000000..cc1ea294d --- /dev/null +++ b/modules/utilities/windows/web_browsers/internet_explorer_11/secgen_metadata.xml @@ -0,0 +1,20 @@ + + + + Internet Explorer 11 install + Jason Keighley + Apache v2 + An Internet Explorer 11 installation + + web_browsers + windows + + + + + + Chocolatey install + + \ No newline at end of file From c4bec37107cea31d63007ac6803ec1779e901eb9 Mon Sep 17 00:00:00 2001 From: Jjk422 Date: Tue, 21 Mar 2017 19:23:55 +0000 Subject: [PATCH 2/4] Moved over ForGen internet history module need to modify into SecGen structure --- Gemfile | 1 + lib/resources/urllists/urls_history_noise | 30 ++++ lib/schemas/forensic_metadata_schema.xsd | 168 ++++++++++++++++++ .../internet_history_chrome/manifests/init.pp | 17 ++ .../secgen_metadata.xml | 13 ++ .../templates/insert_history.erb | 17 ++ .../urls_noise/manifests/.no_puppet | 0 .../urls_noise/secgen_local/local.rb | 46 +++++ .../urls_noise/t_secgen_metadata.xml | 24 +++ .../urls_noise/urls_noise.pp | 0 10 files changed, 316 insertions(+) create mode 100644 lib/resources/urllists/urls_history_noise create mode 100644 lib/schemas/forensic_metadata_schema.xsd create mode 100644 modules/forensics/windows/internet_artifacts/internet_history_chrome/manifests/init.pp create mode 100644 modules/forensics/windows/internet_artifacts/internet_history_chrome/secgen_metadata.xml create mode 100644 modules/forensics/windows/internet_artifacts/internet_history_chrome/templates/insert_history.erb create mode 100644 modules/generators/forensics/internet_artifacts/urls_noise/manifests/.no_puppet create mode 100644 modules/generators/forensics/internet_artifacts/urls_noise/secgen_local/local.rb create mode 100644 modules/generators/forensics/internet_artifacts/urls_noise/t_secgen_metadata.xml create mode 100644 modules/generators/forensics/internet_artifacts/urls_noise/urls_noise.pp diff --git a/Gemfile b/Gemfile index 97e5eecaa..70da4950c 100644 --- a/Gemfile +++ b/Gemfile @@ -7,6 +7,7 @@ gem 'wordlist' gem 'faker' gem 'forgery' gem 'redcarpet' +gem 'sqlite3' #development only gems go here group :test, :development do diff --git a/lib/resources/urllists/urls_history_noise b/lib/resources/urllists/urls_history_noise new file mode 100644 index 000000000..00251d736 --- /dev/null +++ b/lib/resources/urllists/urls_history_noise @@ -0,0 +1,30 @@ +http://www.independent.co.uk/voices/aleppo-crisis-syrian-war-bashar-al-assad-isis-more-propaganda-than-news-a7479901.html +https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=14&ved=0ahUKEwj9ndTE0MHSAhUMmBoKHQrYB-4Q1ScIbjAN&url=http%3A%2F%2Fwww.independent.co.uk%2Fvoices%2Faleppo-crisis-syrian-war-bashar-al-assad-isis-more-propaganda-than-news-a7479901.html&usg=AFQjCNG6lQ4cMWcGWZ_m4rVrNbYp-mwoIg&bvm=bv.148747831,d.d2s&cad=rja +http://www.bbc.co.uk/news/uk-politics-32810887 +https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=13&ved=0ahUKEwj9ndTE0MHSAhUMmBoKHQrYB-4Q1ScIbDAM&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fuk-politics-32810887&usg=AFQjCNEqQpbty5PU_3C4iiZw6AOoZP5rcQ&bvm=bv.148747831,d.d2s&cad=rja +https://www.theguardian.com/us-news/ng-interactive/2017/jan/20/donald-trump-first-100-days-president-daily-updates +http://www.express.co.uk/news +https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=11&ved=0ahUKEwj9ndTE0MHSAhUMmBoKHQrYB-4QFghjMAo&url=http%3A%2F%2Fwww.express.co.uk%2Fnews&usg=AFQjCNGiC2MV8fS-ERjk3lrYasD0xIDeWA&bvm=bv.148747831,d.d2s&cad=rja +https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=12&ved=0ahUKEwj9ndTE0MHSAhUMmBoKHQrYB-4Q1ScIajAL&url=https%3A%2F%2Fwww.theguardian.com%2Fus-news%2Fng-interactive%2F2017%2Fjan%2F20%2Fdonald-trump-first-100-days-president-daily-updates&usg=AFQjCNHand24H2PO66b0OFbQ-6ZYCOyqRA&bvm=bv.148747831,d.d2s&cad=rja +http://www.dailymail.co.uk/news/index.html +https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=10&ved=0ahUKEwj9ndTE0MHSAhUMmBoKHQrYB-4QFghdMAk&url=http%3A%2F%2Fwww.dailymail.co.uk%2Fnews%2Findex.html&usg=AFQjCNGeWFCOn7XJalTOjKGdVTeIQK_T8w&bvm=bv.148747831,d.d2s&cad=rja +https://www.google.co.uk/search?q=bbc+news&ie=utf-8&oe=utf-8&client=firefox-b-ab&gfe_rd=cr&ei=VDS9WKrJO9DCaOf6r5gI#q=news&* +http://www.bbc.co.uk/news/business-39175740 +https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=8&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQqUMIPzAH&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fbusiness-39175740&usg=AFQjCNHTVX1eg93T6kfEoVO5WtqnB9ERGg&cad=rja +http://www.bbc.co.uk/news/uk-39176538 +https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=7&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQqUMIOzAG&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fuk-39176538&usg=AFQjCNF1Lsgw73VzGWkAC9a-4t9fOHoB2A&cad=rja +http://www.bbc.co.uk/news/uk-39176110 +http://www.bbc.co.uk/news/world +https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=6&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQqUMINzAF&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fuk-39176110&usg=AFQjCNH75QSNyOTErnsehKkHGwN5WxqgkA&cad=rja +https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQjBAILzAC&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fworld&usg=AFQjCNF5X_xXbi4RdS-n3YXetp2xyKOgZQ&cad=rja +http://www.bbc.co.uk/news/business +https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=5&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQjBAIMTAE&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fbusiness&usg=AFQjCNGbcH7S94Wc1xAlQpYi2mWNP2gLhg&cad=rja +http://www.bbc.co.uk/news/world/us_and_canada +https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=4&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQjBAILTAD&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fworld%2Fus_and_canada&usg=AFQjCNHfYWm_9x_ukbMz4b1vRFgm-PD5Pw&cad=rja +http://www.bbc.co.uk/news/uk +https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQjBAIKzAB&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fuk&usg=AFQjCNHuNSSR7R0oMF6unGocwTpv-iLAgQ&cad=rja +http://www.bbc.co.uk/news +https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQFggjMAA&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews&usg=AFQjCNEonTvvrrbEptl1n_9nug5piXqeOQ&cad=rja +https://www.google.co.uk/search?q=bbc+news&ie=utf-8&oe=utf-8&client=firefox-b-ab&gfe_rd=cr&ei=VDS9WKrJO9DCaOf6r5gI +https://www.google.co.uk/?gws_rd=ssl +https://www.mozilla.org/en-US/firefox/51.0.1/firstrun/ \ No newline at end of file diff --git a/lib/schemas/forensic_metadata_schema.xsd b/lib/schemas/forensic_metadata_schema.xsd new file mode 100644 index 000000000..55e29282e --- /dev/null +++ b/lib/schemas/forensic_metadata_schema.xsd @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/forensics/windows/internet_artifacts/internet_history_chrome/manifests/init.pp b/modules/forensics/windows/internet_artifacts/internet_history_chrome/manifests/init.pp new file mode 100644 index 000000000..89c197f34 --- /dev/null +++ b/modules/forensics/windows/internet_artifacts/internet_history_chrome/manifests/init.pp @@ -0,0 +1,17 @@ +$user_account = 'vagrant' +$url_paths = ["https://www.offensive-security.com/backtrack/exploit-db-updates"] + +# file { "C:\Users\{$user_account}\AppData\Roaming\Mozilla\Firefox\Profiles\{$mozilla_profile_number}.default\places.sqlite": +# +# } + +# exec { "add-chrome-history": +# command => "", +# } + +file { 'add-chrome-history': + ensure => 'present', + path => "C:/Users/$user_account/AppData/Local/Google/Chrome/User Data/Default/History", + content => template('evidence_windows_cybercrime_internet_history_chrome/insert_history.erb') + # content => inline_template('evidence_windows_cybercrime_internet_history_chrome/insert_history.erb') +} \ No newline at end of file diff --git a/modules/forensics/windows/internet_artifacts/internet_history_chrome/secgen_metadata.xml b/modules/forensics/windows/internet_artifacts/internet_history_chrome/secgen_metadata.xml new file mode 100644 index 000000000..be171533f --- /dev/null +++ b/modules/forensics/windows/internet_artifacts/internet_history_chrome/secgen_metadata.xml @@ -0,0 +1,13 @@ + + + Jason Keighley + evidence + windows + cybercrime + internet_history_chrome + + evidence/windows/cybercrime/internet_history_chrome + Creates google chrome internet history + Puppet + init.pp + \ No newline at end of file diff --git a/modules/forensics/windows/internet_artifacts/internet_history_chrome/templates/insert_history.erb b/modules/forensics/windows/internet_artifacts/internet_history_chrome/templates/insert_history.erb new file mode 100644 index 000000000..523fba220 --- /dev/null +++ b/modules/forensics/windows/internet_artifacts/internet_history_chrome/templates/insert_history.erb @@ -0,0 +1,17 @@ +<% #puts "Hello World!" %> +<% + require 'sqlite3' + + local_user = 'vagrant' + chrome_user = 'Default' + + SQLite3::Database.new( "C:\\Users\\#{local_user}\\AppData\\Local\\Google\\Chrome\\User Data\\#{chrome_user}\\History" ) do |db| + db.execute( "select * from urls" ) do |row| + p row + end + db.execute( + "INSERT INTO urls(id, url, title, visit_count, typed_count, last_visit_time, hidden, favicon_id) +VALUES ('37', 'test_url', 'test_title', '1', '1', '1', '0', '0');" + ) + end +%> \ No newline at end of file diff --git a/modules/generators/forensics/internet_artifacts/urls_noise/manifests/.no_puppet b/modules/generators/forensics/internet_artifacts/urls_noise/manifests/.no_puppet new file mode 100644 index 000000000..e69de29bb diff --git a/modules/generators/forensics/internet_artifacts/urls_noise/secgen_local/local.rb b/modules/generators/forensics/internet_artifacts/urls_noise/secgen_local/local.rb new file mode 100644 index 000000000..0472da946 --- /dev/null +++ b/modules/generators/forensics/internet_artifacts/urls_noise/secgen_local/local.rb @@ -0,0 +1,46 @@ +#!/usr/bin/ruby +require_relative '../../../../lib/objects/local_string_encoder.rb' +require 'sqlite3' + +class UrlsNoiseEncoder < StringEncoder + attr_accessor :name + + def initialize + super + self.module_name = 'Url Noise Encoder' + self.name = '' + end + + def encode_all + domain = craft_domain + tld = %w(org com net co.uk).sample + + self.outputs << "#{domain}.#{tld}" + end + + # Creates a domain from the business_name + def craft_domain + domain = self.name + # replace spaces + domain = domain.downcase.tr(' ', %w(_ -).sample) + # strip punctuation and return + domain.gsub(/[^0-9a-z\s_-]/i, '') + end + + def process_options(opt, arg) + super + if opt == '--name' + self.name << arg + end + end + + def get_options_array + super + [['--name', GetoptLong::REQUIRED_ARGUMENT]] + end + + def encoding_print_string + 'name: ' + self.name.to_s + end +end + +UrlsNoiseEncoder.new.run \ No newline at end of file diff --git a/modules/generators/forensics/internet_artifacts/urls_noise/t_secgen_metadata.xml b/modules/generators/forensics/internet_artifacts/urls_noise/t_secgen_metadata.xml new file mode 100644 index 000000000..87c918f68 --- /dev/null +++ b/modules/generators/forensics/internet_artifacts/urls_noise/t_secgen_metadata.xml @@ -0,0 +1,24 @@ + + + + Domain Encoder + Thomas Shaw + MIT + Creates a domain based on user inputting a name. + + string_generator + domain_generator + domain + local_calculation + linux + windows + + https://github.com/stympy/faker + + + name + + domain + \ No newline at end of file diff --git a/modules/generators/forensics/internet_artifacts/urls_noise/urls_noise.pp b/modules/generators/forensics/internet_artifacts/urls_noise/urls_noise.pp new file mode 100644 index 000000000..e69de29bb From a13431fad9af89934477f861a1ab45af528c8826 Mon Sep 17 00:00:00 2001 From: Jjk422 Date: Mon, 27 Mar 2017 09:21:40 +0100 Subject: [PATCH 3/4] Moved over ForGen internet history module need to modify into SecGen structure IN PROGRESS: Creating URL generator and chrome history file generator, added forensic option to xml_report_generator. Need to find a way to efficiently pass history file from chrome_history_file_generator to chrome_history forensic module. --- Gemfile.lock | 4 +- lib/output/xml_report_generator.rb | 8 +++ lib/readers/module_reader.rb | 7 ++- lib/readers/system_reader.rb | 2 +- .../{urls_history_noise => generic_urls} | 0 lib/schemas/forensic_metadata_schema.xsd | 14 ++--- lib/schemas/scenario_schema.xsd | 20 +++--- .../internet_history_chrome.pp | 1 + .../internet_history_chrome/manifests/init.pp | 28 +++++---- .../secgen_metadata.xml | 52 ++++++++++++---- .../chrome_history_file_generator.pp} | 0 .../manifests/.no_puppet} | 0 .../secgen_local/local.rb | 52 ++++++++++++++++ .../secgen_metadata.xml | 20 ++++++ .../url_generator/manifests/.no_puppet | 0 .../url_generator/secgen_local/local.rb | 62 +++++++++++++++++++ .../url_generator/secgen_metadata.xml | 21 +++++++ .../url_generator/url_generator.pp | 0 .../urls_noise/secgen_local/local.rb | 46 -------------- .../urls_noise/t_secgen_metadata.xml | 24 ------- .../chrome_history_example.xml | 29 +++++++++ secgen.rb | 7 ++- 22 files changed, 282 insertions(+), 115 deletions(-) rename lib/resources/urllists/{urls_history_noise => generic_urls} (100%) create mode 100644 modules/forensics/windows/internet_artifacts/internet_history_chrome/internet_history_chrome.pp rename modules/generators/forensics/internet_artifacts/{urls_noise/manifests/.no_puppet => chrome_history_file_generator/chrome_history_file_generator.pp} (100%) rename modules/generators/forensics/internet_artifacts/{urls_noise/urls_noise.pp => chrome_history_file_generator/manifests/.no_puppet} (100%) create mode 100644 modules/generators/forensics/internet_artifacts/chrome_history_file_generator/secgen_local/local.rb create mode 100644 modules/generators/forensics/internet_artifacts/chrome_history_file_generator/secgen_metadata.xml create mode 100644 modules/generators/forensics/internet_artifacts/url_generator/manifests/.no_puppet create mode 100644 modules/generators/forensics/internet_artifacts/url_generator/secgen_local/local.rb create mode 100644 modules/generators/forensics/internet_artifacts/url_generator/secgen_metadata.xml create mode 100644 modules/generators/forensics/internet_artifacts/url_generator/url_generator.pp delete mode 100644 modules/generators/forensics/internet_artifacts/urls_noise/secgen_local/local.rb delete mode 100644 modules/generators/forensics/internet_artifacts/urls_noise/t_secgen_metadata.xml create mode 100644 scenarios/simple_examples/forensic_examples/chrome_history_example.xml diff --git a/Gemfile.lock b/Gemfile.lock index bf72394ad..2f438ba9f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -48,6 +48,7 @@ GEM semantic_puppet (0.1.3) spidr (0.6.0) nokogiri (~> 1.3) + sqlite3 (1.3.13) thor (0.19.1) wordlist (0.1.1) spidr (~> 0.2) @@ -66,8 +67,9 @@ DEPENDENCIES rake rdoc redcarpet + sqlite3 wordlist yard BUNDLED WITH - 1.14.3 + 1.14.5 diff --git a/lib/output/xml_report_generator.rb b/lib/output/xml_report_generator.rb index 2e5efc630..6f993030c 100644 --- a/lib/output/xml_report_generator.rb +++ b/lib/output/xml_report_generator.rb @@ -91,6 +91,14 @@ class XMLReportGenerator } end } + when 'forensic' + xml.forensic(selected_module.attributes_for_scenario_output) { + selected_module.received_inputs.each do |key,value| + xml.input({"into" => key}) { + xml.value value + } + end + } when 'network' xml.network(selected_module.attributes_for_scenario_output) else diff --git a/lib/readers/module_reader.rb b/lib/readers/module_reader.rb index 071909f03..4a4bd6b95 100644 --- a/lib/readers/module_reader.rb +++ b/lib/readers/module_reader.rb @@ -31,6 +31,11 @@ class ModuleReader return read_modules('utility', UTILITIES_DIR, UTILITY_SCHEMA_FILE, true) end + # reads in all forensics + def self.read_forensics + return read_modules('forensic', FORENSICS_DIR, FORENSICS_SCHEMA_FILE, true) + end + # reads in all utilities def self.read_generators return read_modules('generator', GENERATORS_DIR, GENERATOR_SCHEMA_FILE, true) @@ -147,7 +152,7 @@ class ModuleReader # for each default input doc.xpath("/#{module_type}/default_input").each do |inputs_doc| - inputs_doc.xpath('descendant::vulnerability | descendant::service | descendant::utility | descendant::network | descendant::base | descendant::encoder | descendant::generator').each do |module_node| + inputs_doc.xpath('descendant::vulnerability | descendant::service | descendant::utility | descendant::forensic | descendant::network | descendant::base | descendant::encoder | descendant::generator').each do |module_node| # create a selector module, which is a regular module instance used as a placeholder for matching requirements module_selector = Module.new(module_node.name) diff --git a/lib/readers/system_reader.rb b/lib/readers/system_reader.rb index efc485623..dbfbc5ec2 100644 --- a/lib/readers/system_reader.rb +++ b/lib/readers/system_reader.rb @@ -64,7 +64,7 @@ class SystemReader end # for each module selection - system_node.xpath('//vulnerability | //service | //utility | //build | //network | //base | //encoder | //generator').each do |module_node| + system_node.xpath('//vulnerability | //service | //utility | //forensic | //build | //network | //base | //encoder | //generator').each do |module_node| # create a selector module, which is a regular module instance used as a placeholder for matching requirements module_selector = Module.new(module_node.name) diff --git a/lib/resources/urllists/urls_history_noise b/lib/resources/urllists/generic_urls similarity index 100% rename from lib/resources/urllists/urls_history_noise rename to lib/resources/urllists/generic_urls diff --git a/lib/schemas/forensic_metadata_schema.xsd b/lib/schemas/forensic_metadata_schema.xsd index 55e29282e..24a3ea748 100644 --- a/lib/schemas/forensic_metadata_schema.xsd +++ b/lib/schemas/forensic_metadata_schema.xsd @@ -1,7 +1,7 @@ @@ -89,11 +89,11 @@ - - + + - - + + @@ -137,7 +137,7 @@ - + diff --git a/lib/schemas/scenario_schema.xsd b/lib/schemas/scenario_schema.xsd index 47e86363d..c570a522a 100644 --- a/lib/schemas/scenario_schema.xsd +++ b/lib/schemas/scenario_schema.xsd @@ -15,12 +15,13 @@ - - + + + - - - + + + @@ -42,9 +43,10 @@ - - - + + + + @@ -103,7 +105,7 @@ - + diff --git a/modules/forensics/windows/internet_artifacts/internet_history_chrome/internet_history_chrome.pp b/modules/forensics/windows/internet_artifacts/internet_history_chrome/internet_history_chrome.pp new file mode 100644 index 000000000..0183cdb2e --- /dev/null +++ b/modules/forensics/windows/internet_artifacts/internet_history_chrome/internet_history_chrome.pp @@ -0,0 +1 @@ +include internet_history_chrome::init \ No newline at end of file diff --git a/modules/forensics/windows/internet_artifacts/internet_history_chrome/manifests/init.pp b/modules/forensics/windows/internet_artifacts/internet_history_chrome/manifests/init.pp index 89c197f34..f6b82de68 100644 --- a/modules/forensics/windows/internet_artifacts/internet_history_chrome/manifests/init.pp +++ b/modules/forensics/windows/internet_artifacts/internet_history_chrome/manifests/init.pp @@ -1,17 +1,19 @@ -$user_account = 'vagrant' -$url_paths = ["https://www.offensive-security.com/backtrack/exploit-db-updates"] +class internet_history_chrome::init { + $user_account = 'vagrant' + $url_paths = ["https://www.offensive-security.com/backtrack/exploit-db-updates"] -# file { "C:\Users\{$user_account}\AppData\Roaming\Mozilla\Firefox\Profiles\{$mozilla_profile_number}.default\places.sqlite": -# -# } + # file { "C:\Users\{$user_account}\AppData\Roaming\Mozilla\Firefox\Profiles\{$mozilla_profile_number}.default\places.sqlite": + # + # } -# exec { "add-chrome-history": -# command => "", -# } + # exec { "add-chrome-history": + # command => "", + # } -file { 'add-chrome-history': - ensure => 'present', - path => "C:/Users/$user_account/AppData/Local/Google/Chrome/User Data/Default/History", - content => template('evidence_windows_cybercrime_internet_history_chrome/insert_history.erb') - # content => inline_template('evidence_windows_cybercrime_internet_history_chrome/insert_history.erb') + file { 'add-chrome-history': + ensure => 'present', + path => "C:/Users/$user_account/AppData/Local/Google/Chrome/User Data/Default/History", + content => template('evidence_windows_cybercrime_internet_history_chrome/insert_history.erb') + # content => inline_template('evidence_windows_cybercrime_internet_history_chrome/insert_history.erb') + } } \ No newline at end of file diff --git a/modules/forensics/windows/internet_artifacts/internet_history_chrome/secgen_metadata.xml b/modules/forensics/windows/internet_artifacts/internet_history_chrome/secgen_metadata.xml index be171533f..e7f8a6c22 100644 --- a/modules/forensics/windows/internet_artifacts/internet_history_chrome/secgen_metadata.xml +++ b/modules/forensics/windows/internet_artifacts/internet_history_chrome/secgen_metadata.xml @@ -1,13 +1,41 @@ - - + + + + Internet history chrome Jason Keighley - evidence - windows - cybercrime - internet_history_chrome - - evidence/windows/cybercrime/internet_history_chrome - Creates google chrome internet history - Puppet - init.pp - \ No newline at end of file + Apache v2 + Create internet history for the Google Chrome browser + + internet_artifacts + windows + + + + + + + + chrome_history_file + + + + + + + + + + + + + + + + + + + Google Chrome install + + \ No newline at end of file diff --git a/modules/generators/forensics/internet_artifacts/urls_noise/manifests/.no_puppet b/modules/generators/forensics/internet_artifacts/chrome_history_file_generator/chrome_history_file_generator.pp similarity index 100% rename from modules/generators/forensics/internet_artifacts/urls_noise/manifests/.no_puppet rename to modules/generators/forensics/internet_artifacts/chrome_history_file_generator/chrome_history_file_generator.pp diff --git a/modules/generators/forensics/internet_artifacts/urls_noise/urls_noise.pp b/modules/generators/forensics/internet_artifacts/chrome_history_file_generator/manifests/.no_puppet similarity index 100% rename from modules/generators/forensics/internet_artifacts/urls_noise/urls_noise.pp rename to modules/generators/forensics/internet_artifacts/chrome_history_file_generator/manifests/.no_puppet diff --git a/modules/generators/forensics/internet_artifacts/chrome_history_file_generator/secgen_local/local.rb b/modules/generators/forensics/internet_artifacts/chrome_history_file_generator/secgen_local/local.rb new file mode 100644 index 000000000..26f13a397 --- /dev/null +++ b/modules/generators/forensics/internet_artifacts/chrome_history_file_generator/secgen_local/local.rb @@ -0,0 +1,52 @@ +#!/usr/bin/ruby +require_relative '../../../../../../lib/objects/local_string_generator.rb' +require 'date' +require 'sqlite3' +require 'fileutils' + +# class ChromeHistoryFileGenerator < StringGenerator +# attr_accessor :history_urls +# +# def initialize +# super +# self.module_name = 'Chrome history file generator' +# self.history_urls = '' +# end +# +# def generate + local_user = 'vagrant' + chrome_user = 'Default' + + history_urls = { + 'url_test_1' => {:url => 'test1', :title => 'test1', :visit_count => '1', :typed_count => '1', :last_visit_time => 10, :hidden => '0', :favicon_id => '0'}, + 'url_test_2' => {:url => 'test2', :title => 'test2', :visit_count => '2', :typed_count => '2', :last_visit_time => 10, :hidden => '0', :favicon_id => '0'}, + 'url_test_3' => {:url => 'test3', :title => 'test3', :visit_count => '3', :typed_count => '3', :last_visit_time => 10, :hidden => '0', :favicon_id => '0'} + } + + FileUtils.cp('../templates/History.source', '../templates/History') + + database = SQLite3::Database.new( "../templates/History" ) do |db| + history_urls.each_value do |details| + db.execute( + "INSERT INTO urls(url, title, visit_count, typed_count, last_visit_time, hidden, favicon_id) +VALUES ('#{details[:url]}', '#{details[:title]}', '#{details[:visit_count]}', '#{details[:typed_count]}', '#{details[:last_visit_time]}', '#{details[:hidden]}', '#{details[:favicon_id]}');" + ) + end + + # db.execute( "select * from urls" ) do |row| + # puts row + # # p row + # end + +# "INSERT INTO urls(url, title, visit_count, typed_count, last_visit_time, hidden, favicon_id) +# VALUES ('test_url', 'test_title', '1', '1', '1', '0', '0');" + + end + + # puts self.history_urls + # + # self.outputs << database + # end +# end +# +# ChromeHistoryFileGenerator.new.run \ No newline at end of file diff --git a/modules/generators/forensics/internet_artifacts/chrome_history_file_generator/secgen_metadata.xml b/modules/generators/forensics/internet_artifacts/chrome_history_file_generator/secgen_metadata.xml new file mode 100644 index 000000000..0d209a158 --- /dev/null +++ b/modules/generators/forensics/internet_artifacts/chrome_history_file_generator/secgen_metadata.xml @@ -0,0 +1,20 @@ + + + + Chrome history file generator + Jason Keighley + Apache v2 + Randomly selects urls from pool of crime urls dependent on inputted crime type. + + internet_history_file_generator + windows + + + + + history_urls + + urls + \ No newline at end of file diff --git a/modules/generators/forensics/internet_artifacts/url_generator/manifests/.no_puppet b/modules/generators/forensics/internet_artifacts/url_generator/manifests/.no_puppet new file mode 100644 index 000000000..e69de29bb diff --git a/modules/generators/forensics/internet_artifacts/url_generator/secgen_local/local.rb b/modules/generators/forensics/internet_artifacts/url_generator/secgen_local/local.rb new file mode 100644 index 000000000..225a0ca1f --- /dev/null +++ b/modules/generators/forensics/internet_artifacts/url_generator/secgen_local/local.rb @@ -0,0 +1,62 @@ +#!/usr/bin/ruby +require_relative '../../../../../../lib/objects/local_string_generator.rb' +require 'date' + +class UrlGenerator < StringGenerator + def initialize + super + self.module_name = 'Url generator' + self.number_of_generic_urls = '10' + self.generic_urls_start_time = '3rd july 2017' + self.number_of_cybercrime_urls = '' + self.cybercrime_urls_start_time = '' + end + + def generate + + + urls = Hash.new + + # number_of_generic_urls = 10 + # generic_urls_start_time = '3rd july 2017 15:16:20' + # generic_urls_length_time = '2 days 1 hour 10 seconds' + # ROOT_DIR = File.expand_path('../../../../../../../',__FILE__) + # URLLISTS_DIR = "#{ROOT_DIR}/lib/resources/urllists" + + # Generic filler urls + generic_urls = File.readlines("#{URLLISTS_DIR}/generic_urls").sample(self.number_of_generic_urls.to_int) + + # Crime url start + # cybercrime_urls = File.readlines("#{URLLISTS_DIR}/cybercrime_urls").sample(self.number_of_cybercrime_urls).chomp + + generic_urls.each do |url| + start_time = DateTime.parse(self.generic_urls_start_time) + + # urls[url] = DateTime.new( + # rand(start_time.year..length_time.year + 1), + # rand(start_time.month..length_time.month + 1), + # rand(start_time.day..length_time.day + 1), + # rand(start_time.hour..length_time.hour + 1), + # rand(start_time.minute..length_time.minute + 1), + # rand(start_time.second..length_time.second + 1) + # ) + + # urls[url] = DateTime.new( + # rand(length_time.year - start_time.year), + # rand(length_time.month - start_time.month), + # rand(length_time.day - start_time.day), + # rand(length_time.hour - start_time.hour), + # rand(length_time.minute - start_time.minute), + # rand(length_time.second - start_time.second) + # ) + + urls[url] = { :url => url ,:title => 'test', :visit_count => '1', :typed_count => '1', :last_visit_time => start_time, :hidden => '0', :favicon_id => '0' } + end + + puts urls + + self.outputs << urls + end +end + +UrlGenerator.new.run \ No newline at end of file diff --git a/modules/generators/forensics/internet_artifacts/url_generator/secgen_metadata.xml b/modules/generators/forensics/internet_artifacts/url_generator/secgen_metadata.xml new file mode 100644 index 000000000..0f3991c54 --- /dev/null +++ b/modules/generators/forensics/internet_artifacts/url_generator/secgen_metadata.xml @@ -0,0 +1,21 @@ + + + + Url generator + Jason Keighley + Apache v2 + Randomly selects urls from pool of crime urls dependent on inputted crime type. + + url_generator + windows + + + + + number_of_generic_urls + number_of_cybercrime_urls + + urls + \ No newline at end of file diff --git a/modules/generators/forensics/internet_artifacts/url_generator/url_generator.pp b/modules/generators/forensics/internet_artifacts/url_generator/url_generator.pp new file mode 100644 index 000000000..e69de29bb diff --git a/modules/generators/forensics/internet_artifacts/urls_noise/secgen_local/local.rb b/modules/generators/forensics/internet_artifacts/urls_noise/secgen_local/local.rb deleted file mode 100644 index 0472da946..000000000 --- a/modules/generators/forensics/internet_artifacts/urls_noise/secgen_local/local.rb +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/ruby -require_relative '../../../../lib/objects/local_string_encoder.rb' -require 'sqlite3' - -class UrlsNoiseEncoder < StringEncoder - attr_accessor :name - - def initialize - super - self.module_name = 'Url Noise Encoder' - self.name = '' - end - - def encode_all - domain = craft_domain - tld = %w(org com net co.uk).sample - - self.outputs << "#{domain}.#{tld}" - end - - # Creates a domain from the business_name - def craft_domain - domain = self.name - # replace spaces - domain = domain.downcase.tr(' ', %w(_ -).sample) - # strip punctuation and return - domain.gsub(/[^0-9a-z\s_-]/i, '') - end - - def process_options(opt, arg) - super - if opt == '--name' - self.name << arg - end - end - - def get_options_array - super + [['--name', GetoptLong::REQUIRED_ARGUMENT]] - end - - def encoding_print_string - 'name: ' + self.name.to_s - end -end - -UrlsNoiseEncoder.new.run \ No newline at end of file diff --git a/modules/generators/forensics/internet_artifacts/urls_noise/t_secgen_metadata.xml b/modules/generators/forensics/internet_artifacts/urls_noise/t_secgen_metadata.xml deleted file mode 100644 index 87c918f68..000000000 --- a/modules/generators/forensics/internet_artifacts/urls_noise/t_secgen_metadata.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - Domain Encoder - Thomas Shaw - MIT - Creates a domain based on user inputting a name. - - string_generator - domain_generator - domain - local_calculation - linux - windows - - https://github.com/stympy/faker - - - name - - domain - \ No newline at end of file diff --git a/scenarios/simple_examples/forensic_examples/chrome_history_example.xml b/scenarios/simple_examples/forensic_examples/chrome_history_example.xml new file mode 100644 index 000000000..e6e98423e --- /dev/null +++ b/scenarios/simple_examples/forensic_examples/chrome_history_example.xml @@ -0,0 +1,29 @@ + + + + + + + + + storage_server + + + + + + + + + + + + + + + + + + diff --git a/secgen.rb b/secgen.rb index 13b004f7b..cc73995fe 100644 --- a/secgen.rb +++ b/secgen.rb @@ -59,6 +59,10 @@ def build_config(scenario, out_dir, options) all_available_utilities = ModuleReader.read_utilities Print.std "#{all_available_utilities.size} utility modules loaded" + Print.info 'Reading available forensic modules...' + all_available_forensics = ModuleReader.read_forensics + Print.std "#{all_available_forensics.size} forensic modules loaded" + Print.info 'Reading available generator modules...' all_available_generators = ModuleReader.read_generators Print.std "#{all_available_generators.size} generator modules loaded" @@ -74,7 +78,8 @@ def build_config(scenario, out_dir, options) Print.info 'Resolving systems: randomising scenario...' # for each system, select modules all_available_modules = all_available_bases + all_available_builds + all_available_vulnerabilties + - all_available_services + all_available_utilities + all_available_generators + all_available_encoders + all_available_networks + all_available_services + all_available_utilities + all_available_forensics + all_available_generators + + all_available_encoders + all_available_networks # update systems with module selections systems.map! {|system| system.module_selections = system.resolve_module_selection(all_available_modules) From ac41834e828d257c696bd7a996a8d5b384f2c03a Mon Sep 17 00:00:00 2001 From: Jjk422 Date: Mon, 3 Apr 2017 11:45:20 +0100 Subject: [PATCH 4/4] Moved over ForGen internet history module need to modify into SecGen structure IN PROGRESS: Creating URL generator and chrome history file generator, added forensic option to xml_report_generator. Need to find a way to efficiently pass history file from chrome_history_file_generator to chrome_history forensic module. ERRORING: Recieving error ==> storage_server: Error: Could not find class internet_history_chrome::init for vagrant-2008r2.lan on node vagrant-2008r2.lan Need to look into vagrant/puppet not findign forensics internet history class --- lib/templates/Puppetfile.erb | 2 +- .../internet_history_chrome/files/History | 0 .../templates/insert_history.erb | 37 ++++++++++++------- .../templates/insert_history.erb.old | 17 +++++++++ 4 files changed, 42 insertions(+), 14 deletions(-) create mode 100644 modules/forensics/windows/internet_artifacts/internet_history_chrome/files/History create mode 100644 modules/forensics/windows/internet_artifacts/internet_history_chrome/templates/insert_history.erb.old diff --git a/lib/templates/Puppetfile.erb b/lib/templates/Puppetfile.erb index dddc7bfcf..1059d0728 100644 --- a/lib/templates/Puppetfile.erb +++ b/lib/templates/Puppetfile.erb @@ -13,7 +13,7 @@ mod 'SecGen-secgen_functions', :path => '<%= SECGEN_FUNCTIONS_PUPPET_DIR %>' <% @currently_processing_system.module_selections.each do |selected_module| -%> <% case selected_module.module_type - when 'vulnerability', 'service', 'utility', 'build' -%> + when 'vulnerability', 'service', 'utility', 'build', 'forensic' -%> mod 'SecGen-<%= selected_module.module_path_name %>/<%= selected_module.module_path_end %>', :path => '<%="#{ROOT_DIR}/#{selected_module.module_path}"%>' <% end -%> <% end -%> diff --git a/modules/forensics/windows/internet_artifacts/internet_history_chrome/files/History b/modules/forensics/windows/internet_artifacts/internet_history_chrome/files/History new file mode 100644 index 000000000..e69de29bb diff --git a/modules/forensics/windows/internet_artifacts/internet_history_chrome/templates/insert_history.erb b/modules/forensics/windows/internet_artifacts/internet_history_chrome/templates/insert_history.erb index 523fba220..fd7ff1c4a 100644 --- a/modules/forensics/windows/internet_artifacts/internet_history_chrome/templates/insert_history.erb +++ b/modules/forensics/windows/internet_artifacts/internet_history_chrome/templates/insert_history.erb @@ -1,17 +1,28 @@ -<% #puts "Hello World!" %> -<% - require 'sqlite3' +<% #require 'json' + #$secgen_parameters = JSON.parse(@json_inputs) + #$server_name = $secgen_parameters['server_name'].first + #$welcome_msg = $secgen_parameters['welcome_msg'].first + # + #if $secgen_parameters['url'] + # $business_name = $secgen_parameters['business_name'].first + # $welcome_msg = "Welcome to the #{$business_name} FTP server!" + #end - local_user = 'vagrant' - chrome_user = 'Default' + require 'sqlite' - SQLite3::Database.new( "C:\\Users\\#{local_user}\\AppData\\Local\\Google\\Chrome\\User Data\\#{chrome_user}\\History" ) do |db| - db.execute( "select * from urls" ) do |row| - p row - end - db.execute( - "INSERT INTO urls(id, url, title, visit_count, typed_count, last_visit_time, hidden, favicon_id) + local_user = 'vagrant' + chrome_user = 'Default' + + SQLite3::Database.new( "/media/user/3TB_internal_drive/Documents/SecGen/modules/forensics/windows/internet_artifacts/internet_history_chrome/files/History" ) do |db| + db.execute( "select * from urls" ) do |row| + puts row + end + db.execute( + "INSERT INTO urls(id, url, title, visit_count, typed_count, last_visit_time, hidden, favicon_id) VALUES ('37', 'test_url', 'test_title', '1', '1', '1', '0', '0');" - ) - end + ) + db.execute( "select * from urls" ) do |row| + puts row + end + end %> \ No newline at end of file diff --git a/modules/forensics/windows/internet_artifacts/internet_history_chrome/templates/insert_history.erb.old b/modules/forensics/windows/internet_artifacts/internet_history_chrome/templates/insert_history.erb.old new file mode 100644 index 000000000..523fba220 --- /dev/null +++ b/modules/forensics/windows/internet_artifacts/internet_history_chrome/templates/insert_history.erb.old @@ -0,0 +1,17 @@ +<% #puts "Hello World!" %> +<% + require 'sqlite3' + + local_user = 'vagrant' + chrome_user = 'Default' + + SQLite3::Database.new( "C:\\Users\\#{local_user}\\AppData\\Local\\Google\\Chrome\\User Data\\#{chrome_user}\\History" ) do |db| + db.execute( "select * from urls" ) do |row| + p row + end + db.execute( + "INSERT INTO urls(id, url, title, visit_count, typed_count, last_visit_time, hidden, favicon_id) +VALUES ('37', 'test_url', 'test_title', '1', '1', '1', '0', '0');" + ) + end +%> \ No newline at end of file