diff --git a/.gitignore b/.gitignore index f318dc8..8367bdc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ www/* !www/logs/tail !www/index.php config.custom.yaml -/packer_cache \ No newline at end of file +/packer_cache diff --git a/CHANGELOG.md b/CHANGELOG.md index d0cddf6..2ef8565 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,21 @@ in 1.x versions. To get the diff for a specific change, go to https://github.com/joomlatools/joomla-vagrant/commit/xxx where xxx is the change hash. To view the diff between two versions, go to https://github.com/joomlatools/joomla-vagrant/compare/v1.0.0...v1.0.1 +* 1.4.0 (2015-10-19) + * Added - `box php:engine hhvm` command to switch to HHVM + * Added - `box xdebug:profiler start|stop` command to turn on Xdebug profiling + * Added - [Zend Z-Ray](http://www.zend.com/en/products/z-ray/z-ray-preview) preview + * Added - [httpie](https://github.com/jkbrzt/httpie) CLI HTTP Client + * Added - [Cloudcommander](http://cloudcmd.io/) web-based file browser + * Added - System will automatically look for [joomlatools/joomla-console](http://developer.joomlatools.com/tools/console.html) updates + * Added - Installed Varnish cache in front of Apache + * Added - Automatically backup and restore virtual hosts and databases when upgrading the box + * Fixed - Upgraded Webgrind to automatically find cachegrind files + * Fixed - Consolidate the PHP ini files into a single custom.ini file + * Improved - Automatically change directory to /var/www when logging in via `vagrant ssh` or web terminal + * Improved - Added /terminal, /mailcatcher and /filebrowser aliases + * Improved - Added bash autocompletion to the `box` command + * 1.3.1 (2015-09-03) * Added - Support for PHP7 * Added - Support for [joomla-platform](https://github.com/joomlatools/joomla-platform) installations diff --git a/Vagrantfile b/Vagrantfile index dba18b3..e8f25aa 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,6 +1,12 @@ require "yaml" require "json" +# Check for required plugins and install if missing +required_plugins = %w( vagrant-triggers ) +required_plugins.each do |plugin| + exec "vagrant plugin install #{plugin};vagrant #{ARGV.join(" ")}" unless Vagrant.has_plugin? plugin || ARGV[0] == 'plugin' +end + # Initialize config def deep_merge!(target, data) merger = proc{|key, v1, v2| @@ -27,7 +33,7 @@ CONF = _config Vagrant.configure("2") do |config| config.vm.box = "ubuntu/trusty64" - config.vm.hostname = "joomlatools.dev" + config.vm.hostname = "joomlatools" # Important: we use this in joomla-console to determine if we are being run in the Vagrant box or not! config.vm.network :private_network, ip: "33.33.33.58" config.ssh.forward_agent = true @@ -67,4 +73,32 @@ Vagrant.configure("2") do |config| "pma_controluser_password" => "awesome" } end + + config.trigger.before :destroy do + while true + print "Do you want to backup your virtual hosts and databases first? [y/N] " + case STDIN.gets.strip + when 'Y', 'y', 'yes' + run_remote "/bin/bash /home/vagrant/triggers/backup.sh" + break + when /\A[nN]o?\Z/ #n or no + break + end + end + end + + config.trigger.after :up do + if File.exist?('./joomla-box-backup.tar') + while true + print "Backup archive found. Do you want to restore the backup file? [y/N] " + case STDIN.gets.strip + when 'Y', 'y', 'yes' + run_remote "/bin/bash /home/vagrant/triggers/restore.sh" + break + when /\A[nN]o?\Z/ #n or no + break + end + end + end + end end diff --git a/Vagrantfile.pkg b/Vagrantfile.pkg index dfeea10..ca6d858 100644 --- a/Vagrantfile.pkg +++ b/Vagrantfile.pkg @@ -1,6 +1,12 @@ require "yaml" require "json" +# Check for required plugins and install if missing +required_plugins = %w( vagrant-triggers ) +required_plugins.each do |plugin| + exec "vagrant plugin install #{plugin};vagrant #{ARGV.join(" ")}" unless Vagrant.has_plugin? plugin || ARGV[0] == 'plugin' +end + # Initialize config def deep_merge!(target, data) merger = proc{|key, v1, v2| @@ -53,4 +59,32 @@ Vagrant.configure("2") do |config| config.vm.provision :shell, :inline => shell_cmd, :run => "always" end + + config.trigger.before :destroy do + while true + print "Do you want to backup your virtual hosts and databases first? [y/N] " + case STDIN.gets.strip + when 'Y', 'y', 'yes' + run_remote "/bin/bash /home/vagrant/triggers/backup.sh" + break + when /\A[nN]o?\Z/ #n or no + break + end + end + end + + config.trigger.after :up do + if File.exist?('./joomla-box-backup.tar') + while true + print "Backup archive found. Do you want to restore the backup file? [y/N] " + case STDIN.gets.strip + when 'Y', 'y', 'yes' + run_remote "/bin/bash /home/vagrant/triggers/restore.sh" + break + when /\A[nN]o?\Z/ #n or no + break + end + end + end + end end diff --git a/packer.json b/packer.json index eb6e9b7..58e707a 100644 --- a/packer.json +++ b/packer.json @@ -90,7 +90,7 @@ "artifact_type": "vagrant.box", "metadata": { "provider": "virtualbox", - "version": "1.3.1" + "version": "1.4.0" } }] ] diff --git a/puppet/manifests/default.pp b/puppet/manifests/default.pp index 603a425..b32b371 100644 --- a/puppet/manifests/default.pp +++ b/puppet/manifests/default.pp @@ -1,5 +1,5 @@ group { 'puppet': ensure => present } -Exec { path => [ '/bin/', '/sbin/', '/usr/bin/', '/usr/sbin/', '/usr/local/bin/' ] } +Exec { path => [ '/bin/', '/sbin/', '/usr/bin/', '/usr/sbin/', '/usr/local/bin/' ], timeout => 900 } File { owner => 0, group => 0, mode => 0644 } user { 'vagrant': } @@ -15,7 +15,7 @@ apt::key { '4F4EA0AAE5267A6C': } -apt::ppa { 'ppa:ondrej/php5': +apt::ppa { 'ppa:ondrej/php5-5.6': require => Apt::Key['4F4EA0AAE5267A6C'] } @@ -32,6 +32,8 @@ file { '/home/vagrant/.bash_aliases': ensure => 'present', + owner => vagrant, + group => vagrant, source => 'puppet:///modules/puphpet/dot/.bash_aliases', } @@ -68,12 +70,21 @@ require => Class['apache::certificate'], } +exec { 'apache-set-servername': + command => "echo \"ServerName joomlatools\" > /etc/apache2/conf-available/fqdn.conf; a2enconf fqdn", + path => ['/usr/bin' , '/bin', '/usr/sbin/'], + creates => '/etc/apache2/conf-available/fqdn', + require => Class['apache'] +} + apache::dotconf { 'custom': content => template("apache/custom.conf.erb"), } apache::module { 'rewrite': } apache::module { 'ssl': } +apache::module { 'proxy_fcgi': } +apache::module { 'headers': } class { 'php': service => 'apache', @@ -82,6 +93,17 @@ require => Package['apache'], } +$apache_hhvm_proxy = " + + SetHandler \"proxy:fcgi://127.0.0.1:9000\" +" + +file { '/etc/apache2/conf-available/hhvm.conf': + ensure => file, + content => $apache_hhvm_proxy, + require => Class['apache'] +} + php::module { 'php5-mysql': } php::module { 'php5-cli': } php::module { 'php5-curl': } @@ -128,11 +150,38 @@ value => [ 'extension=yaml.so' ], - ini => '/etc/php5/mods-available/zzz_yaml.ini', + ini => '/etc/php5/mods-available/yaml.ini', notify => Service['apache'], require => [Class['php'], Php::Pecl::Module['yaml']] } +file { ['/etc/php5/apache2/conf.d/20-yaml.ini', '/etc/php5/cli/conf.d/20-yaml.ini']: + ensure => link, + target => '/etc/php5/mods-available/yaml.ini', + require => Puphpet::Ini['yaml'] +} + +php::pecl::module { 'oauth': + use_package => no, + ensure => present, + require => Php::Pear::Config['download_dir'] +} + +puphpet::ini { 'oauth': + value => [ + 'extension=oauth.so' + ], + ini => '/etc/php5/mods-available/oauth.ini', + notify => Service['apache'], + require => [Class['php'], Php::Pecl::Module['oauth']] +} + +file { ['/etc/php5/apache2/conf.d/20-oauth.ini', '/etc/php5/cli/conf.d/20-oauth.ini']: + ensure => link, + target => '/etc/php5/mods-available/oauth.ini', + require => Puphpet::Ini['oauth'] +} + class { 'xdebug': service => 'apache', } @@ -141,24 +190,13 @@ require => Package['php5', 'curl'], } -puphpet::ini { 'xdebug': - value => [ - 'xdebug.remote_autostart = 0', - ';Use remote_connect_back = 0 if accessing a shared box', - 'xdebug.remote_connect_back = 1', - 'xdebug.remote_enable = 1', - 'xdebug.remote_handler = "dbgp"', - 'xdebug.remote_port = 9000', - 'xdebug.remote_host = "33.33.33.1"', - 'xdebug.show_local_vars = 1', - 'xdebug.profiler_enable = 0', - 'xdebug.profiler_enable_trigger = 1', - 'xdebug.max_nesting_level = 1000', - 'xdebug.profiler_output_dir = /var/www/logs/xdebug/' - ], - ini => '/etc/php5/mods-available/zzz_xdebug.ini', - notify => Service['apache'], - require => Class['php'], +exec { "composer-plugin-changelogs": + command => "composer global require pyrech/composer-changelogs", + path => ['/usr/bin' , '/bin'], + creates => '/home/vagrant/.composer/vendor/pyrech/composer-changelogs', + user => vagrant, + environment => 'COMPOSER_HOME=/home/vagrant/.composer', + require => Class['Composer'] } puphpet::ini { 'custom': @@ -170,23 +208,28 @@ 'upload_max_filesize = "256M"', 'post_max_size = "256M"', 'memory_limit = "256M"', - 'date.timezone = "UTC"' + 'date.timezone = "UTC"', + 'xdebug.remote_autostart = 0', + 'xdebug.remote_connect_back = 1', + 'xdebug.remote_enable = 1', + 'xdebug.remote_handler = "dbgp"', + 'xdebug.remote_port = 9000', + 'xdebug.remote_host = "33.33.33.1"', + 'xdebug.show_local_vars = 1', + 'xdebug.profiler_enable = 0', + 'xdebug.profiler_enable_trigger = 0', + 'xdebug.max_nesting_level = 1000', + 'xdebug.profiler_output_dir = /var/www/' ], - ini => '/etc/php5/mods-available/zzz_custom.ini', + ini => '/etc/php5/mods-available/custom.ini', notify => Service['apache'], require => Class['php'], } -exec {'symlink-custom-ini-files-apache': - command => 'find /etc/php5/mods-available/ -name "zzz_*" -exec /bin/bash -c \'ln -s {} /etc/php5/apache2/conf.d/`basename $0`\' {} \;', - unless => 'bash -c "test -f /etc/php5/apache2/conf.d/zzz_custom.ini"', - require => [Puphpet::Ini['custom'], Puphpet::Ini['yaml'], Puphpet::Ini['xdebug']] -} - -exec {'symlink-custom-ini-files-cli': - command => 'find /etc/php5/mods-available/ -name "zzz_*" -exec /bin/bash -c \'ln -s {} /etc/php5/cli/conf.d/`basename $0`\' {} \;', - unless => 'bash -c "test -f etc/php5/cli/conf.d/zzz_custom.ini"', - require => [Puphpet::Ini['custom'], Puphpet::Ini['yaml'], Puphpet::Ini['xdebug']] +file { ['/etc/php5/apache2/conf.d/99-custom.ini', '/etc/php5/cli/conf.d/99-custom.ini']: + ensure => link, + target => '/etc/php5/mods-available/custom.ini', + require => Puphpet::Ini['custom'] } class { 'mysql::server': @@ -209,7 +252,7 @@ server_name => 'phpmyadmin', serveraliases => 'phpmyadmin.joomla.box', docroot => '/usr/share/phpmyadmin', - port => 80, + port => 8080, priority => '10', require => Class['phpmyadmin'], } @@ -244,8 +287,8 @@ apache::vhost { 'webgrind': server_name => 'webgrind', serveraliases => 'webgrind.joomla.box', - docroot => '/usr/share/webgrind', - port => 80, + docroot => '/usr/share/webgrind-1.2', + port => 8080, priority => '10', require => Class['webgrind'], } @@ -253,7 +296,7 @@ apache::vhost { 'joomla.box': server_admin => 'webmaster@localhost', serveraliases => 'localhost', - port => 80, + port => 8080, priority => '00', docroot => '/var/www', directory => '/var/www', @@ -317,6 +360,7 @@ } class {'wetty': } +class {'cloudcommander': } file { '/etc/update-motd.d/999-joomlatools': ensure => 'present', @@ -340,7 +384,25 @@ require => Apt::Ppa['ppa:resmo/git-ftp'] } +package { 'httpie': + ensure => latest +} + swap_file::files { 'default': ensure => present, swapfilesize => '512 MB' -} \ No newline at end of file +} + +class { 'hhvm': + manage_repos => true, + pgsql => false +} + +class {'triggers': } + +class { 'varnish': } + +class { 'zray': + notify => Service['apache'], + require => Class['php'] +} diff --git a/puppet/modules/apache/templates/virtualhost/joomlatools.vhost.conf.erb b/puppet/modules/apache/templates/virtualhost/joomlatools.vhost.conf.erb index 07b22ed..aa4c6df 100644 --- a/puppet/modules/apache/templates/virtualhost/joomlatools.vhost.conf.erb +++ b/puppet/modules/apache/templates/virtualhost/joomlatools.vhost.conf.erb @@ -29,6 +29,11 @@ Alias /dashboard /home/vagrant/scripts/dashboard Alias /pimpmylog /usr/share/pimpmylog/vendor/potsky/pimp-my-log + Alias /varnish-enabled /home/vagrant/scripts/varnish-enabled + + Redirect permanent /terminal http://joomla.box:3000 + Redirect permanent /mailcatcher http://joomla.box:1080 + Redirect permanent /filebrowser http://joomla.box:8001/fs/var/www RewriteEngine on RewriteCond %{REQUEST_URI} ^/$ diff --git a/puppet/modules/archive/.fixtures.yml b/puppet/modules/archive/.fixtures.yml new file mode 100755 index 0000000..715cad4 --- /dev/null +++ b/puppet/modules/archive/.fixtures.yml @@ -0,0 +1,3 @@ +fixtures: + symlinks: + archive: "#{source_dir}" diff --git a/puppet/modules/archive/.gitignore b/puppet/modules/archive/.gitignore new file mode 100755 index 0000000..b5b7a00 --- /dev/null +++ b/puppet/modules/archive/.gitignore @@ -0,0 +1,7 @@ +pkg/ +Gemfile.lock +vendor/ +spec/fixtures/ +.vagrant/ +.bundle/ +coverage/ diff --git a/puppet/modules/archive/.puppet-lint.rc b/puppet/modules/archive/.puppet-lint.rc new file mode 100755 index 0000000..d8f5c59 --- /dev/null +++ b/puppet/modules/archive/.puppet-lint.rc @@ -0,0 +1,5 @@ +--fail-on-warnings +--relative +--no-80chars +--no-documentation +--no-class_inherits_from_params_class-check diff --git a/puppet/modules/archive/.sync.yml b/puppet/modules/archive/.sync.yml new file mode 100755 index 0000000..9d232e6 --- /dev/null +++ b/puppet/modules/archive/.sync.yml @@ -0,0 +1,3 @@ +--- +.travis.yml: + forge_password: "KDSkD9tprA+AxUg7kNaMavysQUHa7cmqsSl9x89J0ai6z736KXqjCBQIN8kW5V6vfat/yoDScVVYaQv7Y0/6ExBpoL05pOgI9wXvD8G3BONUfd1iFKMOATitjdBxUhVqZClG/iABwgPKh5gPxBKm5Bp/ViLFv8nuhaLSlSBQ0U0=" diff --git a/puppet/modules/archive/.travis.yml b/puppet/modules/archive/.travis.yml new file mode 100755 index 0000000..d494c0f --- /dev/null +++ b/puppet/modules/archive/.travis.yml @@ -0,0 +1,32 @@ +--- +language: ruby +sudo: false +cache: bundler +bundler_args: --without system_tests +script: ["bundle exec rake validate", "bundle exec rake lint", "bundle exec rake spec SPEC_OPTS='--format documentation'", "bundle exec rake metadata"] +matrix: + fast_finish: true + include: + - rvm: 1.8.7 + env: PUPPET_GEM_VERSION="~> 3.0" FACTER_GEM_VERSION="~> 1.7.0" + - rvm: 1.9.3 + env: PUPPET_GEM_VERSION="~> 3.0" + - rvm: 2.0.0 + env: PUPPET_GEM_VERSION="~> 3.0" + - rvm: 2.0.0 + env: PUPPET_GEM_VERSION="~> 3.0" FUTURE_PARSER="yes" + - rvm: 2.1.0 + env: PUPPET_GEM_VERSION="~> 4.0" +notifications: + email: false +deploy: + provider: puppetforge + user: camptocamp + password: + secure: "KDSkD9tprA+AxUg7kNaMavysQUHa7cmqsSl9x89J0ai6z736KXqjCBQIN8kW5V6vfat/yoDScVVYaQv7Y0/6ExBpoL05pOgI9wXvD8G3BONUfd1iFKMOATitjdBxUhVqZClG/iABwgPKh5gPxBKm5Bp/ViLFv8nuhaLSlSBQ0U0=" + on: + tags: true + # all_branches is required to use tags + all_branches: true + # Only publish if our main Ruby target builds + rvm: 1.9.3 diff --git a/puppet/modules/archive/CHANGELOG.md b/puppet/modules/archive/CHANGELOG.md new file mode 100755 index 0000000..356d6f7 --- /dev/null +++ b/puppet/modules/archive/CHANGELOG.md @@ -0,0 +1,111 @@ +## 2015-06-29 - Release 0.8.0 + +allow to specify a user for the archive extraction and the archive download + +## 2015-06-26 - Release 0.7.5 + +Fix strict_variables activation with rspec-puppet 2.2 + +## 2015-05-28 - Release 0.7.4 + +Add beaker_spec_helper to Gemfile + +## 2015-05-26 - Release 0.7.3 + +Use random application order in nodeset + +## 2015-05-26 - Release 0.7.2 + +add utopic & vivid nodesets + +## 2015-05-25 - Release 0.7.1 + +Don't allow failure on Puppet 4 + +## 2015-05-18 - Release 0.7.0 + +Support tar.xz format + +## 2015-05-13 - Release 0.6.2 + +Add puppet-lint-file_source_rights-check gem + +## 2015-05-12 - Release 0.6.1 + +Don't pin beaker + +## 2015-05-12 - Release 0.6.0 + +Support the purging of target directories + +## 2015-04-27 - Release 0.5.3 + +Add nodeset ubuntu-12.04-x86_64-openstack + +## 2015-04-17 - Release 0.5.2 + +Add beaker nodesets + +## 2015-04-03 - Release 0.5.1 + +Confine rspec pinning to ruby 1.8 +Fix when not using digest_url + +## 2015-03-24 - Release 0.5.0 + +Add a proxy_server parameter + +## 2015-03-24 - Release 0.4.1 + +Add unit tests + +## 2015-03-06 - Release 0.4.0 + +Add --strip-components support + +## 2015-01-07 - Release 0.3.6 + +Fix unquoted strings in cases + +## 2015-01-05 - Release 0.3.5 + +Simplify bundler cache in Travis CI +Fix license name in metadata.json + +## 2014-11-18 Release 0.3.2 + +Linting metadata + +## 2014-11-04 Release 0.3.1 + +Fix missing comma + +## 2014-11-04 Release 0.3.0 + +Add path to execs + +## 2014-11-04 Release 0.2.1 + +Drop Puppet 2.7 support + +## 2014-10-20 Release 0.2.0 + +Setup automatic Forge releases + +## 2014-09-24 Release 0.1.3 + +Bug fix + +## 2014-09-23 Release 0.1.2 + +Quote url to get the data from + +## 2014-09-05 Release 0.1.1 + +Allow disabling of no-checksum notices in puppetmaster logs + +## 2014-07-02 Release 0.1.0 + +Make curl silent, #21 +Add documentation +Fix strict variables diff --git a/puppet/modules/archive/Gemfile b/puppet/modules/archive/Gemfile new file mode 100755 index 0000000..45c03ce --- /dev/null +++ b/puppet/modules/archive/Gemfile @@ -0,0 +1,44 @@ +source ENV['GEM_SOURCE'] || "https://rubygems.org" + +group :development, :unit_tests do + gem 'rake', :require => false + gem 'rspec', '< 3.2', :require => false if RUBY_VERSION =~ /^1.8/ + gem 'rspec-puppet', :require => false + gem 'puppetlabs_spec_helper', :require => false + gem 'metadata-json-lint', :require => false + gem 'puppet-lint', :require => false + gem 'puppet-lint-unquoted_string-check', :require => false + gem 'puppet-lint-empty_string-check', :require => false + gem 'puppet-lint-spaceship_operator_without_tag-check', :require => false + gem 'puppet-lint-variable_contains_upcase', :require => false + gem 'puppet-lint-absolute_classname-check', :require => false + gem 'puppet-lint-undef_in_function-check', :require => false + gem 'puppet-lint-leading_zero-check', :require => false + gem 'puppet-lint-trailing_comma-check', :require => false + gem 'puppet-lint-file_ensure-check', :require => false + gem 'puppet-lint-version_comparison-check', :require => false + gem 'puppet-lint-fileserver-check', :require => false + gem 'puppet-lint-file_source_rights-check', :require => false + gem 'rspec-puppet-facts', :require => false +end + +group :system_tests do + gem 'beaker', :require => false + gem 'beaker-rspec', :require => false + gem 'beaker_spec_helper', :require => false + gem 'serverspec', :require => false +end + +if facterversion = ENV['FACTER_GEM_VERSION'] + gem 'facter', facterversion, :require => false +else + gem 'facter', :require => false +end + +if puppetversion = ENV['PUPPET_GEM_VERSION'] + gem 'puppet', puppetversion, :require => false +else + gem 'puppet', :require => false +end + +# vim:ft=ruby diff --git a/puppet/modules/archive/LICENSE b/puppet/modules/archive/LICENSE new file mode 100755 index 0000000..d645695 --- /dev/null +++ b/puppet/modules/archive/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/puppet/modules/archive/README.md b/puppet/modules/archive/README.md new file mode 100755 index 0000000..8e2b785 --- /dev/null +++ b/puppet/modules/archive/README.md @@ -0,0 +1,112 @@ +Archive Puppet Module +==================== + +[![Puppet Forge Version](http://img.shields.io/puppetforge/v/camptocamp/archive.svg)](https://forge.puppetlabs.com/camptocamp/archive) +[![Puppet Forge Downloads](http://img.shields.io/puppetforge/dt/camptocamp/archive.svg)](https://forge.puppetlabs.com/camptocamp/archive) +[![Build Status](https://img.shields.io/travis/camptocamp/puppet-archive/master.svg)](https://travis-ci.org/camptocamp/puppet-archive) +[![Gemnasium](https://img.shields.io/gemnasium/camptocamp/puppet-archive.svg)](https://gemnasium.com/camptocamp/puppet-archive) +[![By Camptocamp](https://img.shields.io/badge/by-camptocamp-fb7047.svg)](http://www.camptocamp.com) + +Overview +-------- + +Puppet Module to download and extract tar and zip archives based on [camptocamp/puppet-archive](https://github.com/camptocamp/puppet-archive). + +Supported archive types are: + +- `tar.gz`, `tgz` +- `tar.bz2`, `tbz2` +- `tar.xz`, `txz` +- `zip` + +Features: + +- Ability to follow redirects +- Supports checksum matching + +Usage +----- + +Example: + + archive { 'apache-tomcat-6.0.26': + ensure => present, + url => 'http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.26/bin/apache-tomcat-6.0.26.tar.gz', + target => '/opt', + } + +You can have archive follow redirects by setting: + +``` +follow_redirects => true +```` + +The default archive format is ```tar.gz```. To use another supported format you must specify the extenstion: + +``` +extension => "zip" +``` + +By default archive will try and find a matching checksum file to verify the download. To disable this behavior set the ```checksum``` option to ```false```: + +``` +checksum => false +``` + +You can specify a ```digest_url```, ```digest_string``` and ```digest_type``` to verify archive integrity. + +For `.tar.gz` and `tar.bz2` archives, the extract step's `--strip-components=n` flag can be accessed. This can be used to [change the name of the extracted directory](http://unix.stackexchange.com/questions/11018/how-to-choose-directory-name-during-untarring). + +``` +strip_components => 1 +``` + +``` +purge_target => false +``` + +By default the target directory is left intact, this option can be used to `rm -rf` the target directory prior to extraction. + +This full example will download the [packer](packer.io) tool to ```/usr/local/bin```: + +``` +archive { '0.5.1_linux_amd64': + ensure => present, + url => 'https://dl.bintray.com/mitchellh/packer/0.5.1_linux_amd64.zip', + target => '/usr/local/bin', + follow_redirects => true, + extension => 'zip', + checksum => false, + src_target => '/tmp' +} +``` + +You can also specifiy a global user to be used for the whole download and extract operation. Note that the module doesn't handle the right of the specified user on the src_target directory. +``` + +archive { '0.5.1_linux_amd64': + ensure => present, + url => 'https://dl.bintray.com/mitchellh/packer/0.5.1_linux_amd64.zip', + target => '/usr/local/bin', + follow_redirects => true, + extension => 'zip', + checksum => false, + user => 'camptocamp', + src_target => '/home/camptocamp' +} +``` + +License +------- + +Copyright (c) 2012 Camptocamp SA + +This script is licensed under the Apache License, Version 2.0. + +See http://www.apache.org/licenses/LICENSE-2.0.html for the full license text. + + +Support +------- + +Please log tickets and issues at our [project site](https://github.com/camptocamp/puppet-archive/issues). diff --git a/puppet/modules/archive/Rakefile b/puppet/modules/archive/Rakefile new file mode 100755 index 0000000..f87e608 --- /dev/null +++ b/puppet/modules/archive/Rakefile @@ -0,0 +1,11 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' + +Rake::Task[:lint].clear +PuppetLint::RakeTask.new :lint do |config| + config.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp", "vendor/**/*.pp"] + config.disable_checks = ['80chars'] + config.fail_on_warnings = true +end + +PuppetSyntax.exclude_paths = ["spec/fixtures/**/*.pp", "vendor/**/*"] diff --git a/puppet/modules/archive/manifests/download.pp b/puppet/modules/archive/manifests/download.pp new file mode 100755 index 0000000..ef4eb21 --- /dev/null +++ b/puppet/modules/archive/manifests/download.pp @@ -0,0 +1,190 @@ +# == Definition: archive::download +# +# Archive downloader with integrity verification. +# +# Parameters: +# +# - *$url: +# - *$digest_url: +# - *$digest_string: Default value undef +# - *$digest_type: Default value "md5". +# - *$timeout: Default value 120. +# - *$src_target: Default value "/usr/src". +# - *$allow_insecure: Default value false. +# - *$follow_redirects: Default value false. +# - *$verbose: Default value true. +# - *$proxy_server: Default value undef. +# - *$user: The user used to download the archive +# +# Example usage: +# +# archive::download {"apache-tomcat-6.0.26.tar.gz": +# ensure => present, +# url => "http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.26/bin/apache-tomcat-6.0.26.tar.gz", +# } +# +# archive::download {"apache-tomcat-6.0.26.tar.gz": +# ensure => present, +# digest_string => "f9eafa9bfd620324d1270ae8f09a8c89", +# url => "http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.26/bin/apache-tomcat-6.0.26.tar.gz", +# } +# +define archive::download ( + $url, + $ensure=present, + $checksum=true, + $digest_url=undef, + $digest_string=undef, + $digest_type='md5', + $timeout=120, + $src_target='/usr/src', + $allow_insecure=false, + $follow_redirects=false, + $verbose=true, + $path=$::path, + $proxy_server=undef, + $user=undef, +) { + + $insecure_arg = $allow_insecure ? { + true => '-k', + default => '', + } + + $redirect_arg = $follow_redirects ? { + true => '-L', + default => '', + } + + if !defined(Package['curl']) { + package{'curl': + ensure => present, + } + } + + if $proxy_server { + $proxy_option = "--proxy ${proxy_server}" + } else { + $proxy_option = undef + } + + case $checksum { + true : { + case $digest_type { + 'md5','sha1','sha224','sha256','sha384','sha512' : { + $checksum_cmd = "${digest_type}sum -c ${name}.${digest_type}" + } + default: { fail 'Unimplemented digest type' } + } + + if $digest_url and $digest_string { + fail 'digest_url and digest_string should not be used together !' + } + + if $digest_string { + case $ensure { + 'present': { + file {"${src_target}/${name}.${digest_type}": + ensure => $ensure, + content => "${digest_string} *${name}", + owner => $user, + notify => Exec["download archive ${name} and check sum"], + } + } + 'absent': { + file {"${src_target}/${name}.${digest_type}": + ensure => absent, + purge => true, + owner => $user, + force => true, + } + } + default: { + fail('$ensure can only be present or absent.') + } + } + } else { + case $ensure { + 'present': { + + if !$digest_url { + $digest_src = "${url}.${digest_type}" + } else { + $digest_src = $digest_url + } + + + exec {"download digest of archive ${name}": + command => "curl ${proxy_option} -s -S ${insecure_arg} ${redirect_arg} -o ${src_target}/${name}.${digest_type} '${digest_src}'", + creates => "${src_target}/${name}.${digest_type}", + timeout => $timeout, + path => $path, + notify => Exec["download archive ${name} and check sum"], + user => $user, + require => Package['curl'], + } + + } + 'absent': { + file{"${src_target}/${name}.${digest_type}": + ensure => absent, + purge => true, + owner => $user, + force => true, + } + } + default: { + fail('$ensure can only be present or absent.') + } + } + } + } + false : { + $checksum_cmd = undef # Fix for strict_variables + if $verbose { + notice 'No checksum for this archive' + } + } + default: { fail ( "Unknown checksum value: '${checksum}'" ) } + } + + case $ensure { + 'present': { + $_notify = $checksum ? { + true => Exec["rm-on-error-${name}"], + default => undef, + } + $refreshonly = $checksum ? { + true => true, + default => undef, + } + exec {"download archive ${name} and check sum": + command => "curl ${proxy_option} -s -S ${insecure_arg} ${redirect_arg} -o ${src_target}/${name} '${url}'", + creates => "${src_target}/${name}", + logoutput => true, + timeout => $timeout, + path => $path, + require => Package['curl'], + notify => $_notify, + user => $user, + refreshonly => $refreshonly, + } + + exec {"rm-on-error-${name}": + command => "rm -f ${src_target}/${name} ${src_target}/${name}.${digest_type} && exit 1", + unless => $checksum_cmd, + cwd => $src_target, + path => $path, + refreshonly => true, + } + } + 'absent': { + file {"${src_target}/${name}": + ensure => absent, + purge => true, + force => true, + } + } + default: { fail ( "Unknown ensure value: '${ensure}'" ) } + } +} diff --git a/puppet/modules/archive/manifests/extract.pp b/puppet/modules/archive/manifests/extract.pp new file mode 100755 index 0000000..b5e47a9 --- /dev/null +++ b/puppet/modules/archive/manifests/extract.pp @@ -0,0 +1,93 @@ +# == Definition: archive::extract +# +# Archive extractor. +# +# Parameters: +# +# - *$target: Destination directory +# - *$src_target: Default value "/usr/src". +# - *$root_dir: Default value "". +# - *$extension: Default value ".tar.gz". +# - *$timeout: Default value 120. +# - *$strip_components: Default value 0. +# - *$user: The user used to do the extraction. +# +# Example usage: +# +# archive::extract {"apache-tomcat-6.0.26": +# ensure => present, +# target => "/opt", +# } +# +# This means we want to extract the local archive +# (maybe downloaded with archive::download) +# '/usr/src/apache-tomcat-6.0.26.tar.gz' in '/src/apache-tomcat-6.0.26' +# +# Warning: +# +# The parameter *$root_dir* must be used if the root directory of the archive +# is different from the name of the archive *$name*. To extract the name of +# the root directory use the commands "tar tf archive.tar.gz" or +# "unzip -l archive.zip" +# +define archive::extract ( + $target, + $ensure=present, + $src_target='/usr/src', + $root_dir=undef, + $extension='tar.gz', + $timeout=120, + $path=$::path, + $strip_components=0, + $purge=false, + $user=undef, +) { + + if $root_dir { + $extract_dir = "${target}/${root_dir}" + } else { + $extract_dir = "${target}/${name}" + } + + case $ensure { + 'present': { + + $extract_zip = "unzip -o ${src_target}/${name}.${extension} -d ${target}" + $extract_targz = "tar --no-same-owner --no-same-permissions --strip-components=${strip_components} -xzf ${src_target}/${name}.${extension} -C ${target}" + $extract_tarbz2 = "tar --no-same-owner --no-same-permissions --strip-components=${strip_components} -xjf ${src_target}/${name}.${extension} -C ${target}" + $extract_tarxz = "tar --no-same-owner --no-same-permissions --strip-components=${strip_components} -xpf ${src_target}/${name}.${extension} -C ${target}" + + $purge_command = $purge ? { + true => "rm -rf ${target} && ", + default => '', + } + + $command = $extension ? { + 'zip' => "${purge_command}mkdir -p ${target} && ${extract_zip}", + 'tar.gz' => "${purge_command}mkdir -p ${target} && ${extract_targz}", + 'tgz' => "${purge_command}mkdir -p ${target} && ${extract_targz}", + 'tar.bz2' => "${purge_command}mkdir -p ${target} && ${extract_tarbz2}", + 'tgz2' => "${purge_command}mkdir -p ${target} && ${extract_tarbz2}", + 'tar.xz' => "${purge_command}mkdir -p ${target} && ${extract_tarxz}", + 'txz' => "${purge_command}mkdir -p ${target} && ${extract_tarxz}", + default => fail ( "Unknown extension value '${extension}'" ), + } + exec {"${name} unpack": + command => $command, + creates => $extract_dir, + timeout => $timeout, + user => $user, + path => $path, + } + } + 'absent': { + file {$extract_dir: + ensure => absent, + recurse => true, + purge => true, + force => true, + } + } + default: { err ( "Unknown ensure value: '${ensure}'" ) } + } +} diff --git a/puppet/modules/archive/manifests/init.pp b/puppet/modules/archive/manifests/init.pp new file mode 100755 index 0000000..cd32609 --- /dev/null +++ b/puppet/modules/archive/manifests/init.pp @@ -0,0 +1,82 @@ +# == Definition: archive +# +# Download and extract an archive. +# +# Parameters: +# +# - *$url: +# - *$target: Destination directory +# - *$purge_target: Purge Destination prior to extraction. Default false +# - *$checksum: Default value "true" +# - *$digest_url: Default value undef +# - *$digest_string: Default value undef +# - *$digest_type: Default value "md5" +# - *$src_target: Default value "/usr/src" +# - *$root_dir: Default value undef +# - *$extension: Default value ".tar.gz" +# - *$timeout: Default value 120 +# - *$allow_insecure: Default value false +# - *$follow_redirects: Default value false +# - *$verbose: Default value true +# - *$strip_components: Default value 0 +# - *$proxy_server: Default value undef +# - *$user: User used to do the download and the extraction. The final directory will be used by him/her. +# +# Example usage: +# +# archive {"apache-tomcat-6.0.26": +# ensure => present, +# url => "http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.26/bin/apache-tomcat-6.0.26.tar.gz", +# target => "/opt", +# } +# +define archive ( + $url, + $target, + $ensure=present, + $checksum=true, + $digest_url=undef, + $digest_string=undef, + $digest_type='md5', + $timeout=120, + $root_dir=undef, + $extension='tar.gz', + $src_target='/usr/src', + $allow_insecure=false, + $follow_redirects=false, + $verbose=true, + $strip_components=0, + $proxy_server=undef, + $purge_target=false, + $user=undef, +) { + + archive::download {"${name}.${extension}": + ensure => $ensure, + url => $url, + checksum => $checksum, + digest_url => $digest_url, + digest_string => $digest_string, + digest_type => $digest_type, + timeout => $timeout, + src_target => $src_target, + allow_insecure => $allow_insecure, + follow_redirects => $follow_redirects, + verbose => $verbose, + proxy_server => $proxy_server, + user => $user, + } + + archive::extract {$name: + ensure => $ensure, + target => $target, + purge => $purge_target, + src_target => $src_target, + root_dir => $root_dir, + extension => $extension, + timeout => $timeout, + strip_components => $strip_components, + require => Archive::Download["${name}.${extension}"], + user => $user, + } +} diff --git a/puppet/modules/archive/manifests/tar_gz.pp b/puppet/modules/archive/manifests/tar_gz.pp new file mode 100755 index 0000000..f912a92 --- /dev/null +++ b/puppet/modules/archive/manifests/tar_gz.pp @@ -0,0 +1,9 @@ +# See README.md for details. +define archive::tar_gz($source, $target, $path=$::path) { + exec {"${name} unpack": + command => "curl -s -S ${source} | tar -xzf - -C ${target} && touch ${name}", + creates => $name, + path => $path, + require => Package[curl], + } +} diff --git a/puppet/modules/archive/manifests/zip.pp b/puppet/modules/archive/manifests/zip.pp new file mode 100755 index 0000000..3b44dfb --- /dev/null +++ b/puppet/modules/archive/manifests/zip.pp @@ -0,0 +1,9 @@ +# See README.md for details. +define archive::zip($source, $target, $path = $::path) { + exec {"${name} unpack": + command => "TMPFILE=\$(mktemp); curl -s -S -o \${TMPFILE}.zip ${source} && unzip \${TMPFILE}.zip -d ${target} && rm \$TMPFILE && rm \${TMPFILE}.zip && touch ${name}", + creates => $name, + path => $::path, + require => Package['unzip'], + } +} diff --git a/puppet/modules/archive/metadata.json b/puppet/modules/archive/metadata.json new file mode 100755 index 0000000..1676af4 --- /dev/null +++ b/puppet/modules/archive/metadata.json @@ -0,0 +1,32 @@ +{ + "name": "camptocamp-archive", + "version": "0.8.0", + "author": "Camptocamp", + "summary": "Camptocamp Archive Module", + "license": "Apache-2.0", + "source": "https://github.com/camptocamp/puppet-archive", + "project_page": "https://github.com/camptocamp/puppet-archive", + "issues_url": "https://github.com/camptocamp/puppet-archive/issues", + "description": "Archive Module for Puppet", + "dependencies": [ + + ], + "operatingsystem_support": [ + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "6", + "7", + "8" + ] + }, + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "5", + "6", + "7" + ] + } + ] +} diff --git a/puppet/modules/archive/spec/acceptance/nodesets/centos-5-x86_64-docker.yml b/puppet/modules/archive/spec/acceptance/nodesets/centos-5-x86_64-docker.yml new file mode 100755 index 0000000..d9a52d8 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/centos-5-x86_64-docker.yml @@ -0,0 +1,13 @@ +HOSTS: + centos-5-x64: + default_apply_opts: + order: random + strict_variables: + platform: el-5-x86_64 + hypervisor : docker + image: centos:5 + # This stops the image from being deleted on completion, speeding up the process. + docker_preserve_image: true +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/centos-6-x86_64-docker.yml b/puppet/modules/archive/spec/acceptance/nodesets/centos-6-x86_64-docker.yml new file mode 100755 index 0000000..b7a4396 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/centos-6-x86_64-docker.yml @@ -0,0 +1,13 @@ +HOSTS: + centos-6-x64: + default_apply_opts: + order: random + strict_variables: + platform: el-6-x86_64 + hypervisor : docker + image: centos:6 + # This stops the image from being deleted on completion, speeding up the process. + docker_preserve_image: true +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/centos-6-x86_64-openstack.yml b/puppet/modules/archive/spec/acceptance/nodesets/centos-6-x86_64-openstack.yml new file mode 100755 index 0000000..e325b9e --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/centos-6-x86_64-openstack.yml @@ -0,0 +1,14 @@ +HOSTS: + centos-6-x64: + default_apply_opts: + order: random + strict_variables: + platform: el-6-x86_64 + hypervisor : openstack + flavor: m1.small + image: centos-6-latest + user: root +CONFIG: + type: foss + log_level: debug + openstack_network: default diff --git a/puppet/modules/archive/spec/acceptance/nodesets/centos-6-x86_64-vagrant.yml b/puppet/modules/archive/spec/acceptance/nodesets/centos-6-x86_64-vagrant.yml new file mode 100755 index 0000000..f06036e --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/centos-6-x86_64-vagrant.yml @@ -0,0 +1,11 @@ +HOSTS: + centos-6-x64: + default_apply_opts: + order: random + strict_variables: + platform: el-6-x86_64 + hypervisor : vagrant + box : camptocamp/centos-6-x86_64 +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/centos-7-x86_64-docker.yml b/puppet/modules/archive/spec/acceptance/nodesets/centos-7-x86_64-docker.yml new file mode 100755 index 0000000..d891edf --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/centos-7-x86_64-docker.yml @@ -0,0 +1,13 @@ +HOSTS: + centos-7-x64: + default_apply_opts: + order: random + strict_variables: + platform: el-7-x86_64 + hypervisor : docker + image: centos:7 + # This stops the image from being deleted on completion, speeding up the process. + docker_preserve_image: true +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/centos-7-x86_64-openstack.yml b/puppet/modules/archive/spec/acceptance/nodesets/centos-7-x86_64-openstack.yml new file mode 100755 index 0000000..9003c86 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/centos-7-x86_64-openstack.yml @@ -0,0 +1,14 @@ +HOSTS: + centos-7-x64: + default_apply_opts: + order: random + strict_variables: + platform: el-7-x86_64 + hypervisor : openstack + flavor: m1.small + image: centos-7-latest + user: centos +CONFIG: + type: foss + log_level: debug + openstack_network: default diff --git a/puppet/modules/archive/spec/acceptance/nodesets/centos-7-x86_64-vagrant.yml b/puppet/modules/archive/spec/acceptance/nodesets/centos-7-x86_64-vagrant.yml new file mode 100755 index 0000000..95402e5 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/centos-7-x86_64-vagrant.yml @@ -0,0 +1,11 @@ +HOSTS: + centos-7-x64: + default_apply_opts: + order: random + strict_variables: + platform: el-7-x86_64 + hypervisor : vagrant + box : camptocamp/centos-7-x86_64 +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/debian-6-x86_64-docker.yml b/puppet/modules/archive/spec/acceptance/nodesets/debian-6-x86_64-docker.yml new file mode 100755 index 0000000..685e2b7 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/debian-6-x86_64-docker.yml @@ -0,0 +1,13 @@ +HOSTS: + debian-6-x64: + default_apply_opts: + order: random + strict_variables: + platform: debian-6-amd64 + hypervisor : docker + image: debian:6 + # This stops the image from being deleted on completion, speeding up the process. + docker_preserve_image: true +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/debian-6-x86_64-openstack.yml b/puppet/modules/archive/spec/acceptance/nodesets/debian-6-x86_64-openstack.yml new file mode 100755 index 0000000..c6c192f --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/debian-6-x86_64-openstack.yml @@ -0,0 +1,14 @@ +HOSTS: + debian-6-x64: + default_apply_opts: + order: random + strict_variables: + platform: debian-6-amd64 + hypervisor : openstack + flavor: m1.small + image: debian-6-latest + user: debian +CONFIG: + type: foss + log_level: debug + openstack_network: default diff --git a/puppet/modules/archive/spec/acceptance/nodesets/debian-6-x86_64-vagrant.yml b/puppet/modules/archive/spec/acceptance/nodesets/debian-6-x86_64-vagrant.yml new file mode 100755 index 0000000..03db0fa --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/debian-6-x86_64-vagrant.yml @@ -0,0 +1,11 @@ +HOSTS: + debian-6-x64: + default_apply_opts: + order: random + strict_variables: + platform: debian-6-amd64 + hypervisor : vagrant + box : puppetlabs/debian-6.0.10-64-nocm +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/debian-7-x86_64-docker.yml b/puppet/modules/archive/spec/acceptance/nodesets/debian-7-x86_64-docker.yml new file mode 100755 index 0000000..0be8845 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/debian-7-x86_64-docker.yml @@ -0,0 +1,13 @@ +HOSTS: + debian-7-x64: + default_apply_opts: + order: random + strict_variables: + platform: debian-7-amd64 + hypervisor : docker + image: debian:7 + # This stops the image from being deleted on completion, speeding up the process. + docker_preserve_image: true +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/debian-7-x86_64-openstack.yml b/puppet/modules/archive/spec/acceptance/nodesets/debian-7-x86_64-openstack.yml new file mode 100755 index 0000000..017b4c7 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/debian-7-x86_64-openstack.yml @@ -0,0 +1,14 @@ +HOSTS: + debian-7-x64: + default_apply_opts: + order: random + strict_variables: + platform: debian-7-amd64 + hypervisor : openstack + flavor: m1.small + image: debian-7-latest + user: debian +CONFIG: + type: foss + log_level: debug + openstack_network: default diff --git a/puppet/modules/archive/spec/acceptance/nodesets/debian-7-x86_64-vagrant.yml b/puppet/modules/archive/spec/acceptance/nodesets/debian-7-x86_64-vagrant.yml new file mode 100755 index 0000000..8ed1264 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/debian-7-x86_64-vagrant.yml @@ -0,0 +1,11 @@ +HOSTS: + debian-7-x64: + default_apply_opts: + order: random + strict_variables: + platform: debian-7-amd64 + hypervisor : vagrant + box : camptocamp/debian-7-amd64 +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/debian-8-x86_64-docker.yml b/puppet/modules/archive/spec/acceptance/nodesets/debian-8-x86_64-docker.yml new file mode 100755 index 0000000..d3b89d9 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/debian-8-x86_64-docker.yml @@ -0,0 +1,13 @@ +HOSTS: + debian-8-x64: + default_apply_opts: + order: random + strict_variables: + platform: debian-8-amd64 + hypervisor : docker + image: debian:8 + # This stops the image from being deleted on completion, speeding up the process. + docker_preserve_image: true +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/debian-8-x86_64-openstack.yml b/puppet/modules/archive/spec/acceptance/nodesets/debian-8-x86_64-openstack.yml new file mode 100755 index 0000000..003b6f4 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/debian-8-x86_64-openstack.yml @@ -0,0 +1,14 @@ +HOSTS: + debian-8-x64: + default_apply_opts: + order: random + strict_variables: + platform: debian-8-amd64 + hypervisor : openstack + flavor: m1.small + image: debian-8-latest + user: debian +CONFIG: + type: foss + log_level: debug + openstack_network: default diff --git a/puppet/modules/archive/spec/acceptance/nodesets/debian-8-x86_64-vagrant.yml b/puppet/modules/archive/spec/acceptance/nodesets/debian-8-x86_64-vagrant.yml new file mode 100755 index 0000000..5cc7f0c --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/debian-8-x86_64-vagrant.yml @@ -0,0 +1,11 @@ +HOSTS: + debian-8-x64: + default_apply_opts: + order: random + strict_variables: + platform: debian-8-amd64 + hypervisor : vagrant + box : camptocamp/debian-8-amd64 +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-10.04-x86_64-docker.yml b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-10.04-x86_64-docker.yml new file mode 100755 index 0000000..933dee6 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-10.04-x86_64-docker.yml @@ -0,0 +1,13 @@ +HOSTS: + ubuntu-1004-x64: + default_apply_opts: + order: random + strict_variables: + platform: ubuntu-10.04-amd64 + hypervisor : docker + image: ubuntu:10.04 + # This stops the image from being deleted on completion, speeding up the process. + docker_preserve_image: true +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-12.04-x86_64-docker.yml b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-12.04-x86_64-docker.yml new file mode 100755 index 0000000..92a7901 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-12.04-x86_64-docker.yml @@ -0,0 +1,13 @@ +HOSTS: + ubuntu-1204-x64: + default_apply_opts: + order: random + strict_variables: + platform: ubuntu-12.04-amd64 + hypervisor : docker + image: ubuntu:12.04 + # This stops the image from being deleted on completion, speeding up the process. + docker_preserve_image: true +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-12.04-x86_64-openstack.yml b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-12.04-x86_64-openstack.yml new file mode 100755 index 0000000..f81b04b --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-12.04-x86_64-openstack.yml @@ -0,0 +1,14 @@ +HOSTS: + ubuntu-1204-x64: + default_apply_opts: + order: random + strict_variables: + platform: ubuntu-12.04-amd64 + hypervisor : openstack + flavor: m1.small + image: ubuntu-1204-latest + user: ubuntu +CONFIG: + type: foss + log_level: debug + openstack_network: default diff --git a/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-14.04-x86_64-docker.yml b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-14.04-x86_64-docker.yml new file mode 100755 index 0000000..7716f94 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-14.04-x86_64-docker.yml @@ -0,0 +1,13 @@ +HOSTS: + ubuntu-1404-x64: + default_apply_opts: + order: random + strict_variables: + platform: ubuntu-14.04-amd64 + hypervisor : docker + image: ubuntu:14.04 + # This stops the image from being deleted on completion, speeding up the process. + docker_preserve_image: true +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-14.04-x86_64-openstack.yml b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-14.04-x86_64-openstack.yml new file mode 100755 index 0000000..2eeb912 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-14.04-x86_64-openstack.yml @@ -0,0 +1,14 @@ +HOSTS: + ubuntu-1404-x64: + default_apply_opts: + order: random + strict_variables: + platform: ubuntu-14.04-amd64 + hypervisor : openstack + flavor: m1.small + image: ubuntu-1404-latest + user: ubuntu +CONFIG: + type: foss + log_level: debug + openstack_network: default diff --git a/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-14.04-x86_64-vagrant.yml b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-14.04-x86_64-vagrant.yml new file mode 100755 index 0000000..3b37695 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-14.04-x86_64-vagrant.yml @@ -0,0 +1,11 @@ +HOSTS: + ubuntu-1404-x64: + default_apply_opts: + order: random + strict_variables: + platform: ubuntu-14.04-amd64 + hypervisor : vagrant + box : puppetlabs/ubuntu-14.04-64-nocm +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-14.10-x86_64-docker.yml b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-14.10-x86_64-docker.yml new file mode 100755 index 0000000..256b004 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-14.10-x86_64-docker.yml @@ -0,0 +1,13 @@ +HOSTS: + ubuntu-1410-x64: + default_apply_opts: + order: random + strict_variables: + platform: ubuntu-14.10-amd64 + hypervisor : docker + image: ubuntu:14.10 + # This stops the image from being deleted on completion, speeding up the process. + docker_preserve_image: true +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-14.10-x86_64-openstack.yml b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-14.10-x86_64-openstack.yml new file mode 100755 index 0000000..58a2acd --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-14.10-x86_64-openstack.yml @@ -0,0 +1,14 @@ +HOSTS: + ubuntu-1410-x64: + default_apply_opts: + order: random + strict_variables: + platform: ubuntu-14.10-amd64 + hypervisor : openstack + flavor: m1.small + image: ubuntu-1410-latest + user: ubuntu +CONFIG: + type: foss + log_level: debug + openstack_network: default diff --git a/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-15.04-x86_64-docker.yml b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-15.04-x86_64-docker.yml new file mode 100755 index 0000000..800da28 --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-15.04-x86_64-docker.yml @@ -0,0 +1,13 @@ +HOSTS: + ubuntu-1504-x64: + default_apply_opts: + order: random + strict_variables: + platform: ubuntu-15.04-amd64 + hypervisor : docker + image: ubuntu:15.04 + # This stops the image from being deleted on completion, speeding up the process. + docker_preserve_image: true +CONFIG: + type: foss + log_level: debug diff --git a/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-15.04-x86_64-openstack.yml b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-15.04-x86_64-openstack.yml new file mode 100755 index 0000000..22ef76c --- /dev/null +++ b/puppet/modules/archive/spec/acceptance/nodesets/ubuntu-15.04-x86_64-openstack.yml @@ -0,0 +1,14 @@ +HOSTS: + ubuntu-1504-x64: + default_apply_opts: + order: random + strict_variables: + platform: ubuntu-15.04-amd64 + hypervisor : openstack + flavor: m1.small + image: ubuntu-1504-latest + user: ubuntu +CONFIG: + type: foss + log_level: debug + openstack_network: default diff --git a/puppet/modules/archive/spec/defines/archive_spec.rb b/puppet/modules/archive/spec/defines/archive_spec.rb new file mode 100755 index 0000000..b18995a --- /dev/null +++ b/puppet/modules/archive/spec/defines/archive_spec.rb @@ -0,0 +1,72 @@ +require 'spec_helper' + +describe 'archive' do + let(:title) { 'apache-tomcat-6.0.26' } + + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:facts) do + facts + end + + context 'without parameters' do + it { expect { is_expected.to compile.with_all_deps }.to raise_error(/Must pass/) } + end + + context 'with url, without target' do + let(:params) do + { + :url => 'http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.26/bin/apache-tomcat-6.0.26.tar.gz', + } + end + + it { expect { is_expected.to compile.with_all_deps }.to raise_error(/Must pass target/) } + end + + context 'with target, without url' do + let(:params) do + { + :target => '/opt', + } + end + + it { expect { is_expected.to compile.with_all_deps }.to raise_error(/Must pass url/) } + end + + context 'with url and target' do + let(:params) do + { + :url => 'http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.26/bin/apache-tomcat-6.0.26.tar.gz', + :target => '/opt', + } + end + + it { is_expected.to compile.with_all_deps } + end + + context 'with url and purge target' do + let(:params) do + { + :url => 'http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.26/bin/apache-tomcat-6.0.26.tar.gz', + :target => '/opt/tc6', + :purge_target => true, + } + end + + it { is_expected.to compile.with_all_deps } + end + + context 'with url, target and user' do + let(:params) do + { + :url => 'http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.26/bin/apache-tomcat-6.0.26.tar.gz', + :target => '/opt', + :user => 'root', + } + end + + it { is_expected.to compile.with_all_deps } + end + end + end +end diff --git a/puppet/modules/archive/spec/spec.opts b/puppet/modules/archive/spec/spec.opts new file mode 100755 index 0000000..91cd642 --- /dev/null +++ b/puppet/modules/archive/spec/spec.opts @@ -0,0 +1,6 @@ +--format +s +--colour +--loadby +mtime +--backtrace diff --git a/puppet/modules/archive/spec/spec_helper.rb b/puppet/modules/archive/spec/spec_helper.rb new file mode 100755 index 0000000..94d30d5 --- /dev/null +++ b/puppet/modules/archive/spec/spec_helper.rb @@ -0,0 +1,42 @@ +require 'puppetlabs_spec_helper/module_spec_helper' +require 'rspec-puppet-facts' +include RspecPuppetFacts + + +RSpec.configure do |c| + c.include PuppetlabsSpec::Files + + c.before :each do + # Store any environment variables away to be restored later + @old_env = {} + ENV.each_key {|k| @old_env[k] = ENV[k]} + + c.strict_variables = Gem::Version.new(Puppet.version) >= Gem::Version.new('3.5') + Puppet.features.stubs(:root?).returns(true) + end + + c.after :each do + PuppetlabsSpec::Files.cleanup + end +end + +require 'pathname' +dir = Pathname.new(__FILE__).parent +Puppet[:modulepath] = File.join(dir, 'fixtures', 'modules') + +# There's no real need to make this version dependent, but it helps find +# regressions in Puppet +# +# 1. Workaround for issue #16277 where default settings aren't initialised from +# a spec and so the libdir is never initialised (3.0.x) +# 2. Workaround for 2.7.20 that now only loads types for the current node +# environment (#13858) so Puppet[:modulepath] seems to get ignored +# 3. Workaround for 3.5 where context hasn't been configured yet, +# ticket https://tickets.puppetlabs.com/browse/MODULES-823 +# +ver = Gem::Version.new(Puppet.version.split('-').first) +if Gem::Requirement.new("~> 2.7.20") =~ ver || Gem::Requirement.new("~> 3.0.0") =~ ver || Gem::Requirement.new("~> 3.5") =~ ver || Gem::Requirement.new("~> 4.0") + puts "augeasproviders: setting Puppet[:libdir] to work around broken type autoloading" + # libdir is only a single dir, so it can only workaround loading of one external module + Puppet[:libdir] = "#{Puppet[:modulepath]}/augeasproviders_core/lib" +end diff --git a/puppet/modules/box/files/scripts/.gitignore b/puppet/modules/box/files/scripts/.gitignore new file mode 100644 index 0000000..fe4c419 --- /dev/null +++ b/puppet/modules/box/files/scripts/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +/composer.* \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Apc/Apc.php b/puppet/modules/box/files/scripts/Command/Apc/Apc.php index 2b5769d..85692e6 100644 --- a/puppet/modules/box/files/scripts/Command/Apc/Apc.php +++ b/puppet/modules/box/files/scripts/Command/Apc/Apc.php @@ -9,7 +9,7 @@ abstract class Apc extends Command { public static $files; - protected $_ini_files = array('apc.ini', 'apcu.ini', 'opcache.ini', 'zzz_apc.ini', 'zzz_apcu.ini', 'zzz_opcache.ini'); + protected $_ini_files = array('apc.ini', 'apcu.ini', 'opcache.ini'); public function __construct($name = null) { @@ -19,28 +19,4 @@ public function __construct($name = null) self::$files = __DIR__.'/../../util'; } } - - protected function _getConfigFiles($basenames = array()) - { - $inis = array(); - $paths = array('/etc/php5/mods-available/'); - - $installs = glob('/opt/php/php-*/etc/conf.d', GLOB_ONLYDIR); - $installs = array_unique(array_filter($installs)); - - $paths = array_merge($paths, $installs); - - foreach($paths as $path) - { - foreach($basenames as $basename) - { - $fullpath = $path . '/' . $basename; - if(file_exists($fullpath)) { - $inis[] = $fullpath; - } - } - } - - return $inis; - } } \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Apc/Disable.php b/puppet/modules/box/files/scripts/Command/Apc/Disable.php index 180dd75..dacd9e6 100644 --- a/puppet/modules/box/files/scripts/Command/Apc/Disable.php +++ b/puppet/modules/box/files/scripts/Command/Apc/Disable.php @@ -3,6 +3,7 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\OutputInterface; class Disable extends Apc @@ -15,14 +16,13 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { - $files = $this->_getConfigFiles($this->_ini_files); + $files = \Helper\Ini::findIniFiles($this->_ini_files); - foreach($files as $file) - { - `sudo sed -i 's#^\(extension\|zend_extension\)=#; \\1=#' $file`; + foreach($files as $file) { + \Helper\Ini::update($file, 'apc.enabled', '0'); } - exec('sudo service apache2 restart 2>&1 1> /dev/null'); + $this->getApplication()->find('server:restart')->run(new ArrayInput(array('command' => 'server:restart', 'service' => array('apache'))), $output); $output->writeln('APC has been disabled'); } diff --git a/puppet/modules/box/files/scripts/Command/Apc/Enable.php b/puppet/modules/box/files/scripts/Command/Apc/Enable.php index 280b843..9c17530 100644 --- a/puppet/modules/box/files/scripts/Command/Apc/Enable.php +++ b/puppet/modules/box/files/scripts/Command/Apc/Enable.php @@ -3,6 +3,7 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\OutputInterface; class Enable extends Apc @@ -15,13 +16,13 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { - $files = $this->_getConfigFiles($this->_ini_files); + $files = \Helper\Ini::findIniFiles($this->_ini_files); foreach($files as $file) { - `sudo sed -i 's#^; \(extension\|zend_extension\)=#\\1=#' $file`; + \Helper\Ini::update($file, 'apc.enabled', '1'); } - exec('sudo service apache2 restart 2>&1 1> /dev/null'); + $this->getApplication()->find('server:restart')->run(new ArrayInput(array('command' => 'server:restart', 'service' => array('apache'))), $output); $output->writeln('APC has been enabled'); } diff --git a/puppet/modules/box/files/scripts/Command/Backup.php b/puppet/modules/box/files/scripts/Command/Backup.php new file mode 100644 index 0000000..59ac8c8 --- /dev/null +++ b/puppet/modules/box/files/scripts/Command/Backup.php @@ -0,0 +1,30 @@ +setName('backup') + ->setDescription('Backup the MySQL databases and Apache2 virtual hosts') + ->addOption('archive', 'a', InputOption::VALUE_REQUIRED, 'Full path to backup archive', '/vagrant/joomla-box-backup.tar'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $archive = $input->getOption('archive'); + + if ((file_exists($archive) && !is_writable($archive)) || !is_writable(dirname($archive))) { + throw new \RuntimeException('Backup destination ' . $archive . ' is not writable.'); + } + + $output->writeln('Creating backup archive ' . basename($archive) . ''); + + passthru("/bin/bash /home/vagrant/triggers/backup.sh $archive"); + } +} \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Php/Engine.php b/puppet/modules/box/files/scripts/Command/Php/Engine.php new file mode 100644 index 0000000..647cee6 --- /dev/null +++ b/puppet/modules/box/files/scripts/Command/Php/Engine.php @@ -0,0 +1,71 @@ +setName('php:engine') + ->setDescription('Show current PHP engine or switch to another engine.') + ->addArgument( + 'engine', + InputArgument::OPTIONAL, + 'Desired PHP engine to use for virtual hosts. Omit to get current engine. Supported values: zend|hhvm' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $currentEngine = \Helper\System::getEngine(); + $engine = strtolower($input->getArgument('engine')); + + if (empty($engine)) + { + $output->writeln(sprintf("Current engine is %s!", $currentEngine)); + + return; + } + + if (!in_array($engine, array('zend', 'hhvm'))) { + throw new \RuntimeException('Unknown engine "' . $engine. '"'); + } + + if ($currentEngine === $engine) + { + $output->writeln(sprintf("[warning] Engine is already set to %s!", $engine)); + + return; + } + + switch ($engine) + { + case 'hhvm': + `sudo a2enconf hhvm`; + `sudo a2dismod php5`; + + if (file_exists('/etc/apache2/mods-available/php7.conf')) { + `sudo a2dismod php7`; + } + break; + case 'zend': + `sudo a2disconf hhvm`; + + if (version_compare(\Helper\System::getZendPHPVersion(), '7.0.0alpha1', '<')) { + $php = 'php5'; + } + else $php = 'php7'; + + `sudo a2enmod $php`; + break; + } + + `sudo service apache2 restart`; + + $output->writeln('Switched engine to ' . $engine . ''); + } +} \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Php/Ini.php b/puppet/modules/box/files/scripts/Command/Php/Ini.php index a61c3a5..50d8c7f 100644 --- a/puppet/modules/box/files/scripts/Command/Php/Ini.php +++ b/puppet/modules/box/files/scripts/Command/Php/Ini.php @@ -3,6 +3,7 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -33,7 +34,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $key = $input->getArgument('key'); $value = $input->getArgument('value'); - if ($input->getOPtion('list-files') || empty($key)) { + if ($input->getOption('list-files') || empty($key)) { $this->_listIniFiles(); } @@ -41,7 +42,7 @@ protected function execute(InputInterface $input, OutputInterface $output) return; } - $current = $this->_getConfigValue($key); + $current = \Helper\Ini::getPHPConfig($key); if ($current === false) { @@ -60,37 +61,31 @@ protected function execute(InputInterface $input, OutputInterface $output) if ($ini !== false) { - $this->_updateIni($ini, $key, $value); + \Helper\Ini::update($ini, $key, $value); - `sudo service apache2 restart 2>&1 1> /dev/null`; + $this->getApplication()->find('server:restart')->run(new ArrayInput(array('command' => 'server:restart')), $output); - $output->writeln("$key value is now '$value', was '$current'"); + $output->writeln("$key value is now $value, was $current"); } else $output->write('Error: failed to find PHP\'s additional config directory (config-file-scan-dir)!'); } - else $output->writeln("$key value is $current"); + else $output->writeln("$key value is $current"); } - protected function _getConfigValue($key) + protected function _getIniOverride() { - $current = `php -r "\\\$value = ini_get('$key'); echo \\\$value === false ? 'unknown-directive' : \\\$value;"`; - - if ($current == 'unknown-directive') { - return false; + if (\Helper\System::getEngine() === 'hhvm') { + return '/etc/hhvm/php.ini'; } - return $current; - } - - protected function _getIniOverride() - { - $filelist = `php -r 'echo php_ini_scanned_files();'`; + $bin = \Helper\System::getPHPCommand(); + $filelist = `$bin -r 'echo php_ini_scanned_files();'`; if (strpos($filelist, ',')) { $files = explode(',', $filelist); $file = array_shift($files); - $path = dirname($file) . DIRECTORY_SEPARATOR . 'zzz_custom.ini'; + $path = dirname($file) . DIRECTORY_SEPARATOR . '99-custom.ini'; if (!file_exists($path)) { touch($path); @@ -104,7 +99,8 @@ protected function _getIniOverride() protected function _listIniFiles() { - $filelist = `php -r 'echo php_ini_scanned_files();'`; + $bin = \Helper\System::getPHPCommand(); + $filelist = `$bin -r 'echo php_ini_scanned_files();'`; if (strpos($filelist, ',')) { @@ -117,21 +113,4 @@ protected function _listIniFiles() return false; } - - protected function _updateIni($ini, $key, $value) - { - $values = parse_ini_file($ini); - $values[$key] = $value; - - $string = ''; - foreach($values as $k => $v) - { - if (!empty($v) || $v === '0') { - $string .= "$k = $v" . PHP_EOL; - } - } - - `sudo chmod o+rw $ini`; - file_put_contents($ini, $string); - } } \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Php/ListVersion.php b/puppet/modules/box/files/scripts/Command/Php/ListVersion.php index 27bb303..c87e26d 100644 --- a/puppet/modules/box/files/scripts/Command/Php/ListVersion.php +++ b/puppet/modules/box/files/scripts/Command/Php/ListVersion.php @@ -15,6 +15,14 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { + if (\Helper\System::getEngine() === 'hhvm') + { + $output->writeln('[notice] You are currently running the HHVM engine'); + $output->writeln('[notice] Switch back to the Zend engine to manage Zend PHP versions'); + + exit(); + } + passthru('phpmanager available'); } } \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Php/Remove.php b/puppet/modules/box/files/scripts/Command/Php/Remove.php index e1c77ea..fa91085 100644 --- a/puppet/modules/box/files/scripts/Command/Php/Remove.php +++ b/puppet/modules/box/files/scripts/Command/Php/Remove.php @@ -21,6 +21,14 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { + if (\Helper\System::getEngine() === 'hhvm') + { + $output->writeln('[notice] You are currently running the HHVM engine'); + $output->writeln('[notice] Switch back to the Zend engine to manage Zend PHP versions'); + + exit(); + } + $version = $input->getArgument('version'); passthru("phpmanager remove $version"); diff --git a/puppet/modules/box/files/scripts/Command/Php/Reset.php b/puppet/modules/box/files/scripts/Command/Php/Reset.php index c6ac992..d89abe4 100644 --- a/puppet/modules/box/files/scripts/Command/Php/Reset.php +++ b/puppet/modules/box/files/scripts/Command/Php/Reset.php @@ -3,6 +3,7 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\OutputInterface; class Reset extends Command @@ -15,6 +16,10 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { + if (\Helper\System::getEngine() === 'hhvm') { + $this->getApplication()->find('php:engine')->run(new ArrayInput(array('command' => 'php:engine', 'engine' => 'zend')), $output); + } + passthru('phpmanager restore'); } } \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Php/UseVersion.php b/puppet/modules/box/files/scripts/Command/Php/UseVersion.php index 9795c6f..08c34c2 100644 --- a/puppet/modules/box/files/scripts/Command/Php/UseVersion.php +++ b/puppet/modules/box/files/scripts/Command/Php/UseVersion.php @@ -21,6 +21,14 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { + if (\Helper\System::getEngine() === 'hhvm') + { + $output->writeln('[notice] You are currently running the HHVM engine'); + $output->writeln('[notice] Switch back to the Zend engine to manage Zend PHP versions'); + + exit(); + } + $version = $input->getArgument('version'); passthru("phpmanager use $version"); diff --git a/puppet/modules/box/files/scripts/Command/Php/Versions.php b/puppet/modules/box/files/scripts/Command/Php/Versions.php index 38e2fea..d76598f 100644 --- a/puppet/modules/box/files/scripts/Command/Php/Versions.php +++ b/puppet/modules/box/files/scripts/Command/Php/Versions.php @@ -15,6 +15,14 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { + if (\Helper\System::getEngine() === 'hhvm') + { + $output->writeln('[notice] You are currently running the HHVM engine'); + $output->writeln('[notice] Switch back to the Zend engine to manage Zend PHP versions'); + + exit(); + } + passthru('phpmanager versions'); } } \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Restore.php b/puppet/modules/box/files/scripts/Command/Restore.php new file mode 100644 index 0000000..ea1c8c2 --- /dev/null +++ b/puppet/modules/box/files/scripts/Command/Restore.php @@ -0,0 +1,28 @@ +setName('restore') + ->setDescription('Restore the MySQL databases and Apache2 virtual hosts') + ->addOption('archive', 'a', InputOption::VALUE_REQUIRED, 'Full path to backup archive', '/vagrant/joomla-box-backup.tar'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $archive = $input->getOption('archive'); + + if (!file_exists($archive)) { + throw new \RuntimeException('Failed to find backup archive ' . $archive); + } + + passthru("/bin/bash /home/vagrant/triggers/restore.sh $archive"); + } +} \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Server/Restart.php b/puppet/modules/box/files/scripts/Command/Server/Restart.php index 7a1862a..807946b 100644 --- a/puppet/modules/box/files/scripts/Command/Server/Restart.php +++ b/puppet/modules/box/files/scripts/Command/Server/Restart.php @@ -2,6 +2,7 @@ namespace Command\Server; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -11,13 +12,39 @@ class Restart extends Command protected function configure() { $this->setName('server:restart') - ->setDescription('Restart Apache and MySQL'); + ->setDescription('Restart Apache and MySQL') + ->addArgument( + 'service', + InputArgument::IS_ARRAY, + 'Service to restart. Can be one or more of: apache|varnish|mysql|hhvm. Leave empty to restart all services at once.', + array('apache', 'varnish', 'mysql', 'hhvm') + ); } protected function execute(InputInterface $input, OutputInterface $output) { - `sudo service apache2 restart 2>&1 1> /dev/null`; - `sudo service mysql restart 2>&1 1> /dev/null`; + $services = $input->getArgument('service'); + + if (!count($services)) { + $services = array('apache2', 'varnish', 'mysql', 'hhvm'); + } + + if (($key = array_search('apache', $services)) !== false) { + $services[$key] = 'apache2'; + } + + if (($key = array_search('hhvm', $services)) !== false) + { + if (\Helper\System::getEngine() === 'hhvm') { + `sudo service hhvm restart 2>&1 1> /dev/null`; + } + + unset($services[$key]); + } + + foreach ($services as $service) { + `sudo service $service restart 2>&1 1> /dev/null`; + } $output->writeln("Server has been restarted"); } diff --git a/puppet/modules/box/files/scripts/Command/Server/Start.php b/puppet/modules/box/files/scripts/Command/Server/Start.php index b4d095e..ab52ed7 100644 --- a/puppet/modules/box/files/scripts/Command/Server/Start.php +++ b/puppet/modules/box/files/scripts/Command/Server/Start.php @@ -15,9 +15,14 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { + `sudo service varnish start 2>&1 1> /dev/null`; `sudo service apache2 start 2>&1 1> /dev/null`; `sudo service mysql start 2>&1 1> /dev/null`; + if (\Helper\System::getEngine() === 'hhvm') { + `sudo service hhvm start 2>&1 1> /dev/null`; + } + $output->writeln('Server has been started'); } } \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Server/Stop.php b/puppet/modules/box/files/scripts/Command/Server/Stop.php index 39f09f2..c994e95 100644 --- a/puppet/modules/box/files/scripts/Command/Server/Stop.php +++ b/puppet/modules/box/files/scripts/Command/Server/Stop.php @@ -16,9 +16,14 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { + `sudo service varnish stop 2>&1 1> /dev/null`; `sudo service apache2 stop 2>&1 1> /dev/null`; `sudo service mysql stop 2>&1 1> /dev/null`; + if (\Helper\System::getEngine() === 'hhvm') { + `sudo service hhvm stop 2>&1 1> /dev/null`; + } + $output->writeln("Server has been stopped"); } } \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Varnish/Clear.php b/puppet/modules/box/files/scripts/Command/Varnish/Clear.php new file mode 100644 index 0000000..8d3e52e --- /dev/null +++ b/puppet/modules/box/files/scripts/Command/Varnish/Clear.php @@ -0,0 +1,23 @@ +setName('varnish:clear') + ->setDescription('Clear the cache'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + `sudo varnishadm -T 127.0.0.1:6082 -S /etc/varnish/secret "ban req.url ~ ."`; + + $output->writeln('Cleared the Varnish cache'); + } +} \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Varnish/Disable.php b/puppet/modules/box/files/scripts/Command/Varnish/Disable.php new file mode 100644 index 0000000..c4fee43 --- /dev/null +++ b/puppet/modules/box/files/scripts/Command/Varnish/Disable.php @@ -0,0 +1,29 @@ +setName('varnish:disable') + ->setDescription('Disable Varnish cache'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + if (file_exists('/home/vagrant/scripts/varnish-enabled')) + { + `rm -f /home/vagrant/scripts/varnish-enabled`; + + $this->getApplication()->find('varnish:clear')->run(new ArrayInput(array('command' => 'varnish:clear')), $output); + + $output->writeln('Varnish has been disabled'); + } + else $output->writeln('Varnish is already disabled!'); + } +} \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Varnish/Enable.php b/puppet/modules/box/files/scripts/Command/Varnish/Enable.php new file mode 100644 index 0000000..addfc5c --- /dev/null +++ b/puppet/modules/box/files/scripts/Command/Varnish/Enable.php @@ -0,0 +1,30 @@ +setName('varnish:enable') + ->setDescription('Enable Varnish cache'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + if (!file_exists('/home/vagrant/scripts/varnish-enabled')) + { + `touch /home/vagrant/scripts/varnish-enabled`; + + $this->getApplication()->find('varnish:clear')->run(new ArrayInput(array('command' => 'varnish:clear')), $output); + + $output->writeln('Varnish has been enabled.'); + $output->writeln('You can edit the VCL file at /etc/varnish/default.vcl'); + } + else $output->writeln('Varnish is already enabled!'); + } +} \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Xdebug/Disable.php b/puppet/modules/box/files/scripts/Command/Xdebug/Disable.php index 6449f5b..2e24c80 100644 --- a/puppet/modules/box/files/scripts/Command/Xdebug/Disable.php +++ b/puppet/modules/box/files/scripts/Command/Xdebug/Disable.php @@ -3,6 +3,7 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\OutputInterface; class Disable extends Xdebug @@ -15,13 +16,24 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { - $files = $this->_getConfigFiles($this->_ini_files); + parent::execute($input, $output); + + $files = \Helper\Ini::findIniFiles($this->_ini_files); foreach($files as $file) { `sudo sed -i 's#^zend_extension=#; zend_extension=#' $file`; } - `sudo service apache2 restart 2>&1 1> /dev/null`; + // Also disable the profiler so we don't spend + // an afternoon looking for the lack of performance + // after enabling xdebug again after three weeks. :) + $files = \Helper\Ini::findIniFiles(array('custom.ini', '99-custom.ini'), false); + + foreach($files as $file) { + \Helper\Ini::update($file, 'xdebug.profiler_enable', 0); + } + + $this->getApplication()->find('server:restart')->run(new ArrayInput(array('command' => 'server:restart', 'service' => array('apache'))), $output); $output->writeln('Xdebug has been disabled'); } diff --git a/puppet/modules/box/files/scripts/Command/Xdebug/Enable.php b/puppet/modules/box/files/scripts/Command/Xdebug/Enable.php index f052ac9..d52c908 100644 --- a/puppet/modules/box/files/scripts/Command/Xdebug/Enable.php +++ b/puppet/modules/box/files/scripts/Command/Xdebug/Enable.php @@ -3,6 +3,7 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\OutputInterface; class Enable extends Xdebug @@ -15,13 +16,15 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { - $files = $this->_getConfigFiles($this->_ini_files); + parent::execute($input, $output); + + $files = \Helper\Ini::findIniFiles($this->_ini_files); foreach($files as $file) { `sudo sed -i 's#^; zend_extension=#zend_extension=#' $file`; } - `sudo service apache2 restart 2>&1 1> /dev/null`; + $this->getApplication()->find('server:restart')->run(new ArrayInput(array('command' => 'server:restart', 'service' => array('apache'))), $output); $output->writeln('Xdebug has been enabled'); } diff --git a/puppet/modules/box/files/scripts/Command/Xdebug/Profiler.php b/puppet/modules/box/files/scripts/Command/Xdebug/Profiler.php new file mode 100644 index 0000000..435efdc --- /dev/null +++ b/puppet/modules/box/files/scripts/Command/Xdebug/Profiler.php @@ -0,0 +1,77 @@ +setName('xdebug:profiler') + ->setDescription('Toggle profiling') + ->addArgument( + 'action', + InputArgument::REQUIRED, + 'start|stop' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + parent::execute($input, $output); + + if (!extension_loaded('xdebug')) + { + $output->writeln('[error] XDebug is not loaded. You can enable it using the box xdebug:enable command.'); + exit(); + } + + $action = strtolower($input->getArgument('action')); + + if (!in_array($action, array('start', 'stop'))) { + throw new \RuntimeException('Action must be one of start|stop'); + } + + $inis = \Helper\Ini::findIniFiles(array('zray-php5.5.ini', 'zray-php5.6.ini'), false); + $ini = array_pop($inis); + if ($action == 'start' && file_exists($ini)) + { + $contents = file_get_contents($ini); + if (preg_match('/^zend_extension\\s*=\\s*.+zray\\.so/', $contents)) + { + $output->writeln('[warning] Zend Z-Ray is enabled. This will generate a lot of profiler output!'); + $output->writeln('[warning] You can disable Zend Z-Ray with this command: box zray:disable'); + } + } + + $current = \Helper\Ini::getPHPConfig('xdebug.profiler_enable'); + $value = $action == 'start' ? 1 : 0; + $word = $action == 'start' ? 'started' : 'stopped'; + + if ($current == $value) + { + $output->writeln("Profiler has already been $word"); + exit(); + } + + $files = \Helper\Ini::findIniFiles(array('custom.ini', '99-custom.ini'), false); + + foreach($files as $file) { + \Helper\Ini::update($file, 'xdebug.profiler_enable', $value); + } + + $this->getApplication()->find('server:restart')->run(new ArrayInput(array('command' => 'server:restart')), $output); + + $output_dir = \Helper\Ini::getPHPConfig('xdebug.profiler_output_dir'); + + $output->writeln("XDebug profiler has been $word"); + + if ($action == 'start') { + $output->writeln("Profiling information will be written to $output_dir"); + } + } +} \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Xdebug/Xdebug.php b/puppet/modules/box/files/scripts/Command/Xdebug/Xdebug.php index da89a92..b62ef8f 100644 --- a/puppet/modules/box/files/scripts/Command/Xdebug/Xdebug.php +++ b/puppet/modules/box/files/scripts/Command/Xdebug/Xdebug.php @@ -7,29 +7,16 @@ abstract class Xdebug extends Command { - protected $_ini_files = array('xdebug.ini', 'zzz_xdebug.ini'); + protected $_ini_files = array('xdebug.ini'); - protected function _getConfigFiles($basenames = array()) + protected function execute(InputInterface $input, OutputInterface $output) { - $inis = array(); - $paths = array('/etc/php5/mods-available/'); - - $installs = glob('/opt/php/php-*/etc/conf.d', GLOB_ONLYDIR); - $installs = array_unique(array_filter($installs)); - - $paths = array_merge($paths, $installs); - - foreach($paths as $path) + if (\Helper\System::getEngine() === 'hhvm') { - foreach($basenames as $basename) - { - $fullpath = $path . '/' . $basename; - if(file_exists($fullpath)) { - $inis[] = $fullpath; - } - } - } + $output->writeln("[warning] Engine is set to hhvm. No changes will be made."); + $output->writeln("[warning] Switch back to the Zend engine if you want to use Xdebug"); - return $inis; + exit(); + } } } \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Zray/Disable.php b/puppet/modules/box/files/scripts/Command/Zray/Disable.php new file mode 100644 index 0000000..821c353 --- /dev/null +++ b/puppet/modules/box/files/scripts/Command/Zray/Disable.php @@ -0,0 +1,31 @@ +setName('zray:disable') + ->setDescription('Disable Zend Server Z-Ray'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + parent::execute($input, $output); + + $files = \Helper\Ini::findIniFiles($this->_ini_files); + + foreach($files as $file) { + `sudo sed -i 's#^zend_extension=#; zend_extension=#' $file`; + } + + $this->getApplication()->find('server:restart')->run(new ArrayInput(array('command' => 'server:restart', 'service' => array('apache'))), $output); + + $output->writeln('Zend Server Z-Ray has been disabled'); + } +} \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Zray/Enable.php b/puppet/modules/box/files/scripts/Command/Zray/Enable.php new file mode 100644 index 0000000..2b77db3 --- /dev/null +++ b/puppet/modules/box/files/scripts/Command/Zray/Enable.php @@ -0,0 +1,31 @@ +setName('zray:enable') + ->setDescription('Enable Xdebug'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + parent::execute($input, $output); + + $files = \Helper\Ini::findIniFiles($this->_ini_files); + + foreach($files as $file) { + `sudo sed -i 's#^; zend_extension=#zend_extension=#' $file`; + } + + $this->getApplication()->find('server:restart')->run(new ArrayInput(array('command' => 'server:restart', 'service' => array('apache'))), $output); + + $output->writeln('Zend Server Z-Ray has been enabled'); + } +} \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Command/Zray/Zray.php b/puppet/modules/box/files/scripts/Command/Zray/Zray.php new file mode 100644 index 0000000..e3f55c7 --- /dev/null +++ b/puppet/modules/box/files/scripts/Command/Zray/Zray.php @@ -0,0 +1,33 @@ +writeln("[warning] Engine is set to hhvm. No changes will be made."); + $output->writeln("[warning] Switch back to the Zend engine if you want to use Zend Server Z-Ray"); + + exit(); + } + + $version = \Helper\System::getZendPHPVersion(); + $major = substr($version, 0, 3); + + if (!in_array($major, array('5.5', '5.6'))) + { + $output->writeln("[warning] Zend Server Z-Ray is only supported on PHP 5.5 and 5.6."); + $output->writeln("[warning] Your current version is PHP $version"); + + exit(); + } + } +} \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Helper/Ini.php b/puppet/modules/box/files/scripts/Helper/Ini.php new file mode 100644 index 0000000..bae804a --- /dev/null +++ b/puppet/modules/box/files/scripts/Helper/Ini.php @@ -0,0 +1,108 @@ + $v) + { + if (!empty($v) || $v === '0') { + $string .= "$k = $v" . PHP_EOL; + } + } + + if (!is_writable($file)) { + `sudo chmod o+rw $file`; + } + + file_put_contents($file, $string); + } + + /** + * Loop over all installed PHP versions and find + * the given base names. Will return a list of + * absolute paths to the ini files. + * + * @param array $basenames array Array of ini file names to look for. + * @param boolean $global If set to the false, the method will only look for the given ini in the currently enabled PHP version + * @return array List of absolute paths + */ + public static function findIniFiles($basenames = array(), $global = true) + { + $inis = array(); + + if ($global === false) + { + $version = \Helper\System::getZendPHPVersion(); + + if (file_exists("/opt/php/php-$version/etc/conf.d")) { + $paths = array("/opt/php/php-$version/etc/conf.d"); + } + else $paths = array('/etc/php5/mods-available/'); + } + else + { + $paths = array('/etc/php5/mods-available/'); + + $installs = glob('/opt/php/php-*/etc/conf.d', GLOB_ONLYDIR); + $installs = array_unique(array_filter($installs)); + + $paths = array_merge($paths, $installs); + } + + foreach($paths as $path) + { + foreach($basenames as $basename) + { + $fullpath = $path . '/' . $basename; + + if(file_exists($fullpath)) { + $inis[] = $fullpath; + } + } + } + + return $inis; + } + + /** + * Look up the value for the given ini directive + * in the currently active PHP version. + * + * @param $key + * @return bool + */ + public static function getPHPConfig($key) + { + $bin = \Helper\System::getPHPCommand(); + + // Special case: since we explicitly disable xdebug.profiler_enable on CLI commands + // we need to omit this when looking up this specific key. + // Otherwise the result will always be 0 + if ($key == 'xdebug.profiler_enable') { + $bin = str_replace('-d xdebug.profiler_enable=Off', '', $bin); + } + + $current = `$bin -r "\\\$value = ini_get('$key'); echo \\\$value === false ? 'unknown-directive' : \\\$value;"`; + + if ($current == 'unknown-directive') { + return false; + } + + return $current; + } +} \ No newline at end of file diff --git a/puppet/modules/box/files/scripts/Helper/System.php b/puppet/modules/box/files/scripts/Helper/System.php new file mode 100644 index 0000000..e3eada3 --- /dev/null +++ b/puppet/modules/box/files/scripts/Helper/System.php @@ -0,0 +1,29 @@ +add(new CompletionCommand()); + $application->add(new Command\Apc\Enable()); $application->add(new Command\Apc\Disable()); $application->add(new Command\Apc\Clear()); $application->add(new Command\Xdebug\Enable()); $application->add(new Command\Xdebug\Disable()); +$application->add(new Command\Xdebug\Profiler()); $application->add(new Command\Server\Restart()); $application->add(new Command\Server\Start()); $application->add(new Command\Server\Stop()); +$application->add(new Command\Php\Engine()); $application->add(new Command\Php\Ini()); $application->add(new Command\Php\UseVersion()); $application->add(new Command\Php\ListVersion()); @@ -42,4 +47,14 @@ $application->add(new Command\Php\Versions()); $application->add(new Command\Php\Remove()); $application->add(new Command\Php\Reset()); +$application->add(new Command\Varnish\Enable()); +$application->add(new Command\Varnish\Disable()); +$application->add(new Command\Varnish\Clear()); + +$application->add(new Command\Zray\Disable()); +$application->add(new Command\Zray\Enable()); + +$application->add(new Command\Backup()); +$application->add(new Command\Restore()); + $application->run(); diff --git a/puppet/modules/box/manifests/init.pp b/puppet/modules/box/manifests/init.pp index 81891a1..85eb0de 100644 --- a/puppet/modules/box/manifests/init.pp +++ b/puppet/modules/box/manifests/init.pp @@ -7,7 +7,7 @@ } exec { 'fetch-box-dependencies': - command => 'composer require symfony/console:2.4.* --no-interaction', + command => 'composer require symfony/console:2.7.* stecman/symfony-console-completion --no-interaction', cwd => '/home/vagrant/box', unless => '[ -d /home/vagrant/box/vendor/symfony ]', path => '/usr/bin', @@ -22,8 +22,15 @@ } exec { 'add-box-to-path': - command => 'echo "export PATH=\$PATH:/home/vagrant/box" >> /home/vagrant/.profile', - unless => 'grep ":/home/vagrant/box" /home/vagrant/.profile', + command => 'echo "export PATH=\$PATH:/home/vagrant/box" >> /home/vagrant/.bash_profile', + unless => 'grep ":/home/vagrant/box" /home/vagrant/.bash_profile', require => Exec['make-box-executable'] } + + file_line { 'register-box-autocompletion': + path => '/home/vagrant/.bash_profile', + line => 'source <(/home/vagrant/box/box _completion --generate-hook --program=box)', + require => File['/home/vagrant/.bash_profile'] + } + } \ No newline at end of file diff --git a/puppet/modules/cloudcommander/files/config.json b/puppet/modules/cloudcommander/files/config.json new file mode 100644 index 0000000..c9ad2a8 --- /dev/null +++ b/puppet/modules/cloudcommander/files/config.json @@ -0,0 +1,19 @@ +{ + "auth" : false, + "editor" : "edward", + "diff" : true, + "zip" : true, + "notifications" : false, + "localStorage" : true, + "buffer" : true, + "dirStorage" : false, + "online" : false, + "cache" : true, + "showKeysPanel" : true, + "port" : 8001, + "ip" : null, + "root" : "/", + "prefix" : "", + "progress" : true, + "htmlDialogs" : true +} \ No newline at end of file diff --git a/puppet/modules/cloudcommander/files/upstart.conf b/puppet/modules/cloudcommander/files/upstart.conf new file mode 100644 index 0000000..f45d932 --- /dev/null +++ b/puppet/modules/cloudcommander/files/upstart.conf @@ -0,0 +1,13 @@ +# Upstart script +# /etc/init/cloudcommander.conf + +description "File browser" +author "coderaiser.github.io" + +start on started mountall +stop on shutdown + +respawn +respawn limit 20 5 + +exec cloudcmd diff --git a/puppet/modules/cloudcommander/manifests/init.pp b/puppet/modules/cloudcommander/manifests/init.pp new file mode 100644 index 0000000..90be8c5 --- /dev/null +++ b/puppet/modules/cloudcommander/manifests/init.pp @@ -0,0 +1,30 @@ +class cloudcommander { + include nodejs + + exec { 'npm-install-cloudcommander': + command => 'npm install cloudcmd -g', + unless => 'which cloudcmd', + environment => ['HOME=/home/vagrant'], + require => Package['nodejs'] + } + + file { '/etc/init/cloudcommander.conf': + ensure => file, + source => "puppet:///modules/cloudcommander/upstart.conf", + owner => root, + group => root, + require => Exec['npm-install-cloudcommander'] + } + + file { '/root/.cloudcmd.json': + ensure => file, + source => "puppet:///modules/cloudcommander/config.json", + notify => Service['cloudcommander'] + } + + service {'cloudcommander': + ensure => 'running', + provider => 'upstart', + require => File['/etc/init/cloudcommander.conf'] + } +} \ No newline at end of file diff --git a/puppet/modules/hhvm/.fixtures.yml b/puppet/modules/hhvm/.fixtures.yml new file mode 100644 index 0000000..7b46adf --- /dev/null +++ b/puppet/modules/hhvm/.fixtures.yml @@ -0,0 +1,9 @@ +fixtures: + repositories: + stdlib: "git://github.com/puppetlabs/puppetlabs-stdlib.git" + apt: "git://github.com/puppetlabs/puppetlabs-apt.git" + inifile: "git://github.com/puppetlabs/puppetlabs-inifile.git" + wget: "git://github.com/maestrodev/puppet-wget.git" + symlinks: + hhvm: "#{source_dir}" + diff --git a/puppet/modules/hhvm/.travis.yml b/puppet/modules/hhvm/.travis.yml new file mode 100644 index 0000000..570c283 --- /dev/null +++ b/puppet/modules/hhvm/.travis.yml @@ -0,0 +1,9 @@ +language: ruby +rvm: + - 2.1.0 + - 2.0.0 + - 1.9.3 +env: + - PUPPET_VERSION=3.4.3 + - PUPPET_VERSION=3.5.1 + - PUPPET_VERSION=3.6.2 diff --git a/puppet/modules/hhvm/CHANGELOG.md b/puppet/modules/hhvm/CHANGELOG.md new file mode 100644 index 0000000..9aa0b61 --- /dev/null +++ b/puppet/modules/hhvm/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog + +## 0.1.2 + * use correct dependency names (@Lexance) + +## 0.1.1 + * relax dependencies + * use package name + +## 0.1.0 +Initial release + + diff --git a/puppet/modules/hhvm/Gemfile b/puppet/modules/hhvm/Gemfile new file mode 100644 index 0000000..0b560c8 --- /dev/null +++ b/puppet/modules/hhvm/Gemfile @@ -0,0 +1,29 @@ +source 'https://rubygems.org' + +group :development, :test do + gem 'rake', :require => false + gem 'rspec-puppet', :require => false + gem 'puppetlabs_spec_helper', :require => false + gem 'serverspec', :require => false + gem 'rspec-system', :require => false + gem 'rspec-system-puppet', :require => false + gem 'rspec-system-serverspec', :require => false + gem 'puppet-lint', :require => false + gem 'rspec' + gem 'ci_reporter' + gem 'fpm', '<=0.3.11' +end + +if facterversion = ENV['FACTER_GEM_VERSION'] + gem 'facter', facterversion, :require => false +else + gem 'facter', :require => false +end + +if puppetversion = ENV['PUPPET_GEM_VERSION'] + gem 'puppet', puppetversion, :require => false +else + gem 'puppet', :require => false +end + +# vim:ft=ruby diff --git a/puppet/modules/hhvm/README.md b/puppet/modules/hhvm/README.md new file mode 100644 index 0000000..bde489b --- /dev/null +++ b/puppet/modules/hhvm/README.md @@ -0,0 +1,63 @@ +# hhvm + +[![Build Status](https://travis-ci.org/mayflower/puppet-hhvm.svg?branch=master)](https://travis-ci.org/mayflower/puppet-hhvm) + +#### Table of Contents + +1. [Overview](#overview) +2. [Setup - The basics of getting started with hhvm](#setup) + * [Setup requirements](#setup-requirements) + * [Beginning with hhvm](#beginning-with-hhvm) +3. [Usage - Configuration options and additional functionality](#usage) +4. [Limitations - OS compatibility, etc.](#limitations) +5. [Development - Guide for contributing to the module](#development) + +## Overview + +This module installs and configures Facebook's HHVM for you. It aims to use sane defaults and be easily configurable with hiera. + +## Dependencies + +HHVM depends on + * puppetlabs/stdlib + * puppetlabs/apt for the repository configureation + * maestrodev/wget for the highly experimental pgsql support. + +## Usage + +To use the module simply use the base class which will do everything you need. You may turn off repo management or use the **highly experimental** pgsql support. +```puppet +class { '::hhvm': + manage_repos => true, + pgsql => false +} +``` + +Additional configs (with defaults): +```yaml +hhvm::config::user: www-data # user to run server with +hhvm::config::group: www-data # group to run server with +hhvm::config::port: 9000 # port for fastcgi server +hhvm::config::settings: [] # augeas commands for php.ini +``` + +Example config: +```yaml +hhvm::config::user: vagrant +hhvm::config::group: users +hhvm::config::port: 9090 +hhvm::config::settings: + - set .anon/date.timezone Europe/Berlin +``` + +## Limitations + +Currently only tested with Ubuntu 14.04 Trusty Tahr + +## Development + + * If you find a bug or wish to have a new feature simply open an issue. + * Otherwise if you are really motivated pull requests are always welcome, too. + +## Credits + * Created by [Robin Gloster](https://github.com/globin) diff --git a/puppet/modules/hhvm/Rakefile b/puppet/modules/hhvm/Rakefile new file mode 100644 index 0000000..37863e8 --- /dev/null +++ b/puppet/modules/hhvm/Rakefile @@ -0,0 +1,23 @@ +require 'rubygems' +require 'puppetlabs_spec_helper/rake_tasks' +require 'rspec-system/rake_task' +require 'puppet-lint/tasks/puppet-lint' + +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"] + +desc "Validate manifests, templates, and ruby files" +task :validate do + Dir['manifests/**/*.pp'].each do |manifest| + sh "puppet parser validate --noop #{manifest}" + end + Dir['spec/**/*.rb','lib/**/*.rb'].each do |ruby_file| + sh "ruby -c #{ruby_file}" unless ruby_file =~ /spec\/fixtures/ + end + Dir['templates/**/*.erb'].each do |template| + sh "erb -P -x -T '-' #{template} | ruby -c" + end +end + +task :default => [:spec, :lint] + diff --git a/puppet/modules/hhvm/files/hhvm.aug b/puppet/modules/hhvm/files/hhvm.aug new file mode 100644 index 0000000..540894b --- /dev/null +++ b/puppet/modules/hhvm/files/hhvm.aug @@ -0,0 +1,53 @@ +(* HHVM module for Augeas *) +(* Author: Robin Gloster *) +(* *) + +module HHVM = +autoload xfm + +(************************************************************************ +* INI File settings +*************************************************************************) + +let comment = IniFile.comment IniFile.comment_re IniFile.comment_default +let sep = IniFile.sep IniFile.sep_re IniFile.sep_default +let empty = IniFile.empty + + +(************************************************************************ +* ENTRY +* +* We have to remove the keyword "section" from possible entry keywords +* otherwise it would lead to an ambiguity with the "section" label +* since PHP allows entries outside of sections. +*************************************************************************) +let entry = +let word = IniFile.entry_re +in let entry_re = word . ( "[" . word . "]" )? +in IniFile.indented_entry entry_re sep comment + + +(************************************************************************ +* TITLE +* +* We use IniFile.title_label because there can be entries +* outside of sections whose labels would conflict with section names +*************************************************************************) +let title = IniFile.title ( IniFile.record_re - ".anon" ) +let record = IniFile.record title entry + +let record_anon = [ label ".anon" . ( entry | empty )+ ] + + +(************************************************************************ +* LENS & FILTER +* There can be entries before any section +* IniFile.entry includes comment management, so we just pass entry to lns +*************************************************************************) +let lns = record_anon? . record* + +let filter = (incl "/etc/hhvm/*.ini") +. (incl "/etc/default/hhvm") +. Util.stdexcl + +let xfm = transform lns filter diff --git a/puppet/modules/hhvm/lib/puppet/parser/functions/to_hash_settings.rb b/puppet/modules/hhvm/lib/puppet/parser/functions/to_hash_settings.rb new file mode 100644 index 0000000..bd348cc --- /dev/null +++ b/puppet/modules/hhvm/lib/puppet/parser/functions/to_hash_settings.rb @@ -0,0 +1,34 @@ + +module Puppet::Parser::Functions + newfunction(:to_hash_settings, :type => :rvalue, :doc => <<-EOS +This function converts a {key => value} hash into a nested hash and adds an id to the outer key. + +*Examples:* + +to_hash_settings({'a' => 1, 'b' => 2}) + +Would return: { + 'a' => {'value' => 1}, + 'b' => {'value' => 2} +} +EOS + ) do |arguments| + + raise(Puppet::ParseError, "to_hash_settings(): Wrong number of arguments " + + "given (#{arguments.size} for 2)") if arguments.size < 2 + + hash = arguments[0] + id = arguments[1] + + unless hash.is_a?(Hash) + raise(Puppet::ParseError, 'to_hash_settings(): Requires hash to work with') + end + + result = hash.reduce({}) { |acc, kv| + acc[id + ': ' + kv[0]] = {'key' => kv[0] ,'value' => kv[1]} + acc + } + + return result + end +end diff --git a/puppet/modules/hhvm/manifests/config.pp b/puppet/modules/hhvm/manifests/config.pp new file mode 100644 index 0000000..671ec2a --- /dev/null +++ b/puppet/modules/hhvm/manifests/config.pp @@ -0,0 +1,62 @@ +# == Class: hhvm::config +# +# configure hhvm +# +# === Parameters +# +# No parameters +# +# === Variables +# +# No variables +# +# === Examples +# +# include hhvm::config +# +# === Authors +# +# Robin Gloster +# +# === Copyright +# +# See LICENSE file +# +class hhvm::config ( + $user = 'www-data', + $group = 'www-data', + $port = 9000, + $settings = {} +) { + + if $caller_module_name != $module_name { + warning("${name} is not part of the public API of the ${module_name} module and should not be directly included in the manifest.") + } + + validate_hash($settings) + validate_string($user) + validate_string($group) + validate_string($port) + + $default_conf_file = '/etc/default/hhvm' + create_resources(config::setting, to_hash_settings({ + 'RUN_AS_USER' => $user, + 'RUN_AS_GROUP' => $group + }, $default_conf_file), { + file => $default_conf_file, + notify => Service['hhvm'] + }) + + config::setting { 'hhvm-server-ini': + file => '/etc/hhvm/server.ini', + key => 'hhvm.server.port', + value => $port, + notify => Service['hhvm'] + } + + $php_ini = '/etc/hhvm/php.ini' + create_resources(config::setting, to_hash_settings($settings, $php_ini), { + file => $php_ini, + notify => Service['hhvm'] + }) +} diff --git a/puppet/modules/hhvm/manifests/config/setting.pp b/puppet/modules/hhvm/manifests/config/setting.pp new file mode 100644 index 0000000..c5740b7 --- /dev/null +++ b/puppet/modules/hhvm/manifests/config/setting.pp @@ -0,0 +1,28 @@ +define hhvm::config::setting( + $key, + $value, + $file, +) { + + if $caller_module_name != $module_name { + warning("${name} is not part of the public API of the ${module_name} module and should not be directly included in the manifest.") + } + + validate_string($file) + + $split_name = split($key, '/') + if count($split_name) == 1 { + $section = '' + $setting = $split_name[0] + } else { + $section = $split_name[0] + $setting = $split_name[1] + } + + ini_setting { $name: + value => $value, + path => $file, + section => $section, + setting => $setting + } +} diff --git a/puppet/modules/hhvm/manifests/init.pp b/puppet/modules/hhvm/manifests/init.pp new file mode 100644 index 0000000..b576cc9 --- /dev/null +++ b/puppet/modules/hhvm/manifests/init.pp @@ -0,0 +1,48 @@ +# == Class: hhvm +# +# Installs and configures HHVM in a sane kind of way +# +# === Parameters +# +# Document parameters here. +# +# [*manage_repos*] +# Defines if this module should manage the repository for HHVM +# +# === Examples +# +# class { hhvm: } +# +# === Authors +# +# Robin Gloster +# +# === Copyright +# +# See LICENSE file +# +class hhvm ( + $manage_repos = true, + $pgsql = false, +) { + + validate_bool($manage_repos) + + if $manage_repos { + anchor { 'hhvm::repo': } -> + class { 'hhvm::repo': } -> + Anchor['hhvm::begin'] + } + + anchor { 'hhvm::begin': } -> + class { 'hhvm::package': } -> + class { 'hhvm::config': } -> + class { 'hhvm::service': } -> + anchor { 'hhvm::end': } + + if $pgsql { + Class['hhvm::package'] -> + class { 'hhvm::pgsql': } -> + Class['hhvm::service'] + } +} diff --git a/puppet/modules/hhvm/manifests/package.pp b/puppet/modules/hhvm/manifests/package.pp new file mode 100644 index 0000000..07574d0 --- /dev/null +++ b/puppet/modules/hhvm/manifests/package.pp @@ -0,0 +1,31 @@ +# == Class: hhvm::package +# +# Install hhvm +# +# === Parameters +# +# [*package*] +# The package name for hhvm +# +# === Authors +# +# Robin Gloster +# +# === Copyright +# +# See LICENSE file +# +class hhvm::package( + $package = 'hhvm' +) { + + if $caller_module_name != $module_name { + warning("${name} is not part of the public API of the ${module_name} module and should not be directly included in the manifest.") + } + + validate_string($package) + + package { $package: + ensure => 'installed', + } +} diff --git a/puppet/modules/hhvm/manifests/pgsql.pp b/puppet/modules/hhvm/manifests/pgsql.pp new file mode 100644 index 0000000..3aa2c2c --- /dev/null +++ b/puppet/modules/hhvm/manifests/pgsql.pp @@ -0,0 +1,45 @@ +# == hhvm::pgsql +# +# installs hhvm pgsql extension +# +# === Authors +# +# Robin Gloster +# +# === Copyright +# +# See LICENSE file +# +class hhvm::pgsql { + ensure_packages('libpq5') + + Package['libpq5'] -> + wget::fetch { 'http://glob.in/pgsql.so': + destination => '/usr/lib/hhvm/pgsql.so', + timeout => 0, + verbose => false, + } -> + ini_setting { 'hhvm-add-hdf': + path => '/etc/default/hhvm', + section => '', + setting => 'ADDITIONAL_ARGS', + value => '\'--config /etc/hhvm/server.hdf\'', + notify => Service['hhvm'] + } -> + ini_setting { 'hhvm-server-ini-extension': + path => '/etc/hhvm/server.ini', + section => '', + setting => 'hhvm.dynamic_extension_path', + value => '/usr/lib/hhvm', + notify => Service['hhvm'] + } -> + file { '/etc/hhvm/server.hdf': + ensure => present, + content => ' +DynamicExtensions { + * = pgsql.so +} +', + notify => Service['hhvm'] + } +} diff --git a/puppet/modules/hhvm/manifests/repo.pp b/puppet/modules/hhvm/manifests/repo.pp new file mode 100644 index 0000000..b11a475 --- /dev/null +++ b/puppet/modules/hhvm/manifests/repo.pp @@ -0,0 +1,37 @@ +# == Class: hhvm::repo +# +# Configure package repository +# +# === Parameters +# +# No parameters +# +# === Authors +# +# Robin Gloster +# +# === Copyright +# +# See LICENSE file +# +class hhvm::repo { + + if $caller_module_name != $module_name { + warning("${name} is not part of the public API of the ${module_name} module and should not be directly included in the manifest.") + } + + anchor { 'hhvm::repo::begin': } -> + anchor { 'hhvm::repo::end': } + + case $::osfamily { + 'Debian': { + + # FIXME use correct urls for different Debian variants/versions + # see https://github.com/facebook/hhvm/wiki/Prebuilt%20Packages%20for%20HHVM + include hhvm::repo::apt + } + default: { + fail("No repo available for ${::osfamily}/${::operatingsystem}, please fork this module and add one in repo.pp") + } + } +} diff --git a/puppet/modules/hhvm/manifests/repo/apt.pp b/puppet/modules/hhvm/manifests/repo/apt.pp new file mode 100644 index 0000000..8d23350 --- /dev/null +++ b/puppet/modules/hhvm/manifests/repo/apt.pp @@ -0,0 +1,54 @@ +# == Class: hhvm::repo::apt +# +# Configure apt repo +# +# === Parameters +# +# [*location*] +# location of the apt repository +# +# [*release*] +# release of the apt repository +# +# [*repos*] +# apt repository names +# +# [*repo_key*] +# location of the apt repository gpg key +# +# === Variables +# +# No variables +# +# === Examples +# +# include hhvm::repo::apt +# +# === Authors +# +# Robin Gloster +# +# === Copyright +# +# See LICENSE file +# +class hhvm::repo::apt( + $location = 'http://dl.hhvm.com/ubuntu', + $release = 'trusty', + $repos = 'main', + $repo_key = 'http://dl.hhvm.com/conf/hhvm.gpg.key', +) { + + if $caller_module_name != $module_name { + warning("${name} is not part of the public API of the ${module_name} module and should not be directly included in the manifest.") + } + + apt::source { 'hhvm': + location => $location, + release => $release, + repos => $repos, + include_src => false, + key => '1BE7A449', + key_source => 'http://dl.hhvm.com/conf/hhvm.gpg.key', + } +} diff --git a/puppet/modules/hhvm/manifests/service.pp b/puppet/modules/hhvm/manifests/service.pp new file mode 100644 index 0000000..45eafc4 --- /dev/null +++ b/puppet/modules/hhvm/manifests/service.pp @@ -0,0 +1,25 @@ +# == Class: hhvm::service +# +# Start and control hhvm service +# +# === Authors +# +# Robin Gloster +# +# === Copyright +# +# See LICENSE file +# +class hhvm::service { + + if $caller_module_name != $module_name { + warning("${name} is not part of the public API of the ${module_name} module and should not be directly included in the manifest.") + } + + service { 'hhvm': + ensure => 'running', + enable => true, + hasstatus => true, + require => Package[$hhvm::package::package], + } +} diff --git a/puppet/modules/hhvm/metadata.json b/puppet/modules/hhvm/metadata.json new file mode 100644 index 0000000..294ceee --- /dev/null +++ b/puppet/modules/hhvm/metadata.json @@ -0,0 +1,25 @@ +{ + "name": "mayflower-hhvm", + "version": "0.1.2", + "author": "mayflower", + "summary": "Installs and configures Facebook's HHVM", + "license": "Apache 2.0", + "source": "https://github.com/Mayflower/puppet-hhvm", + "project_page": "https://github.com/Mayflower/puppet-hhvm", + "issues_url": "https://github.com/Mayflower/puppet-hhvm/issues", + "dependencies": [ + { + "name": "puppetlabs/stdlib", + "version_requirement": ">= 4.0.0" + }, + { + "name": "puppetlabs/apt", + "version_requirement": ">= 1.0.0" + }, + { + "name": "maestrodev/wget", + "version_requirement": ">= 1.0.0" + } + ] +} + diff --git a/puppet/modules/hhvm/spec/classes/hhvm_spec.rb b/puppet/modules/hhvm/spec/classes/hhvm_spec.rb new file mode 100644 index 0000000..a087b36 --- /dev/null +++ b/puppet/modules/hhvm/spec/classes/hhvm_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe 'hhvm', :type => :class do + let(:facts) { { :osfamily => 'Debian', + :lsbdistid => 'Debian', + :operatingsystem => 'Debian', + :path => '/usr/local/bin:/usr/bin:/bin' } } + + describe 'when called with no parameters on Debian' do + it { + should contain_package('hhvm').with({ + 'ensure' => 'installed', + }) + should contain_class('hhvm::repo') + should_not contain_class('hhvm::pgsql') + should contain_class('hhvm::config') + should contain_class('hhvm::service') + } + end + + describe 'when pgsql is enabled' do + let(:params) { { :pgsql => true, } } + it { + should contain_class('hhvm::pgsql') + } + end + describe 'when manage_repos is disabled' do + let(:params) { { :manage_repos => false, } } + it { + should_not contain_class('php::repo') + } + end +end diff --git a/puppet/modules/hhvm/spec/spec_helper.rb b/puppet/modules/hhvm/spec/spec_helper.rb new file mode 100644 index 0000000..7e440ad --- /dev/null +++ b/puppet/modules/hhvm/spec/spec_helper.rb @@ -0,0 +1,3 @@ +require 'rubygems' + +require 'puppetlabs_spec_helper/module_spec_helper' diff --git a/puppet/modules/hhvm/tests/init.pp b/puppet/modules/hhvm/tests/init.pp new file mode 100644 index 0000000..950df11 --- /dev/null +++ b/puppet/modules/hhvm/tests/init.pp @@ -0,0 +1,12 @@ +# 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 +# +include hhvm diff --git a/puppet/modules/inifile/.fixtures.yml b/puppet/modules/inifile/.fixtures.yml new file mode 100755 index 0000000..db98538 --- /dev/null +++ b/puppet/modules/inifile/.fixtures.yml @@ -0,0 +1,3 @@ +fixtures: + symlinks: + inifile: "#{source_dir}" diff --git a/puppet/modules/inifile/.gitignore b/puppet/modules/inifile/.gitignore new file mode 100755 index 0000000..b5db85e --- /dev/null +++ b/puppet/modules/inifile/.gitignore @@ -0,0 +1,9 @@ +pkg/ +Gemfile.lock +vendor/ +spec/fixtures/ +.vagrant/ +.bundle/ +coverage/ +.idea/ +*.iml diff --git a/puppet/modules/inifile/.sync.yml b/puppet/modules/inifile/.sync.yml new file mode 100755 index 0000000..66a03c6 --- /dev/null +++ b/puppet/modules/inifile/.sync.yml @@ -0,0 +1,3 @@ +--- +spec/spec_helper.rb: + unmanaged: true diff --git a/puppet/modules/inifile/.travis.yml b/puppet/modules/inifile/.travis.yml new file mode 100755 index 0000000..742380f --- /dev/null +++ b/puppet/modules/inifile/.travis.yml @@ -0,0 +1,23 @@ +--- +sudo: false +language: ruby +bundler_args: --without system_tests +script: "bundle exec rake validate && bundle exec rake lint && bundle exec rake spec SPEC_OPTS='--format documentation'" +matrix: + fast_finish: true + include: + - rvm: 1.8.7 + env: PUPPET_GEM_VERSION="~> 3.0" + - rvm: 1.9.3 + env: PUPPET_GEM_VERSION="~> 3.0" + - rvm: 2.1.5 + env: PUPPET_GEM_VERSION="~> 3.0" + - rvm: 2.1.5 + env: PUPPET_GEM_VERSION="~> 3.0" FUTURE_PARSER="yes" + - rvm: 2.1.6 + env: PUPPET_GEM_VERSION="~> 4.0" STRICT_VARIABLES="yes" + allow_failures: + - rvm: 2.1.6 + env: PUPPET_GEM_VERSION="~> 4.0" STRICT_VARIABLES="yes" +notifications: + email: false diff --git a/puppet/modules/inifile/CHANGELOG.md b/puppet/modules/inifile/CHANGELOG.md new file mode 100755 index 0000000..4b354f8 --- /dev/null +++ b/puppet/modules/inifile/CHANGELOG.md @@ -0,0 +1,236 @@ +## 2015-09-01 - Supported Release 1.4.2 +### Summary +This release adds some bugfixes. + +####Bugfixes +- MODULES-2212 Add use_exact_match parameter for subsettings +- MODULES-1908 Munge the setting to ensure we always strip the whitespace +- MODULES-2369 Support a space as a key_val_separator + +## 2015-07-15 - Supported Release 1.4.1 +### Summary +This release bumps the metadata for PE up. + +##2015-07-07 - Supported Releases 1.4.0 +###Summary + +This is primarily a release which includes acceptance tests updates, but also includes some minor bug fixes and improvements + +####Features +- Solaris 12 Support +- Acceptance testing improvements + +####Bugfixes +- MODULES-1599 Match only on space and tab whitespace after k/v separator + +##2015-06-09 - Supported Releases 1.3.0 +###Summary + +This is primarily a feature release, but also includes test fixes, documentation updates and synchronization of files with modulesync. + +####Features +- Synchronized files using modulesync +- Improved documentation +- Allow changing key value separator beyond indentation +- Adding the ability to change regex match for $section in inifile + +####Bugfixes +- pin beaker-rspec for windows testing +- pin rspec gems for testing +- Adds default values for section +- Fixed names containing spaces + +##2014-11-11 - Supported Releases 1.2.0 +###Summary + +This is primarily a bugfix release, but also includes documentation updates and synchronization of files with modulesync. + +####Features +- Synchronized files using modulesync +- Improved documentation with a warning about old, manually installed inifile with PE3.3+ + +####Bugfixes +- Fix issue where single character settings were not being saved + +##2014-09-30 - Supported Releases 1.1.4 +###Summary + +This release includes documentation and test updates. + +##2014-07-15 - Supported Release 1.1.3 +###Summary + +This release merely updates metadata.json so the module can be uninstalled and +upgraded via the puppet module command. + +##2014-07-10 - Supported Release 1.1.2 +###Summary + +This is a re-packaging release. + +##2014-07-07 - Release 1.1.1 +###Summary + +This supported bugfix release corrects the inifile section header detection +regex (so you can use more characters in your section titles). + +####Bugfixes +- Correct section regex to allow anything other than ] +- Correct `exists?` to return a boolean +- Lots of test updates +- Add missing CONTRIBUTING.md + +##2014-06-04 - Release 1.1.0 +###Summary + +This is a compatibility and feature release. This release adds one new +feature, the ability to control the quote character used. This allows you to +do things like: + +``` +ini_subsetting { '-Xms': + ensure => present, + path => '/some/config/file', + section => '', + setting => 'JAVA_ARGS', + quote_char => '"', + subsetting => '-Xms' + value => '256m', + } +``` + +Which builds: + +``` +JAVA_ARGS="-Xmx256m -Xms256m" +``` + +####Features +- Add quote_char parameter to the ini_subsetting resource type + +####Bugfixes + +####Known Bugs +* No known bugs + +##2014-03-04 - Supported Release 1.0.3 +###Summary + +This is a supported release. It has only test changes. + +####Features + +####Bugfixes + +####Known Bugs +* No known bugs + + +##2014-02-26 - Version 1.0.2 +###Summary +This release adds supported platforms to metadata.json and contains spec fixes + + +##2014-02-12 - Version 1.0.1 +###Summary +This release is a bugfix for handling whitespace/[]'s better, and adding a +bunch of tests. + +####Bugfixes +- Handle whitespace in sections +- Handle square brances in values +- Add metadata.json +- Update some travis testing +- Tons of beaker-rspec tests + + +##2013-07-16 - Version 1.0.0 +####Features +- Handle empty values. +- Handle whitespace in settings names (aka: server role = something) +- Add mechanism for allowing ini_setting subclasses to override the +formation of the namevar during .instances, to allow for ini_setting +derived types that manage flat ini-file-like files and still purge +them. + +--- +##2013-05-28 - Chris Price - 0.10.3 + * Fix bug in subsetting handling for new settings (cbea5dc) + +##2013-05-22 - Chris Price - 0.10.2 + * Better handling of quotes for subsettings (1aa7e60) + +##2013-05-21 - Chris Price - 0.10.1 + * Change constants to class variables to avoid ruby warnings (6b19864) + +##2013-04-10 - Erik Dalén - 0.10.1 + * Style fixes (c4af8c3) + +##2013-04-02 - Dan Bode - 0.10.1 + * Add travisfile and Gemfile (c2052b3) + +##2013-04-02 - Chris Price - 0.10.1 + * Update README.markdown (ad38a08) + +##2013-02-15 - Karel Brezina - 0.10.0 + * Added 'ini_subsetting' custom resource type (4351d8b) + +##2013-03-11 - Dan Bode - 0.10.0 + * guard against nil indentation values (5f71d7f) + +##2013-01-07 - Dan Bode - 0.10.0 + * Add purging support to ini file (2f22483) + +##2013-02-05 - James Sweeny - 0.10.0 + * Fix test to use correct key_val_parameter (b1aff63) + +##2012-11-06 - Chris Price - 0.10.0 + * Added license file w/Apache 2.0 license (5e1d203) + +##2012-11-02 - Chris Price - 0.9.0 + * Version 0.9.0 released + +##2012-10-26 - Chris Price - 0.9.0 + * Add detection for commented versions of settings (a45ab65) + +##2012-10-20 - Chris Price - 0.9.0 + * Refactor to clarify implementation of `save` (f0d443f) + +##2012-10-20 - Chris Price - 0.9.0 + * Add example for `ensure=absent` (e517148) + +##2012-10-20 - Chris Price - 0.9.0 + * Better handling of whitespace lines at ends of sections (845fa70) + +##2012-10-20 - Chris Price - 0.9.0 + * Respect indentation / spacing for existing sections and settings (c2c26de) + +##2012-10-17 - Chris Price - 0.9.0 + * Minor tweaks to handling of removing settings (cda30a6) + +##2012-10-10 - Dan Bode - 0.9.0 + * Add support for removing lines (1106d70) + +##2012-10-02 - Dan Bode - 0.9.0 + * Make value a property (cbc90d3) + +##2012-10-02 - Dan Bode - 0.9.0 + * Make ruby provider a better parent. (1564c47) + +##2012-09-29 - Reid Vandewiele - 0.9.0 + * Allow values with spaces to be parsed and set (3829e20) + +##2012-09-24 - Chris Price - 0.0.3 + * Version 0.0.3 released + +##2012-09-20 - Chris Price - 0.0.3 + * Add validation for key_val_separator (e527908) + +##2012-09-19 - Chris Price - 0.0.3 + * Allow overriding separator string between key/val pairs (8d1fdc5) + +##2012-08-20 - Chris Price - 0.0.2 + * Version 0.0.2 released + +##2012-08-17 - Chris Price - 0.0.2 + * Add support for "global" section at beginning of file (c57dab4) diff --git a/puppet/modules/inifile/CONTRIBUTING.md b/puppet/modules/inifile/CONTRIBUTING.md new file mode 100755 index 0000000..bfeaa70 --- /dev/null +++ b/puppet/modules/inifile/CONTRIBUTING.md @@ -0,0 +1,220 @@ +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.puppetlabs.com/secure/CreateIssue!default.jspa), or [watch the ticket](https://tickets.puppetlabs.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 +% bundle exec 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 +% bundle exec rake spec_clean +% bundle exec 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://puppetlabs.com/community/get-help) + +* [Writing tests](http://projects.puppetlabs.com/projects/puppet/wiki/Development_Writing_Tests) + +* [Patchwork](https://patchwork.puppetlabs.com) + +* [General GitHub documentation](http://help.github.com/) + +* [GitHub pull request documentation](http://help.github.com/send-pull-requests/) + diff --git a/puppet/modules/inifile/Gemfile b/puppet/modules/inifile/Gemfile new file mode 100755 index 0000000..04f8667 --- /dev/null +++ b/puppet/modules/inifile/Gemfile @@ -0,0 +1,48 @@ +source ENV['GEM_SOURCE'] || "https://rubygems.org" + +def location_for(place, fake_version = nil) + if place =~ /^(git:[^#]*)#(.*)/ + [fake_version, { :git => $1, :branch => $2, :require => false }].compact + elsif place =~ /^file:\/\/(.*)/ + ['>= 0', { :path => File.expand_path($1), :require => false }] + else + [place, { :require => false }] + end +end + +group :development, :unit_tests do + gem 'rspec-core', '3.1.7', :require => false + gem 'puppetlabs_spec_helper', :require => false + gem 'simplecov', :require => false + gem 'puppet_facts', :require => false + gem 'json', :require => false +end + +group :system_tests do + if beaker_version = ENV['BEAKER_VERSION'] + gem 'beaker', *location_for(beaker_version) + end + if beaker_rspec_version = ENV['BEAKER_RSPEC_VERSION'] + gem 'beaker-rspec', *location_for(beaker_rspec_version) + else + gem 'beaker-rspec', :require => false + end + gem 'serverspec', :require => false + gem 'beaker-puppet_install_helper', :require => false +end + + + +if facterversion = ENV['FACTER_GEM_VERSION'] + gem 'facter', facterversion, :require => false +else + gem 'facter', :require => false +end + +if puppetversion = ENV['PUPPET_GEM_VERSION'] + gem 'puppet', puppetversion, :require => false +else + gem 'puppet', :require => false +end + +# vim:ft=ruby diff --git a/puppet/modules/inifile/LICENSE b/puppet/modules/inifile/LICENSE new file mode 100755 index 0000000..73caeda --- /dev/null +++ b/puppet/modules/inifile/LICENSE @@ -0,0 +1,201 @@ + 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 2012 Chris Price + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/puppet/modules/inifile/README.markdown b/puppet/modules/inifile/README.markdown new file mode 100755 index 0000000..9735697 --- /dev/null +++ b/puppet/modules/inifile/README.markdown @@ -0,0 +1,413 @@ +#inifile + +[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-inifile.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-inifile) + +####Table of Contents + +1. [Overview](#overview) +2. [Module Description - What the module does and why it is useful](#module-description) +3. [Setup - The basics of getting started with inifile module](#setup) + * [Beginning with inifile](#beginning-with-inifile) +4. [Usage - Configuration options and additional functionality](#usage) +5. [Reference - An under-the-hood peek at what the module is doing and how](#reference) +5. [Limitations - OS compatibility, etc.](#limitations) +6. [Development - Guide for contributing to the module](#development) + +##Overview + +The inifile module lets Puppet manage settings stored in INI-style configuration files. + +##Module Description + +Many applications use INI-style configuration files to store their settings. This module supplies two custom resource types to let you manage those settings through Puppet. + +##Setup + +###Beginning with inifile + +To manage a single setting in an INI file, add the `ini_setting` type to a class: + +~~~puppet +ini_setting { "sample setting": + ensure => present, + path => '/tmp/foo.ini', + section => 'bar', + setting => 'baz', + value => 'quux', +} +~~~ + +##Usage + + +The inifile module tries hard not to manipulate your file any more than it needs to. In most cases, it doesn't affect the original whitespace, comments, ordering, etc. + + * Supports comments starting with either '#' or ';'. + * Supports either whitespace or no whitespace around '='. + * Adds any missing sections to the INI file. + +###Manage multiple values in a setting + +Use the `ini_subsetting` type: + +~~~puppet +ini_subsetting {'sample subsetting': + ensure => present, + section => '', + key_val_separator => '=', + path => '/etc/default/pe-puppetdb', + setting => 'JAVA_ARGS', + subsetting => '-Xmx', + value => '512m', +} +~~~ + +Results in managing this `-Xmx` subsetting: + +~~~puppet +JAVA_ARGS="-Xmx512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof" +~~~ + + +###Use a non-standard section header + +~~~puppet +ini_setting { 'default minage': + ensure => present, + path => '/etc/security/users', + section => 'default', + setting => 'minage', + value => '1', + section_prefix => '', + section_suffix => ':', +} +~~~ + +Results in: + +~~~puppet +default: + minage = 1 +~~~ + +###Implement child providers + +You might want to create child providers that inherit the `ini_setting` provider, for one or both of these purposes: + + * Make a custom resource to manage an application that stores its settings in INI files, without recreating the code to manage the files themselves. + + * [Purge all unmanaged settings](https://docs.puppetlabs.com/references/latest/type.html#resources-attribute-purge) from a managed INI file. + +To implement child providers, first specify a custom type. Have it implement a namevar called `name` and a property called `value`: + +~~~ruby +#my_module/lib/puppet/type/glance_api_config.rb +Puppet::Type.newtype(:glance_api_config) do + ensurable + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from glance-api.conf' + # namevar should be of the form section/setting + newvalues(/\S+\/\S+/) + end + newproperty(:value) do + desc 'The value of the setting to define' + munge do |v| + v.to_s.strip + end + end +end +~~~ + +Your type also needs a provider that uses the `ini_setting` provider as its parent: + +~~~ruby +# my_module/lib/puppet/provider/glance_api_config/ini_setting.rb +Puppet::Type.type(:glance_api_config).provide( + :ini_setting, + # set ini_setting as the parent provider + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + # implement section as the first part of the namevar + def section + resource[:name].split('/', 2).first + end + def setting + # implement setting as the second part of the namevar + resource[:name].split('/', 2).last + end + # hard code the file path (this allows purging) + def self.file_path + '/etc/glance/glance-api.conf' + end +end +~~~ + +Now the settings in /etc/glance/glance-api.conf file can be managed as individual resources: + +~~~puppet +glance_api_config { 'HEADER/important_config': + value => 'secret_value', +} +~~~ + +If you've implemented self.file_path, you can have Puppet purge the file of all lines that aren't implemented as Puppet resources: + +~~~puppet +resources { 'glance_api_config' + purge => true, +} +~~~ + +### Manage multiple ini_settings + +To manage multiple ini_settings, use the [`create_ini_settings`](#function-create_ini_settings) function. + +~~~puppet +$defaults = { 'path' => '/tmp/foo.ini' } +$example = { 'section1' => { 'setting1' => 'value1' } } +create_ini_settings($example, $defaults) +~~~ + +results in: + +~~~puppet +ini_setting { '[section1] setting1': + ensure => present, + section => 'section1', + setting => 'setting1', + value => 'value1', + path => '/tmp/foo.ini', +} +~~~ + +To include special parameters, the following code: + +~~~puppet +$defaults = { 'path' => '/tmp/foo.ini' } +$example = { + 'section1' => { + 'setting1' => 'value1', + 'settings2' => { + 'ensure' => 'absent' + } + } +} +create_ini_settings($example, $defaults) +~~~ + +results in: + +~~~puppet +ini_setting { '[section1] setting1': + ensure => present, + section => 'section1', + setting => 'setting1', + value => 'value1', + path => '/tmp/foo.ini', +} +ini_setting { '[section1] setting2': + ensure => absent, + section => 'section1', + setting => 'setting2', + path => '/tmp/foo.ini', +} +~~~ + +#### Manage multiple ini_settings with Hiera + +This example requires Puppet 3.x/4.x, as it uses automatic retrieval of Hiera data for class parameters and `puppetlabs/stdlib`. + +For the profile `example`: + +~~~puppet +class profile::example ( + $settings, +) { + validate_hash($settings) + $defaults = { 'path' => '/tmp/foo.ini' } + create_ini_settings($settings, $defaults) +} +~~~ + +Provide this in your Hiera data: + +~~~puppet +profile::example::settings: + section1: + setting1: value1 + setting2: value2 + setting3: + ensure: absent +~~~ + +Results in: + +~~~puppet +ini_setting { '[section1] setting1': + ensure => present, + section => 'section1', + setting => 'setting1', + value => 'value1', + path => '/tmp/foo.ini', +} +ini_setting { '[section1] setting2': + ensure => present, + section => 'section1', + setting => 'setting2', + value => 'value2', + path => '/tmp/foo.ini', +} +ini_setting { '[section1] setting3': + ensure => absent, + section => 'section1', + setting => 'setting3', + path => '/tmp/foo.ini', +} +~~~ + + +##Reference + +###Public Types + + * [`ini_setting`](#type-ini_setting) + + * [`ini_subsetting`](#type-ini_subsetting) + +###Public Functions + + * [`create_ini_settings`](#function-create_ini_settings) + +### Type: ini_setting + +Manages a setting within an INI file. + +#### Parameters + +##### `ensure` + +Determines whether the specified setting should exist. Valid options: 'present' and 'absent'. Default value: 'present'. + +##### `key_val_separator` + +*Optional.* Specifies a string to use between each setting name and value (e.g., to determine whether the separator includes whitespace). Valid options: a string. Default value: ' = '. + +##### `name` + +*Optional.* Specifies an arbitrary name to identify the resource. Valid options: a string. Default value: the title of your declared resource. + +##### `path` + +*Required.* Specifies an INI file containing the setting to manage. Valid options: a string containing an absolute path. + +##### `section` + +*Required.* Designates a section of the specified INI file containing the setting to manage. To manage a global setting (at the beginning of the file, before any named sections) enter "". Valid options: a string. + +##### `setting` + +*Optional.* The name of the setting to define. Valid options: a string. + +##### `value` + +*Optional.* Supplies a value for the specified setting. Valid options: a string. Default value: undefined. + +##### `section_prefix` + +*Optional.* Designates the string that will appear before the section's name. Default value: "[" + +##### `section_suffix` + +*Optional.* Designates the string that will appear after the section's name. Default value: "]". + +**NOTE:** This type finds all sections in the file by looking for lines like `${section_prefix}${title}${section_suffix}`. + +### Type: ini_subsetting + +Manages multiple values within the same INI setting. + +#### Parameters + +##### `ensure` + +Specifies whether the subsetting should be present. Valid options: 'present' and 'absent'. Default value: 'present'. + +##### `key_val_separator` + +*Optional.* Specifies a string to use between setting name and value (e.g., to determine whether the separator includes whitespace). Valid options: a string. Default value: ' = '. + +##### `path` + +*Required.* Specifies an INI file containing the subsetting to manage. Valid options: a string containing an absolute path. + +##### `quote_char` + +*Optional.* The character used to quote the entire value of the setting. Valid values are '', '"', and "'". Defaults to ''. Valid options: '', '"' and "'". Default value: ''. + +##### `section` + +*Optional.* Designates a section of the specified INI file containing the setting to manage. To manage a global setting (at the beginning of the file, before any named sections) enter "". Defaults to "". Valid options: a string. + +##### `setting` + +*Required.* Designates a setting within the specified section containing the subsetting to manage. Valid options: a string. + +##### `subsetting` + +*Required.* Designates a subsetting to manage within the specified setting. Valid options: a string. + +##### `subsetting_separator` + +*Optional.* Specifies a string to use between subsettings. Valid options: a string. Default value: " ". + +##### `use_exact_match` + +*Optional.* Whether to use partial or exact matching for subsetting. Should be set to true if the subsettings do not have values. Valid options: true, false. Default value: false. + +##### `value` + +*Optional.* Supplies a value for the specified subsetting. Valid options: a string. Default value: undefined. + +### Function: create_ini_settings + +Manages multiple `ini_setting` resources from a hash. Note that this cannot be used with ini_subsettings. + +`create_ini_settings($settings, $defaults)` + +#### Arguments + +##### First argument: `settings` + +*Required.* Specify a hash representing the `ini_setting` resources you want to create. + +##### Second argument: `defaults` + +*Optional.* Accepts a hash to be used as the values for any attributes not defined in the first argument. + +~~~puppet +$example = { + 'section1' => { + 'setting1' => { + 'value' => 'value1', 'path' => '/tmp/foo.ini' + } + } +} +~~~ + +Default value: '{}'. + +##Limitations + +This module has been tested on [all PE-supported platforms](https://forge.puppetlabs.com/supported#compat-matrix), and no issues have been identified. Additionally, it is tested (but not supported) on Windows 7, Mac OS X 10.9, and Solaris 12. + +##Development + +Puppet Labs 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.puppetlabs.com/forge/contributing.html) + +###Contributors + +To see who's already involved, see the [list of contributors.](https://github.com/puppetlabs/puppetlabs-inifile/graphs/contributors) diff --git a/puppet/modules/inifile/Rakefile b/puppet/modules/inifile/Rakefile new file mode 100755 index 0000000..181157e --- /dev/null +++ b/puppet/modules/inifile/Rakefile @@ -0,0 +1,10 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' + +PuppetLint.configuration.fail_on_warnings = true +PuppetLint.configuration.send('relative') +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.send('disable_class_inherits_from_params_class') +PuppetLint.configuration.send('disable_documentation') +PuppetLint.configuration.send('disable_single_quote_string_with_variables') +PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"] diff --git a/puppet/modules/inifile/examples/ini_setting.pp b/puppet/modules/inifile/examples/ini_setting.pp new file mode 100755 index 0000000..279cb00 --- /dev/null +++ b/puppet/modules/inifile/examples/ini_setting.pp @@ -0,0 +1,25 @@ +ini_setting { 'sample setting': + ensure => present, + path => '/tmp/foo.ini', + section => 'foo', + setting => 'foosetting', + value => 'FOO!', +} + +ini_setting { 'sample setting2': + ensure => present, + path => '/tmp/foo.ini', + section => 'bar', + setting => 'barsetting', + value => 'BAR!', + key_val_separator => '=', + require => Ini_setting['sample setting'], +} + +ini_setting { 'sample setting3': + ensure => absent, + path => '/tmp/foo.ini', + section => 'bar', + setting => 'bazsetting', + require => Ini_setting['sample setting2'], +} diff --git a/puppet/modules/inifile/examples/ini_subsetting.pp b/puppet/modules/inifile/examples/ini_subsetting.pp new file mode 100755 index 0000000..0458354 --- /dev/null +++ b/puppet/modules/inifile/examples/ini_subsetting.pp @@ -0,0 +1,18 @@ +ini_subsetting { 'sample subsetting': + ensure => present, + section => '', + key_val_separator => '=', + path => '/etc/default/pe-puppetdb', + setting => 'JAVA_ARGS', + subsetting => '-Xmx', + value => '512m', +} + +ini_subsetting { 'sample subsetting2': + ensure => absent, + section => '', + key_val_separator => '=', + path => '/etc/default/pe-puppetdb', + setting => 'JAVA_ARGS', + subsetting => '-Xms', +} diff --git a/puppet/modules/inifile/lib/puppet/parser/functions/create_ini_settings.rb b/puppet/modules/inifile/lib/puppet/parser/functions/create_ini_settings.rb new file mode 100755 index 0000000..8e14591 --- /dev/null +++ b/puppet/modules/inifile/lib/puppet/parser/functions/create_ini_settings.rb @@ -0,0 +1,86 @@ +# +# create_ini_settings.rb +# + +module Puppet::Parser::Functions + newfunction(:create_ini_settings, :type => :statement, :doc => <<-EOS +Uses create_resources to create a set of ini_setting resources from a hash: + + $settings = { section1 => { + setting1 => val1 + }, + section2 => { + setting2 => val2, + setting3 => { + ensure => absent + } + } + } + $defaults = { + path => '/tmp/foo.ini' + } + create_ini_settings($settings,$defaults) + + +Will create the following resources + + ini_setting{'[section1] setting1': + ensure => present, + section => 'section1', + setting => 'setting1', + value => 'val1', + path => '/tmp/foo.ini', + } + ini_setting{'[section2] setting2': + ensure => present, + section => 'section2', + setting => 'setting2', + value => 'val2', + path => '/tmp/foo.ini', + } + ini_setting{'[section2] setting3': + ensure => absent, + section => 'section2', + setting => 'setting3', + path => '/tmp/foo.ini', + } + +EOS + ) do |arguments| + + raise(Puppet::ParseError, "create_ini_settings(): Wrong number of arguments " + + "given (#{arguments.size} for 1 or 2)") unless arguments.size.between?(1,2) + + settings = arguments[0] + defaults = arguments[1] || {} + + if [settings,defaults].any?{|i| !i.is_a?(Hash) } + raise(Puppet::ParseError, + 'create_ini_settings(): Requires all arguments to be a Hash') + end + + resources = settings.keys.inject({}) do |res, section| + raise(Puppet::ParseError, + "create_ini_settings(): Section #{section} must contain a Hash") \ + unless settings[section].is_a?(Hash) + + settings[section].each do |setting, value| + res["[#{section}] #{setting}"] = { + 'ensure' => 'present', + 'section' => section, + 'setting' => setting, + }.merge(if value.is_a?(Hash) + value + else + { 'value' => value, } + end) + end + res + end + + Puppet::Parser::Functions.function('create_resources') + function_create_resources(['ini_setting',resources,defaults]) + end +end + +# vim: set ts=2 sw=2 et : diff --git a/puppet/modules/inifile/lib/puppet/provider/ini_setting/ruby.rb b/puppet/modules/inifile/lib/puppet/provider/ini_setting/ruby.rb new file mode 100755 index 0000000..2455541 --- /dev/null +++ b/puppet/modules/inifile/lib/puppet/provider/ini_setting/ruby.rb @@ -0,0 +1,118 @@ +require File.expand_path('../../../util/ini_file', __FILE__) + +Puppet::Type.type(:ini_setting).provide(:ruby) do + + def self.instances + # this code is here to support purging and the query-all functionality of the + # 'puppet resource' command, on a per-file basis. Users + # can create a type for a specific config file with a provider that uses + # this as its parent and implements the method + # 'self.file_path', and that will provide the value for the path to the + # ini file (rather than needing to specify it on each ini setting + # declaration). This allows 'purging' to be used to clear out + # all settings from a particular ini file except those included in + # the catalog. + if self.respond_to?(:file_path) + # figure out what to do about the seperator + ini_file = Puppet::Util::IniFile.new(file_path, '=') + resources = [] + ini_file.section_names.each do |section_name| + ini_file.get_settings(section_name).each do |setting, value| + resources.push( + new( + :name => namevar(section_name, setting), + :value => value, + :ensure => :present + ) + ) + end + end + resources + else + raise(Puppet::Error, 'Ini_settings only support collecting instances when a file path is hard coded') + end + end + + def self.namevar(section_name, setting) + "#{section_name}/#{setting}" + end + + def exists? + !ini_file.get_value(section, setting).nil? + end + + def create + ini_file.set_value(section, setting, resource[:value]) + ini_file.save + @ini_file = nil + end + + def destroy + ini_file.remove_setting(section, setting) + ini_file.save + @ini_file = nil + end + + def value + ini_file.get_value(section, setting) + end + + def value=(value) + ini_file.set_value(section, setting, resource[:value]) + ini_file.save + end + + def section + # this method is here so that it can be overridden by a child provider + resource[:section] + end + + def setting + # this method is here so that it can be overridden by a child provider + resource[:setting] + end + + def file_path + # this method is here to support purging and sub-classing. + # if a user creates a type and subclasses our provider and provides a + # 'file_path' method, then they don't have to specify the + # path as a parameter for every ini_setting declaration. + # This implementation allows us to support that while still + # falling back to the parameter value when necessary. + if self.class.respond_to?(:file_path) + self.class.file_path + else + resource[:path] + end + end + + def separator + if resource.class.validattr?(:key_val_separator) + resource[:key_val_separator] || '=' + else + '=' + end + end + + def section_prefix + if resource.class.validattr?(:section_prefix) + resource[:section_prefix] || '[' + else + '[' + end + end + + def section_suffix + if resource.class.validattr?(:section_suffix) + resource[:section_suffix] || ']' + else + ']' + end + end + + private + def ini_file + @ini_file ||= Puppet::Util::IniFile.new(file_path, separator, section_prefix, section_suffix) + end + +end diff --git a/puppet/modules/inifile/lib/puppet/provider/ini_subsetting/ruby.rb b/puppet/modules/inifile/lib/puppet/provider/ini_subsetting/ruby.rb new file mode 100755 index 0000000..dbe9961 --- /dev/null +++ b/puppet/modules/inifile/lib/puppet/provider/ini_subsetting/ruby.rb @@ -0,0 +1,73 @@ +require File.expand_path('../../../util/ini_file', __FILE__) +require File.expand_path('../../../util/setting_value', __FILE__) + +Puppet::Type.type(:ini_subsetting).provide(:ruby) do + + def exists? + setting_value.get_subsetting_value(subsetting, resource[:use_exact_match]) + end + + def create + setting_value.add_subsetting(subsetting, resource[:value], resource[:use_exact_match]) + ini_file.set_value(section, setting, setting_value.get_value) + ini_file.save + @ini_file = nil + @setting_value = nil + end + + def destroy + setting_value.remove_subsetting(subsetting, resource[:use_exact_match]) + ini_file.set_value(section, setting, setting_value.get_value) + ini_file.save + @ini_file = nil + @setting_value = nil + end + + def value + setting_value.get_subsetting_value(subsetting) + end + + def value=(value) + setting_value.add_subsetting(subsetting, resource[:value], resource[:use_exact_match]) + ini_file.set_value(section, setting, setting_value.get_value) + ini_file.save + end + + def section + resource[:section] + end + + def setting + resource[:setting] + end + + def subsetting + resource[:subsetting] + end + + def subsetting_separator + resource[:subsetting_separator] + end + + def file_path + resource[:path] + end + + def separator + resource[:key_val_separator] || '=' + end + + def quote_char + resource[:quote_char] + end + + private + def ini_file + @ini_file ||= Puppet::Util::IniFile.new(file_path, separator) + end + + def setting_value + @setting_value ||= Puppet::Util::SettingValue.new(ini_file.get_value(section, setting), subsetting_separator, quote_char) + end + +end diff --git a/puppet/modules/inifile/lib/puppet/type/ini_setting.rb b/puppet/modules/inifile/lib/puppet/type/ini_setting.rb new file mode 100755 index 0000000..0ec223c --- /dev/null +++ b/puppet/modules/inifile/lib/puppet/type/ini_setting.rb @@ -0,0 +1,60 @@ +Puppet::Type.newtype(:ini_setting) do + + ensurable do + defaultvalues + defaultto :present + end + + newparam(:name, :namevar => true) do + desc 'An arbitrary name used as the identity of the resource.' + end + + newparam(:section) do + desc 'The name of the section in the ini file in which the setting should be defined.' + + 'If not provided, defaults to global, top of file, sections.' + defaultto("") + end + + newparam(:setting) do + desc 'The name of the setting to be defined.' + munge do |value| + if value =~ /(^\s|\s$)/ + Puppet.warn("Settings should not have spaces in the value, we are going to strip the whitespace") + end + value.lstrip.rstrip + end + end + + newparam(:path) do + desc 'The ini file Puppet will ensure contains the specified setting.' + validate do |value| + unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/)) + raise(Puppet::Error, "File paths must be fully qualified, not '#{value}'") + end + end + end + + newparam(:key_val_separator) do + desc 'The separator string to use between each setting name and value. ' + + 'Defaults to " = ", but you could use this to override e.g. ": ", or' + + 'whether or not the separator should include whitespace.' + defaultto(" = ") + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + end + + newparam(:section_prefix) do + desc 'The prefix to the section name\'s header.' + + 'Defaults to \'[\'.' + defaultto('[') + end + + newparam(:section_suffix) do + desc 'The suffix to the section name\'s header.' + + 'Defaults to \']\'.' + defaultto(']') + end + +end diff --git a/puppet/modules/inifile/lib/puppet/type/ini_subsetting.rb b/puppet/modules/inifile/lib/puppet/type/ini_subsetting.rb new file mode 100755 index 0000000..88a7c60 --- /dev/null +++ b/puppet/modules/inifile/lib/puppet/type/ini_subsetting.rb @@ -0,0 +1,69 @@ +Puppet::Type.newtype(:ini_subsetting) do + + ensurable do + defaultvalues + defaultto :present + end + + newparam(:name, :namevar => true) do + desc 'An arbitrary name used as the identity of the resource.' + end + + newparam(:section) do + desc 'The name of the section in the ini file in which the setting should be defined.' + + 'If not provided, defaults to global, top of file, sections.' + defaultto("") + end + + newparam(:setting) do + desc 'The name of the setting to be defined.' + end + + newparam(:subsetting) do + desc 'The name of the subsetting to be defined.' + end + + newparam(:subsetting_separator) do + desc 'The separator string between subsettings. Defaults to " "' + defaultto(" ") + end + + newparam(:path) do + desc 'The ini file Puppet will ensure contains the specified setting.' + validate do |value| + unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/)) + raise(Puppet::Error, "File paths must be fully qualified, not '#{value}'") + end + end + end + + newparam(:key_val_separator) do + desc 'The separator string to use between each setting name and value. ' + + 'Defaults to " = ", but you could use this to override e.g. ": ", or' + + 'whether or not the separator should include whitespace.' + defaultto(" = ") + end + + newparam(:quote_char) do + desc 'The character used to quote the entire value of the setting. ' + + %q{Valid values are '', '"' and "'". Defaults to ''.} + defaultto('') + + validate do |value| + unless value =~ /^["']?$/ + raise Puppet::Error, %q{:quote_char valid values are '', '"' and "'"} + end + end + end + + newparam(:use_exact_match) do + desc 'Set to true if your subsettings don\'t have values and you want to use exact matches to determine if the subsetting exists. See MODULES-2212' + newvalues(:true, :false) + defaultto(:false) + end + + newproperty(:value) do + desc 'The value of the subsetting to be defined.' + end + +end diff --git a/puppet/modules/inifile/lib/puppet/util/external_iterator.rb b/puppet/modules/inifile/lib/puppet/util/external_iterator.rb new file mode 100755 index 0000000..45c0fa4 --- /dev/null +++ b/puppet/modules/inifile/lib/puppet/util/external_iterator.rb @@ -0,0 +1,28 @@ +module Puppet +module Util + class ExternalIterator + def initialize(coll) + @coll = coll + @cur_index = -1 + end + + def next + @cur_index = @cur_index + 1 + item_at(@cur_index) + end + + def peek + item_at(@cur_index + 1) + end + + private + def item_at(index) + if @coll.length > index + [@coll[index], index] + else + [nil, nil] + end + end + end +end +end diff --git a/puppet/modules/inifile/lib/puppet/util/ini_file.rb b/puppet/modules/inifile/lib/puppet/util/ini_file.rb new file mode 100755 index 0000000..6305780 --- /dev/null +++ b/puppet/modules/inifile/lib/puppet/util/ini_file.rb @@ -0,0 +1,326 @@ +require File.expand_path('../external_iterator', __FILE__) +require File.expand_path('../ini_file/section', __FILE__) + +module Puppet +module Util + class IniFile + + def initialize(path, key_val_separator = ' = ', section_prefix = '[', section_suffix = ']') + + k_v_s = key_val_separator =~ /^\s+$/ ? ' ' : key_val_separator.strip + + @section_prefix = section_prefix + @section_suffix = section_suffix + + @@SECTION_REGEX = section_regex + @@SETTING_REGEX = /^(\s*)([^#;\s]|[^#;\s].*?[^\s#{k_v_s}])(\s*#{k_v_s}[ \t]*)(.*)\s*$/ + @@COMMENTED_SETTING_REGEX = /^(\s*)[#;]+(\s*)(.*?[^\s#{k_v_s}])(\s*#{k_v_s}[ \t]*)(.*)\s*$/ + + @path = path + @key_val_separator = key_val_separator + @section_names = [] + @sections_hash = {} + if File.file?(@path) + parse_file + end + end + + def section_regex + # Only put in prefix/suffix if they exist + # Also, if the prefix is '', the negated + # set match should be a match all instead. + r_string = '^\s*' + r_string += Regexp.escape(@section_prefix) + r_string += '(' + if @section_prefix != '' + r_string += '[^' + r_string += Regexp.escape(@section_prefix) + r_string += ']' + else + r_string += '.' + end + r_string += '*)' + r_string += Regexp.escape(@section_suffix) + r_string += '\s*$' + /#{r_string}/ + end + + def section_names + @section_names + end + + def get_settings(section_name) + section = @sections_hash[section_name] + section.setting_names.inject({}) do |result, setting| + result[setting] = section.get_value(setting) + result + end + end + + def get_value(section_name, setting) + if (@sections_hash.has_key?(section_name)) + @sections_hash[section_name].get_value(setting) + end + end + + def set_value(section_name, setting, value) + unless (@sections_hash.has_key?(section_name)) + add_section(Section.new(section_name, nil, nil, nil, nil)) + end + + section = @sections_hash[section_name] + + if (section.has_existing_setting?(setting)) + update_line(section, setting, value) + section.update_existing_setting(setting, value) + elsif result = find_commented_setting(section, setting) + # So, this stanza is a bit of a hack. What we're trying + # to do here is this: for settings that don't already + # exist, we want to take a quick peek to see if there + # is a commented-out version of them in the section. + # If so, we'd prefer to add the setting directly after + # the commented line, rather than at the end of the section. + + # If we get here then we found a commented line, so we + # call "insert_inline_setting_line" to update the lines array + insert_inline_setting_line(result, section, setting, value) + + # Then, we need to tell the setting object that we hacked + # in an inline setting + section.insert_inline_setting(setting, value) + + # Finally, we need to update all of the start/end line + # numbers for all of the sections *after* the one that + # was modified. + section_index = @section_names.index(section_name) + increment_section_line_numbers(section_index + 1) + else + section.set_additional_setting(setting, value) + end + end + + def remove_setting(section_name, setting) + section = @sections_hash[section_name] + if (section.has_existing_setting?(setting)) + # If the setting is found, we have some work to do. + # First, we remove the line from our array of lines: + remove_line(section, setting) + + # Then, we need to tell the setting object to remove + # the setting from its state: + section.remove_existing_setting(setting) + + # Finally, we need to update all of the start/end line + # numbers for all of the sections *after* the one that + # was modified. + section_index = @section_names.index(section_name) + decrement_section_line_numbers(section_index + 1) + end + end + + def save + File.open(@path, 'w') do |fh| + + @section_names.each_index do |index| + name = @section_names[index] + + section = @sections_hash[name] + + # We need a buffer to cache lines that are only whitespace + whitespace_buffer = [] + + if (section.is_new_section?) && (! section.is_global?) + fh.puts("\n#{@section_prefix}#{section.name}#{@section_suffix}") + end + + if ! section.is_new_section? + # write all of the pre-existing settings + (section.start_line..section.end_line).each do |line_num| + line = lines[line_num] + + # We buffer any lines that are only whitespace so that + # if they are at the end of a section, we can insert + # any new settings *before* the final chunk of whitespace + # lines. + if (line =~ /^\s*$/) + whitespace_buffer << line + else + # If we get here, we've found a non-whitespace line. + # We'll flush any cached whitespace lines before we + # write it. + flush_buffer_to_file(whitespace_buffer, fh) + fh.puts(line) + end + end + end + + # write new settings, if there are any + section.additional_settings.each_pair do |key, value| + fh.puts("#{' ' * (section.indentation || 0)}#{key}#{@key_val_separator}#{value}") + end + + if (whitespace_buffer.length > 0) + flush_buffer_to_file(whitespace_buffer, fh) + else + # We get here if there were no blank lines at the end of the + # section. + # + # If we are adding a new section with a new setting, + # and if there are more sections that come after this one, + # we'll write one blank line just so that there is a little + # whitespace between the sections. + #if (section.end_line.nil? && + if (section.is_new_section? && + (section.additional_settings.length > 0) && + (index < @section_names.length - 1)) + fh.puts("") + end + end + + end + end + end + + + private + def add_section(section) + @sections_hash[section.name] = section + @section_names << section.name + end + + def parse_file + line_iter = create_line_iter + + # We always create a "global" section at the beginning of the file, for + # anything that appears before the first named section. + section = read_section('', 0, line_iter) + add_section(section) + line, line_num = line_iter.next + + while line + if (match = @@SECTION_REGEX.match(line)) + section = read_section(match[1], line_num, line_iter) + add_section(section) + end + line, line_num = line_iter.next + end + end + + def read_section(name, start_line, line_iter) + settings = {} + end_line_num = nil + min_indentation = nil + while true + line, line_num = line_iter.peek + if (line_num.nil? or match = @@SECTION_REGEX.match(line)) + return Section.new(name, start_line, end_line_num, settings, min_indentation) + elsif (match = @@SETTING_REGEX.match(line)) + settings[match[2]] = match[4] + indentation = match[1].length + min_indentation = [indentation, min_indentation || indentation].min + end + end_line_num = line_num + line_iter.next + end + end + + def update_line(section, setting, value) + (section.start_line..section.end_line).each do |line_num| + if (match = @@SETTING_REGEX.match(lines[line_num])) + if (match[2] == setting) + lines[line_num] = "#{match[1]}#{match[2]}#{match[3]}#{value}" + end + end + end + end + + def remove_line(section, setting) + (section.start_line..section.end_line).each do |line_num| + if (match = @@SETTING_REGEX.match(lines[line_num])) + if (match[2] == setting) + lines.delete_at(line_num) + end + end + end + end + + def create_line_iter + ExternalIterator.new(lines) + end + + def lines + @lines ||= IniFile.readlines(@path) + end + + # This is mostly here because it makes testing easier--we don't have + # to try to stub any methods on File. + def self.readlines(path) + # If this type is ever used with very large files, we should + # write this in a different way, using a temp + # file; for now assuming that this type is only used on + # small-ish config files that can fit into memory without + # too much trouble. + File.readlines(path) + end + + # This utility method scans through the lines for a section looking for + # commented-out versions of a setting. It returns `nil` if it doesn't + # find one. If it does find one, then it returns a hash containing + # two keys: + # + # :line_num - the line number that contains the commented version + # of the setting + # :match - the ruby regular expression match object, which can + # be used to mimic the whitespace from the comment line + def find_commented_setting(section, setting) + return nil if section.is_new_section? + (section.start_line..section.end_line).each do |line_num| + if (match = @@COMMENTED_SETTING_REGEX.match(lines[line_num])) + if (match[3] == setting) + return { :match => match, :line_num => line_num } + end + end + end + nil + end + + # This utility method is for inserting a line into the existing + # lines array. The `result` argument is expected to be in the + # format of the return value of `find_commented_setting`. + def insert_inline_setting_line(result, section, setting, value) + line_num = result[:line_num] + match = result[:match] + lines.insert(line_num + 1, "#{' ' * (section.indentation || 0 )}#{setting}#{match[4]}#{value}") + end + + # Utility method; given a section index (index into the @section_names + # array), decrement the start/end line numbers for that section and all + # all of the other sections that appear *after* the specified section. + def decrement_section_line_numbers(section_index) + @section_names[section_index..(@section_names.length - 1)].each do |name| + section = @sections_hash[name] + section.decrement_line_nums + end + end + + # Utility method; given a section index (index into the @section_names + # array), increment the start/end line numbers for that section and all + # all of the other sections that appear *after* the specified section. + def increment_section_line_numbers(section_index) + @section_names[section_index..(@section_names.length - 1)].each do |name| + section = @sections_hash[name] + section.increment_line_nums + end + end + + + def flush_buffer_to_file(buffer, fh) + if buffer.length > 0 + buffer.each { |l| fh.puts(l) } + buffer.clear + end + end + + end +end +end diff --git a/puppet/modules/inifile/lib/puppet/util/ini_file/section.rb b/puppet/modules/inifile/lib/puppet/util/ini_file/section.rb new file mode 100755 index 0000000..9682d7f --- /dev/null +++ b/puppet/modules/inifile/lib/puppet/util/ini_file/section.rb @@ -0,0 +1,103 @@ +module Puppet +module Util +class IniFile + class Section + # Some implementation details: + # + # * `name` will be set to the empty string for the 'global' section. + # * there will always be a 'global' section, with a `start_line` of 0, + # but if the file actually begins with a real section header on + # the first line, then the 'global' section will have an + # `end_line` of `nil`. + # * `start_line` and `end_line` will be set to `nil` for a new non-global + # section. + def initialize(name, start_line, end_line, settings, indentation) + @name = name + @start_line = start_line + @end_line = end_line + @existing_settings = settings.nil? ? {} : settings + @additional_settings = {} + @indentation = indentation + end + + attr_reader :name, :start_line, :end_line, :additional_settings, :indentation + + def is_global?() + @name == '' + end + + def is_new_section?() + # a new section (global or named) will always have `end_line` + # set to `nil` + @end_line.nil? + end + + def setting_names + @existing_settings.keys | @additional_settings.keys + end + + def get_value(setting_name) + @existing_settings[setting_name] || @additional_settings[setting_name] + end + + def has_existing_setting?(setting_name) + @existing_settings.has_key?(setting_name) + end + + def update_existing_setting(setting_name, value) + @existing_settings[setting_name] = value + end + + def remove_existing_setting(setting_name) + if (@existing_settings.delete(setting_name)) + if @end_line + @end_line = @end_line - 1 + end + end + end + + # This is a hacky method; it's basically called when we need to insert + # a new setting but we don't want it to appear at the very end of the + # section. Instead we hack it into the existing settings list and + # increment our end_line number--this assumes that the caller (`ini_file`) + # is doing some babysitting w/rt the other sections and the actual data + # of the lines. + def insert_inline_setting(setting_name, value) + @existing_settings[setting_name] = value + if @end_line + @end_line = @end_line + 1 + end + end + + def set_additional_setting(setting_name, value) + @additional_settings[setting_name] = value + end + + # Decrement the start and end line numbers for the section (if they are + # defined); this is intended to be called when a setting is removed + # from a section that comes before this section in the ini file. + def decrement_line_nums() + if @start_line + @start_line = @start_line - 1 + end + if @end_line + @end_line = @end_line - 1 + end + end + + # Increment the start and end line numbers for the section (if they are + # defined); this is intended to be called when an inline setting is added + # to a section that comes before this section in the ini file. + def increment_line_nums() + if @start_line + @start_line = @start_line + 1 + end + if @end_line + @end_line = @end_line + 1 + end + end + + end +end +end +end diff --git a/puppet/modules/inifile/lib/puppet/util/setting_value.rb b/puppet/modules/inifile/lib/puppet/util/setting_value.rb new file mode 100755 index 0000000..5ccd3ca --- /dev/null +++ b/puppet/modules/inifile/lib/puppet/util/setting_value.rb @@ -0,0 +1,103 @@ +module Puppet + module Util + + class SettingValue + + def initialize(setting_value, subsetting_separator = ' ', default_quote_char = nil) + @setting_value = setting_value + @subsetting_separator = subsetting_separator + + default_quote_char ||= '' + + if @setting_value + unquoted, @quote_char = unquote_setting_value(setting_value) + @subsetting_items = unquoted.scan(Regexp.new("(?:(?:[^\\#{@subsetting_separator}]|\\.)+)")) # an item can contain escaped separator + @subsetting_items.map! { |item| item.strip } + @quote_char = default_quote_char if @quote_char.empty? + else + @subsetting_items = [] + @quote_char = default_quote_char + end + end + + def unquote_setting_value(setting_value) + quote_char = "" + if (setting_value.start_with?('"') and setting_value.end_with?('"')) + quote_char = '"' + elsif (setting_value.start_with?("'") and setting_value.end_with?("'")) + quote_char = "'" + end + + unquoted = setting_value + + if (quote_char != "") + unquoted = setting_value[1, setting_value.length - 2] + end + + [unquoted, quote_char] + end + + def get_value + + result = "" + first = true + + @subsetting_items.each { |item| + result << @subsetting_separator unless first + result << item + first = false + } + + @quote_char + result + @quote_char + end + + def get_subsetting_value(subsetting, use_exact_match=:false) + + value = nil + + @subsetting_items.each { |item| + if(use_exact_match == :false and item.start_with?(subsetting)) + value = item[subsetting.length, item.length - subsetting.length] + break + elsif(use_exact_match == :true and item.eql?(subsetting)) + return true + end + } + + value + end + + def add_subsetting(subsetting, subsetting_value, use_exact_match=:false) + + new_item = subsetting + (subsetting_value || '') + found = false + + @subsetting_items.map! { |item| + if use_exact_match == :false and item.start_with?(subsetting) + value = new_item + found = true + elsif use_exact_match == :true and item.eql?(subsetting) + value = new_item + found = true + else + value = item + end + + value + } + + unless found + @subsetting_items.push(new_item) + end + end + + def remove_subsetting(subsetting, use_exact_match=:false) + if use_exact_match == :false + @subsetting_items = @subsetting_items.map { |item| item.start_with?(subsetting) ? nil : item }.compact + else + @subsetting_items = @subsetting_items.map { |item| item.eql?(subsetting) ? nil : item }.compact + end + end + end + end +end diff --git a/puppet/modules/inifile/metadata.json b/puppet/modules/inifile/metadata.json new file mode 100755 index 0000000..01b6b17 --- /dev/null +++ b/puppet/modules/inifile/metadata.json @@ -0,0 +1,105 @@ +{ + "name": "puppetlabs-inifile", + "version": "1.4.2", + "author": "Puppet Labs", + "summary": "Resource types for managing settings in INI files", + "license": "Apache-2.0", + "source": "https://github.com/puppetlabs/puppetlabs-inifile", + "project_page": "https://github.com/puppetlabs/puppetlabs-inifile", + "issues_url": "https://tickets.puppetlabs.com/browse/MODULES", + "operatingsystem_support": [ + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "CentOS", + "operatingsystemrelease": [ + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "OracleLinux", + "operatingsystemrelease": [ + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "Scientific", + "operatingsystemrelease": [ + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "SLES", + "operatingsystemrelease": [ + "10 SP4", + "11 SP1", + "12" + ] + }, + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "6", + "7" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "10.04", + "12.04", + "14.04" + ] + }, + { + "operatingsystem": "Solaris", + "operatingsystemrelease": [ + "10", + "11", + "12" + ] + }, + { + "operatingsystem": "Windows", + "operatingsystemrelease": [ + "Server 2003 R2", + "Server 2008 R2", + "Server 2012", + "Server 2012 R2" + ] + }, + { + "operatingsystem": "AIX", + "operatingsystemrelease": [ + "5.3", + "6.1", + "7.1" + ] + } + ], + "requirements": [ + { + "name": "pe", + "version_requirement": ">= 3.0.0 < 2015.3.0" + }, + { + "name": "puppet", + "version_requirement": ">= 3.0.0 < 5.0.0" + } + ], + "dependencies": [ + + ] +} diff --git a/puppet/modules/inifile/spec/acceptance/ini_setting_spec.rb b/puppet/modules/inifile/spec/acceptance/ini_setting_spec.rb new file mode 100755 index 0000000..669679c --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/ini_setting_spec.rb @@ -0,0 +1,284 @@ +require 'spec_helper_acceptance' + +tmpdir = default.tmpdir('tmp') + +describe 'ini_setting resource' do + after :all do + shell("rm #{tmpdir}/*.ini", :acceptable_exit_codes => [0, 1, 2]) + end + + shared_examples 'has_content' do |path, pp, content| + before :all do + shell("rm #{path}", :acceptable_exit_codes => [0, 1, 2]) + end + after :all do + shell("cat #{path}", :acceptable_exit_codes => [0, 1, 2]) + shell("rm #{path}", :acceptable_exit_codes => [0, 1, 2]) + end + + it 'applies the manifest twice' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file(path) do + it { should be_file } + its(:content) { should match content } + end + end + + shared_examples 'has_error' do |path, pp, error| + before :all do + shell("rm #{path}", :acceptable_exit_codes => [0, 1, 2]) + end + after :all do + shell("cat #{path}", :acceptable_exit_codes => [0, 1, 2]) + shell("rm #{path}", :acceptable_exit_codes => [0, 1, 2]) + end + + it 'applies the manifest and gets a failure message' do + expect(apply_manifest(pp, :expect_failures => true).stderr).to match(error) + end + + describe file(path) do + it { should_not be_file } + end + end + + describe 'ensure parameter' do + context '=> present for global and section' do + pp = <<-EOS + ini_setting { 'ensure => present for section': + ensure => present, + path => "#{tmpdir}/ini_setting.ini", + section => 'one', + setting => 'two', + value => 'three', + } + ini_setting { 'ensure => present for global': + ensure => present, + path => "#{tmpdir}/ini_setting.ini", + section => '', + setting => 'four', + value => 'five', + } + EOS + + it 'applies the manifest twice' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + it_behaves_like 'has_content', "#{tmpdir}/ini_setting.ini", pp, /four = five\n\n\[one\]\ntwo = three/ + end + + context '=> present for global and section (from previous blank value)' do + before :all do + if fact('osfamily') == 'Darwin' + shell("echo \"four =[one]\ntwo =\" > #{tmpdir}/ini_setting.ini") + else + shell("echo -e \"four =\n[one]\ntwo =\" > #{tmpdir}/ini_setting.ini") + end + end + + pp = <<-EOS + ini_setting { 'ensure => present for section': + ensure => present, + path => "#{tmpdir}/ini_setting.ini", + section => 'one', + setting => 'two', + value => 'three', + } + ini_setting { 'ensure => present for global': + ensure => present, + path => "#{tmpdir}/ini_setting.ini", + section => '', + setting => 'four', + value => 'five', + } + EOS + + it 'applies the manifest twice' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + it_behaves_like 'has_content', "#{tmpdir}/ini_setting.ini", pp, /four = five\n\n\[one\]\ntwo = three/ + end + + context '=> absent for key/value' do + before :all do + if fact('osfamily') == 'Darwin' + shell("echo \"four = five[one]\ntwo = three\" > #{tmpdir}/ini_setting.ini") + else + shell("echo -e \"four = five\n[one]\ntwo = three\" > #{tmpdir}/ini_setting.ini") + end + end + + pp = <<-EOS + ini_setting { 'ensure => absent for key/value': + ensure => absent, + path => "#{tmpdir}/ini_setting.ini", + section => 'one', + setting => 'two', + value => 'three', + } + EOS + + it 'applies the manifest twice' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{tmpdir}/ini_setting.ini") do + it { should be_file } + its(:content) { + should match /four = five/ + should match /\[one\]/ + should_not match /two = three/ + } + end + end + + context '=> absent for global' do + before :all do + if fact('osfamily') == 'Darwin' + shell("echo \"four = five\n[one]\ntwo = three\" > #{tmpdir}/ini_setting.ini") + else + shell("echo -e \"four = five\n[one]\ntwo = three\" > #{tmpdir}/ini_setting.ini") + end + end + after :all do + shell("cat #{tmpdir}/ini_setting.ini", :acceptable_exit_codes => [0, 1, 2]) + shell("rm #{tmpdir}/ini_setting.ini", :acceptable_exit_codes => [0, 1, 2]) + end + + pp = <<-EOS + ini_setting { 'ensure => absent for global': + ensure => absent, + path => "#{tmpdir}/ini_setting.ini", + section => '', + setting => 'four', + value => 'five', + } + EOS + + it 'applies the manifest twice' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{tmpdir}/ini_setting.ini") do + it { should be_file } + its(:content) { + should_not match /four = five/ + should match /\[one\]/ + should match /two = three/ + } + end + end + end + + describe 'section, setting, value parameters' do + { + "section => 'test', setting => 'foo', value => 'bar'," => /\[test\]\nfoo = bar/, + "section => 'more', setting => 'baz', value => 'quux'," => /\[more\]\nbaz = quux/, + "section => '', setting => 'top', value => 'level'," => /top = level/, + "section => 'z', setting => 'sp aces', value => 'foo bar'," => /\[z\]\nsp aces = foo bar/, + }.each do |parameter_list, content| + context parameter_list do + pp = <<-EOS + ini_setting { "#{parameter_list}": + ensure => present, + path => "#{tmpdir}/ini_setting.ini", + #{parameter_list} + } + EOS + + it_behaves_like 'has_content', "#{tmpdir}/ini_setting.ini", pp, content + end + end + + { + "section => 'test'," => /setting is a required.+value is a required/, + "setting => 'foo', value => 'bar'," => /section is a required/, + "section => 'test', setting => 'foo'," => /value is a required/, + "section => 'test', value => 'bar'," => /setting is a required/, + "value => 'bar'," => /section is a required.+setting is a required/, + "setting => 'foo'," => /section is a required.+value is a required/, + }.each do |parameter_list, error| + context parameter_list, :pending => 'no error checking yet' do + pp = <<-EOS + ini_setting { "#{parameter_list}": + ensure => present, + path => "#{tmpdir}/ini_setting.ini", + #{parameter_list} + } + EOS + + it_behaves_like 'has_error', "#{tmpdir}/ini_setting.ini", pp, error + end + end + end + + describe 'path parameter' do + [ + "#{tmpdir}/one.ini", + "#{tmpdir}/two.ini", + "#{tmpdir}/three.ini", + ].each do |path| + context "path => #{path}" do + pp = <<-EOS + ini_setting { 'path => #{path}': + ensure => present, + section => 'one', + setting => 'two', + value => 'three', + path => '#{path}', + } + EOS + + it_behaves_like 'has_content', path, pp, /\[one\]\ntwo = three/ + end + end + + context "path => foo" do + pp = <<-EOS + ini_setting { 'path => foo': + ensure => present, + section => 'one', + setting => 'two', + value => 'three', + path => 'foo', + } + EOS + + it_behaves_like 'has_error', 'foo', pp, /must be fully qualified/ + end + end + + describe 'key_val_separator parameter' do + { + "" => /two = three/, + "key_val_separator => '='," => /two=three/, + "key_val_separator => ' = '," => /two = three/, + "key_val_separator => ' '," => /two three/, + "key_val_separator => ' '," => /two three/, + }.each do |parameter, content| + context "with \"#{parameter}\" makes \"#{content}\"" do + pp = <<-EOS + ini_setting { "with #{parameter} makes #{content}": + ensure => present, + section => 'one', + setting => 'two', + value => 'three', + path => "#{tmpdir}/key_val_separator.ini", + #{parameter} + } + EOS + + it_behaves_like 'has_content', "#{tmpdir}/key_val_separator.ini", pp, content + end + end + end +end diff --git a/puppet/modules/inifile/spec/acceptance/ini_subsetting_spec.rb b/puppet/modules/inifile/spec/acceptance/ini_subsetting_spec.rb new file mode 100755 index 0000000..d099a3b --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/ini_subsetting_spec.rb @@ -0,0 +1,200 @@ +require 'spec_helper_acceptance' + +tmpdir = default.tmpdir('tmp') + +describe 'ini_subsetting resource' do + after :all do + shell("rm #{tmpdir}/*.ini", :acceptable_exit_codes => [0, 1, 2]) + end + + shared_examples 'has_content' do |path, pp, content| + before :all do + shell("rm #{path}", :acceptable_exit_codes => [0, 1, 2]) + end + after :all do + shell("cat #{path}", :acceptable_exit_codes => [0, 1, 2]) + shell("rm #{path}", :acceptable_exit_codes => [0, 1, 2]) + end + + it 'applies the manifest twice' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file(path) do + it { should be_file } + its(:content) { + should match content + } + end + end + + shared_examples 'has_error' do |path, pp, error| + before :all do + shell("rm #{path}", :acceptable_exit_codes => [0, 1, 2]) + end + after :all do + shell("cat #{path}", :acceptable_exit_codes => [0, 1, 2]) + shell("rm #{path}", :acceptable_exit_codes => [0, 1, 2]) + end + + it 'applies the manifest and gets a failure message' do + expect(apply_manifest(pp, :expect_failures => true).stderr).to match(error) + end + + describe file(path) do + it { should_not be_file } + end + end + + describe 'ensure, section, setting, subsetting, & value parameters' do + context '=> present with subsections' do + pp = <<-EOS + ini_subsetting { 'ensure => present for alpha': + ensure => present, + path => "#{tmpdir}/ini_subsetting.ini", + section => 'one', + setting => 'key', + subsetting => 'alpha', + value => 'bet', + } + ini_subsetting { 'ensure => present for beta': + ensure => present, + path => "#{tmpdir}/ini_subsetting.ini", + section => 'one', + setting => 'key', + subsetting => 'beta', + value => 'trons', + require => Ini_subsetting['ensure => present for alpha'], + } + EOS + + it 'applies the manifest twice' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{tmpdir}/ini_subsetting.ini") do + it { should be_file } + its(:content) { + should match /\[one\]\nkey = alphabet betatrons/ + } + end + end + + context 'ensure => absent' do + before :all do + if fact('osfamily') == 'Darwin' + shell("echo \"[one]\nkey = alphabet betatrons\" > #{tmpdir}/ini_subsetting.ini") + else + shell("echo -e \"[one]\nkey = alphabet betatrons\" > #{tmpdir}/ini_subsetting.ini") + end + end + + pp = <<-EOS + ini_subsetting { 'ensure => absent for subsetting': + ensure => absent, + path => "#{tmpdir}/ini_subsetting.ini", + section => 'one', + setting => 'key', + subsetting => 'alpha', + } + EOS + + it 'applies the manifest twice' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{tmpdir}/ini_subsetting.ini") do + it { should be_file } + its(:content) { + should match /\[one\]/ + should match /key = betatrons/ + should_not match /alphabet/ + } + end + end + end + + describe 'subsetting_separator' do + { + "" => /two = twinethree foobar/, + "subsetting_separator => ','," => /two = twinethree,foobar/, + "subsetting_separator => ' '," => /two = twinethree foobar/, + "subsetting_separator => ' == '," => /two = twinethree == foobar/, + "subsetting_separator => '='," => /two = twinethree=foobar/, + }.each do |parameter, content| + context "with \"#{parameter}\" makes \"#{content}\"" do + pp = <<-EOS + ini_subsetting { "with #{parameter} makes #{content}": + ensure => present, + section => 'one', + setting => 'two', + subsetting => 'twine', + value => 'three', + path => "#{tmpdir}/subsetting_separator.ini", + before => Ini_subsetting['foobar'], + #{parameter} + } + ini_subsetting { "foobar": + ensure => present, + section => 'one', + setting => 'two', + subsetting => 'foo', + value => 'bar', + path => "#{tmpdir}/subsetting_separator.ini", + #{parameter} + } + EOS + + it_behaves_like 'has_content', "#{tmpdir}/subsetting_separator.ini", pp, content + end + end + end + + describe 'quote_char' do + { + ['-Xmx'] => /args=""/, + ['-Xmx', '256m'] => /args=-Xmx256m/, + ['-Xmx', '512m'] => /args="-Xmx512m"/, + ['-Xms', '256m'] => /args="-Xmx256m -Xms256m"/, + }.each do |parameter, content| + context %Q{with '#{parameter.first}' #{parameter.length > 1 ? '=> \'' << parameter[1] << '\'' : 'absent'} makes '#{content}'} do + path = File.join(tmpdir, 'ini_subsetting.ini') + + before :all do + shell(%Q{echo '[java]\nargs=-Xmx256m' > #{path}}) + end + after :all do + shell("cat #{path}", :acceptable_exit_codes => [0, 1, 2]) + shell("rm #{path}", :acceptable_exit_codes => [0, 1, 2]) + end + + pp = <<-EOS + ini_subsetting { '#{parameter.first}': + ensure => #{parameter.length > 1 ? 'present' : 'absent'}, + path => '#{path}', + section => 'java', + setting => 'args', + quote_char => '"', + subsetting => '#{parameter.first}', + value => '#{parameter.length > 1 ? parameter[1] : ''}' + } + EOS + + it 'applies the manifest twice' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{tmpdir}/ini_subsetting.ini") do + it { should be_file } + its(:content) { + should match content + } + end + end + end + end +end diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/centos-510-x64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/centos-510-x64.yml new file mode 100755 index 0000000..12c9e78 --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/centos-510-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + centos-510-x64: + roles: + - master + platform: el-5-x86_64 + box : centos-510-x64-virtualbox-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-510-x64-virtualbox-nocm.box + hypervisor : vagrant +CONFIG: + type: git diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/centos-59-x64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/centos-59-x64.yml new file mode 100755 index 0000000..2ad90b8 --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/centos-59-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + centos-59-x64: + roles: + - master + platform: el-5-x86_64 + box : centos-59-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: git diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/centos-64-x64-pe.yml b/puppet/modules/inifile/spec/acceptance/nodesets/centos-64-x64-pe.yml new file mode 100755 index 0000000..7d9242f --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/centos-64-x64-pe.yml @@ -0,0 +1,12 @@ +HOSTS: + centos-64-x64: + roles: + - master + - database + - dashboard + platform: el-6-x86_64 + box : centos-64-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: pe diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/centos-64-x64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/centos-64-x64.yml new file mode 100755 index 0000000..0639835 --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/centos-64-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + centos-64-x64: + roles: + - master + platform: el-6-x86_64 + box : centos-64-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: git diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/centos-65-x64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/centos-65-x64.yml new file mode 100755 index 0000000..4e2cb80 --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/centos-65-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + centos-65-x64: + roles: + - master + platform: el-6-x86_64 + box : centos-65-x64-vbox436-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box + hypervisor : vagrant +CONFIG: + type: foss diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/debian-607-x64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/debian-607-x64.yml new file mode 100755 index 0000000..4c8be42 --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/debian-607-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + debian-607-x64: + roles: + - master + platform: debian-6-amd64 + box : debian-607-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-607-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: git diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/debian-73-x64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/debian-73-x64.yml new file mode 100755 index 0000000..3e31a82 --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/debian-73-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + debian-73-x64: + roles: + - master + platform: debian-7-amd64 + box : debian-73-x64-virtualbox-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-nocm.box + hypervisor : vagrant +CONFIG: + type: git diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/default.yml b/puppet/modules/inifile/spec/acceptance/nodesets/default.yml new file mode 100755 index 0000000..0639835 --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/default.yml @@ -0,0 +1,10 @@ +HOSTS: + centos-64-x64: + roles: + - master + platform: el-6-x86_64 + box : centos-64-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: git diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/fedora-18-x64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/fedora-18-x64.yml new file mode 100755 index 0000000..624b537 --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/fedora-18-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + fedora-18-x64: + roles: + - master + platform: fedora-18-x86_64 + box : fedora-18-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/fedora-18-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: git diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/sles-11sp1-x64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/sles-11sp1-x64.yml new file mode 100755 index 0000000..554c37a --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/sles-11sp1-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + sles-11sp1-x64: + roles: + - master + platform: sles-11-x86_64 + box : sles-11sp1-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: git diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml new file mode 100755 index 0000000..5ca1514 --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + ubuntu-server-10044-x64: + roles: + - master + platform: ubuntu-10.04-amd64 + box : ubuntu-server-10044-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: foss diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml new file mode 100755 index 0000000..d065b30 --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + ubuntu-server-12042-x64: + roles: + - master + platform: ubuntu-12.04-amd64 + box : ubuntu-server-12042-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: foss diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml new file mode 100755 index 0000000..cba1cd0 --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml @@ -0,0 +1,11 @@ +HOSTS: + ubuntu-server-1404-x64: + roles: + - master + platform: ubuntu-14.04-amd64 + box : puppetlabs/ubuntu-14.04-64-nocm + box_url : https://vagrantcloud.com/puppetlabs/ubuntu-14.04-64-nocm + hypervisor : vagrant +CONFIG: + log_level : debug + type: git diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/windows-2003-i386.yml b/puppet/modules/inifile/spec/acceptance/nodesets/windows-2003-i386.yml new file mode 100755 index 0000000..eb571ee --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/windows-2003-i386.yml @@ -0,0 +1,24 @@ +HOSTS: + ubuntu1204: + roles: + - master + - database + - dashboard + platform: ubuntu-12.04-amd64 + template: ubuntu-1204-x86_64 + hypervisor: vcloud + win2003_i386: + roles: + - agent + - default + platform: windows-2003-i386 + template: win-2003-i386 + hypervisor: vcloud +CONFIG: + nfs_server: none + consoleport: 443 + datastore: instance0 + folder: Delivery/Quality Assurance/Enterprise/Dynamic + resourcepool: delivery/Quality Assurance/Enterprise/Dynamic + pooling_api: http://vcloud.delivery.puppetlabs.net/ + pe_dir: http://neptune.puppetlabs.lan/3.2/ci-ready/ diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/windows-2003r2-x86_64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/windows-2003r2-x86_64.yml new file mode 100755 index 0000000..e8659a5 --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/windows-2003r2-x86_64.yml @@ -0,0 +1,24 @@ +HOSTS: + ubuntu1204: + roles: + - master + - database + - dashboard + platform: ubuntu-12.04-amd64 + template: ubuntu-1204-x86_64 + hypervisor: vcloud + win2003r2_x86_64: + roles: + - agent + - default + platform: windows-2003r2-x86_64 + template: win-2003r2-x86_64 + hypervisor: vcloud +CONFIG: + nfs_server: none + consoleport: 443 + datastore: instance0 + folder: Delivery/Quality Assurance/Enterprise/Dynamic + resourcepool: delivery/Quality Assurance/Enterprise/Dynamic + pooling_api: http://vcloud.delivery.puppetlabs.net/ + pe_dir: http://neptune.puppetlabs.lan/3.3/ci-ready/ diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/windows-2008-x86_64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/windows-2008-x86_64.yml new file mode 100755 index 0000000..a5ebc4d --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/windows-2008-x86_64.yml @@ -0,0 +1,24 @@ +HOSTS: + ubuntu1204: + roles: + - master + - database + - dashboard + platform: ubuntu-12.04-amd64 + template: ubuntu-1204-x86_64 + hypervisor: vcloud + win2008_x86_64: + roles: + - agent + - default + platform: windows-2008-x86_64 + template: win-2008-x86_64 + hypervisor: vcloud +CONFIG: + nfs_server: none + consoleport: 443 + datastore: instance0 + folder: Delivery/Quality Assurance/Enterprise/Dynamic + resourcepool: delivery/Quality Assurance/Enterprise/Dynamic + pooling_api: http://vcloud.delivery.puppetlabs.net/ + pe_dir: http://neptune.puppetlabs.lan/3.3/ci-ready/ diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/windows-2008r2-x86_64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/windows-2008r2-x86_64.yml new file mode 100755 index 0000000..d2ddba3 --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/windows-2008r2-x86_64.yml @@ -0,0 +1,24 @@ +HOSTS: + ubuntu1204: + roles: + - master + - database + - dashboard + platform: ubuntu-12.04-amd64 + template: ubuntu-1204-x86_64 + hypervisor: vcloud + win2008r2: + roles: + - agent + - default + platform: windows-2008r2-x86_64 + template: win-2008r2-x86_64 + hypervisor: vcloud +CONFIG: + nfs_server: none + consoleport: 443 + datastore: instance0 + folder: Delivery/Quality Assurance/Enterprise/Dynamic + resourcepool: delivery/Quality Assurance/Enterprise/Dynamic + pooling_api: http://vcloud.delivery.puppetlabs.net/ + pe_dir: http://neptune.puppetlabs.lan/3.3/ci-ready/ diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/windows-2012-x86_64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/windows-2012-x86_64.yml new file mode 100755 index 0000000..deea376 --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/windows-2012-x86_64.yml @@ -0,0 +1,24 @@ +HOSTS: + ubuntu1204: + roles: + - master + - database + - dashboard + platform: ubuntu-12.04-amd64 + template: ubuntu-1204-x86_64 + hypervisor: vcloud + win2012: + roles: + - agent + - default + platform: windows-2012-x86_64 + template: win-2012-x86_64 + hypervisor: vcloud +CONFIG: + nfs_server: none + consoleport: 443 + datastore: instance0 + folder: Delivery/Quality Assurance/Enterprise/Dynamic + resourcepool: delivery/Quality Assurance/Enterprise/Dynamic + pooling_api: http://vcloud.delivery.puppetlabs.net/ + pe_dir: http://neptune.puppetlabs.lan/3.3/ci-ready/ diff --git a/puppet/modules/inifile/spec/acceptance/nodesets/windows-2012r2-x86_64.yml b/puppet/modules/inifile/spec/acceptance/nodesets/windows-2012r2-x86_64.yml new file mode 100755 index 0000000..8f9149a --- /dev/null +++ b/puppet/modules/inifile/spec/acceptance/nodesets/windows-2012r2-x86_64.yml @@ -0,0 +1,24 @@ +HOSTS: + ubuntu1204: + roles: + - master + - database + - dashboard + platform: ubuntu-12.04-amd64 + template: ubuntu-1204-x86_64 + hypervisor: vcloud + win2012r2: + roles: + - agent + - default + platform: windows-2012r2-x86_64 + template: win-2012r2-x86_64 + hypervisor: vcloud +CONFIG: + nfs_server: none + consoleport: 443 + datastore: instance0 + folder: Delivery/Quality Assurance/Enterprise/Dynamic + resourcepool: delivery/Quality Assurance/Enterprise/Dynamic + pooling_api: http://vcloud.delivery.puppetlabs.net/ + pe_dir: http://neptune.puppetlabs.lan/3.3/ci-ready/ diff --git a/puppet/modules/inifile/spec/classes/create_ini_settings_test_spec.rb b/puppet/modules/inifile/spec/classes/create_ini_settings_test_spec.rb new file mode 100755 index 0000000..4e6683a --- /dev/null +++ b/puppet/modules/inifile/spec/classes/create_ini_settings_test_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' +# end-to-end test of the create_init_settings function +describe 'create_ini_settings_test' do + it { should have_ini_setting_resource_count(3) } + it { should contain_ini_setting('[section1] setting1').with( + :ensure => 'present', + :section => 'section1', + :setting => 'setting1', + :value => 'val1', + :path => '/tmp/foo.ini' + )} + it { should contain_ini_setting('[section2] setting2').with( + :ensure => 'present', + :section => 'section2', + :setting => 'setting2', + :value => 'val2', + :path => '/tmp/foo.ini' + )} + it { should contain_ini_setting('[section2] setting3').with( + :ensure => 'absent', + :section => 'section2', + :setting => 'setting3', + :path => '/tmp/foo.ini' + )} +end diff --git a/puppet/modules/inifile/spec/classes/inherit_test1_spec.rb b/puppet/modules/inifile/spec/classes/inherit_test1_spec.rb new file mode 100755 index 0000000..51fc0c2 --- /dev/null +++ b/puppet/modules/inifile/spec/classes/inherit_test1_spec.rb @@ -0,0 +1,10 @@ +require 'spec_helper' +# We can't really test much here, apart from the type roundtrips though the +# parser OK. +describe 'inherit_test1' do + it do + should contain_inherit_ini_setting('valid_type').with({ + 'value' => 'true' + }) + end +end diff --git a/puppet/modules/inifile/spec/functions/create_ini_settings_spec.rb b/puppet/modules/inifile/spec/functions/create_ini_settings_spec.rb new file mode 100755 index 0000000..e40fb09 --- /dev/null +++ b/puppet/modules/inifile/spec/functions/create_ini_settings_spec.rb @@ -0,0 +1,23 @@ +#! /usr/bin/env ruby + +require 'spec_helper' +require 'rspec-puppet' + +describe 'create_ini_settings' do + before :each do + Puppet::Parser::Functions.autoloader.loadall + Puppet::Parser::Functions.function(:create_resources) + end + + describe 'argument handling' do + it { should run.with_params.and_raise_error(Puppet::ParseError, /0 for 1 or 2/) } + it { should run.with_params(1,2,3).and_raise_error(Puppet::ParseError, /3 for 1 or 2/) } + it { should run.with_params('foo').and_raise_error(Puppet::ParseError, /Requires all arguments/) } + it { should run.with_params({},'foo').and_raise_error(Puppet::ParseError, /Requires all arguments/) } + + it { should run.with_params({}) } + it { should run.with_params({},{}) } + + it { should run.with_params({ 1 => 2 }).and_raise_error(Puppet::ParseError, /Section 1 must contain a Hash/) } + end +end diff --git a/puppet/modules/inifile/spec/spec.opts b/puppet/modules/inifile/spec/spec.opts new file mode 100755 index 0000000..91cd642 --- /dev/null +++ b/puppet/modules/inifile/spec/spec.opts @@ -0,0 +1,6 @@ +--format +s +--colour +--loadby +mtime +--backtrace diff --git a/puppet/modules/inifile/spec/spec_helper.rb b/puppet/modules/inifile/spec/spec_helper.rb new file mode 100755 index 0000000..7607c33 --- /dev/null +++ b/puppet/modules/inifile/spec/spec_helper.rb @@ -0,0 +1,5 @@ +require 'puppetlabs_spec_helper/module_spec_helper' + +RSpec.configure do |config| + config.mock_with :rspec +end diff --git a/puppet/modules/inifile/spec/spec_helper_acceptance.rb b/puppet/modules/inifile/spec/spec_helper_acceptance.rb new file mode 100755 index 0000000..dd1f1f0 --- /dev/null +++ b/puppet/modules/inifile/spec/spec_helper_acceptance.rb @@ -0,0 +1,23 @@ +require 'beaker-rspec/spec_helper' +require 'beaker-rspec/helpers/serverspec' +require 'beaker/puppet_install_helper' + +run_puppet_install_helper + +RSpec.configure do |c| + # Project root + proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) + + # Readable test descriptions + c.formatter = :documentation + + # Configure all nodes in nodeset + c.before :suite do + # Install module and dependencies + hosts.each do |host| + copy_root_module_to(host, :source => proj_root, :module_name => 'inifile') + end + end + + c.treat_symbols_as_metadata_keys_with_true_values = true +end diff --git a/puppet/modules/inifile/spec/unit/puppet/provider/ini_setting/inheritance_spec.rb b/puppet/modules/inifile/spec/unit/puppet/provider/ini_setting/inheritance_spec.rb new file mode 100755 index 0000000..4dd6c3f --- /dev/null +++ b/puppet/modules/inifile/spec/unit/puppet/provider/ini_setting/inheritance_spec.rb @@ -0,0 +1,67 @@ +require 'spec_helper' + +# This is a reduced version of ruby_spec.rb just to ensure we can subclass as +# documented +$: << 'spec/fixtures/modules/inherit_ini_setting/lib' +provider_class = Puppet::Type.type(:inherit_ini_setting).provider(:ini_setting) +describe provider_class do + include PuppetlabsSpec::Files + + let(:tmpfile) { tmpfilename('inherit_ini_setting_test') } + + def validate_file(expected_content,tmpfile = tmpfile) + File.read(tmpfile).should == expected_content + end + + + before :each do + File.open(tmpfile, 'w') do |fh| + fh.write(orig_content) + end + end + + context 'when calling instances' do + let(:orig_content) { '' } + + it 'should parse nothing when the file is empty' do + provider_class.stubs(:file_path).returns(tmpfile) + provider_class.instances.should == [] + end + + context 'when the file has contents' do + let(:orig_content) { + <<-EOS +# A comment +red = blue +green = purple + EOS + } + + it 'should parse the results' do + provider_class.stubs(:file_path).returns(tmpfile) + instances = provider_class.instances + instances.size.should == 2 + # inherited version of namevar flattens the names + names = instances.map do |instance| + instance.instance_variable_get(:@property_hash)[:name] + end + names.sort.should == [ 'green', 'red' ] + end + end + end + + context 'when ensuring that a setting is present' do + let(:orig_content) { '' } + + it 'should add a value to the file' do + provider_class.stubs(:file_path).returns(tmpfile) + resource = Puppet::Type::Inherit_ini_setting.new({ + :setting => 'set_this', + :value => 'to_that', + }) + provider = described_class.new(resource) + provider.create + validate_file("set_this=to_that\n") + end + end +end diff --git a/puppet/modules/inifile/spec/unit/puppet/provider/ini_setting/ruby_spec.rb b/puppet/modules/inifile/spec/unit/puppet/provider/ini_setting/ruby_spec.rb new file mode 100755 index 0000000..3b6c503 --- /dev/null +++ b/puppet/modules/inifile/spec/unit/puppet/provider/ini_setting/ruby_spec.rb @@ -0,0 +1,1405 @@ +require 'spec_helper' +require 'puppet' + +provider_class = Puppet::Type.type(:ini_setting).provider(:ruby) +describe provider_class do + include PuppetlabsSpec::Files + + let(:tmpfile) { tmpfilename("ini_setting_test") } + let(:emptyfile) { tmpfilename("ini_setting_test_empty") } + + let(:common_params) { { + :title => 'ini_setting_ensure_present_test', + :path => tmpfile, + :section => 'section2', + } } + + def validate_file(expected_content,tmpfile = tmpfile) + File.read(tmpfile).should == expected_content + end + + + before :each do + File.open(tmpfile, 'w') do |fh| + fh.write(orig_content) + end + File.open(emptyfile, 'w') do |fh| + fh.write("") + end + end + + context 'when calling instances' do + + let :orig_content do + '' + end + + it 'should fail when file path is not set' do + expect { + provider_class.instances + }.to raise_error(Puppet::Error, 'Ini_settings only support collecting instances when a file path is hard coded') + end + + context 'when file path is set by a child class' do + it 'should return [] when file is empty' do + child_one = Class.new(provider_class) do + def self.file_path + emptyfile + end + end + child_one.stubs(:file_path).returns(emptyfile) + child_one.instances.should == [] + end + it 'should override the provider instances file_path' do + child_two = Class.new(provider_class) do + def self.file_path + '/some/file/path' + end + end + resource = Puppet::Type::Ini_setting.new(common_params) + provider = child_two.new(resource) + provider.file_path.should == '/some/file/path' + end + context 'when file has contecnts' do + let(:orig_content) { + <<-EOS +# This is a comment +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + EOS + } + + it 'should be able to parse the results' do + child_three = Class.new(provider_class) do + def self.file_path + '/some/file/path' + end + end + child_three.stubs(:file_path).returns(tmpfile) + child_three.instances.size == 7 + expected_array = [ + {:name => 'section1/foo', :value => 'foovalue' }, + {:name => 'section1/bar', :value => 'barvalue' }, + {:name => 'section1/master', :value => 'true' }, + {:name => 'section2/foo', :value => 'foovalue2' }, + {:name => 'section2/baz', :value => 'bazvalue' }, + {:name => 'section2/url', :value => 'http://192.168.1.1:8080' }, + {:name => 'section:sub/subby', :value => 'bar' } + ] + real_array = [] + ensure_array = [] + child_three.instances.each do |x| + prop_hash = x.instance_variable_get(:@property_hash) + ensure_value = prop_hash.delete(:ensure) + ensure_array.push(ensure_value) + real_array.push(prop_hash) + end + ensure_array.uniq.should == [:present] + ((real_array - expected_array) && (expected_array - real_array)).should == [] + + end + + end + + end + + end + + context "when ensuring that a setting is present" do + let(:orig_content) { + <<-EOS +# This is a comment +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + +-nonstandard- + shoes = purple + EOS + } + + it "should add a missing setting to the correct section" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :setting => 'yahoo', :value => 'yippee')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +# This is a comment +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +yahoo = yippee +[section:sub] +subby=bar + #another comment + ; yet another comment + +-nonstandard- + shoes = purple + EOS +) + end + + it "should add a missing setting to the correct section with pre/suffix" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'nonstandard', + :setting => 'yahoo', :value => 'yippee', + :section_prefix => '-', :section_suffix => '-')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +# This is a comment +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + +-nonstandard- + shoes = purple + yahoo = yippee + EOS +) + end + + it "should add a missing setting to the correct section with colon" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'section:sub', :setting => 'yahoo', :value => 'yippee')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +# This is a comment +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + +-nonstandard- + shoes = purple +yahoo = yippee + EOS +) + end + + it "should modify an existing setting with a different value" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :setting => 'baz', :value => 'bazvalue2')) + provider = described_class.new(resource) + provider.exists?.should be true + provider.value=('bazvalue2') + validate_file(<<-EOS +# This is a comment +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue2 +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + +-nonstandard- + shoes = purple + EOS + ) + end + + it "should modify an existing setting with pre/suffix with a different value" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'nonstandard', + :setting => 'shoes', :value => 'orange', + :section_prefix => '-', :section_suffix => '-' )) + provider = described_class.new(resource) + provider.exists?.should be true + provider.value=('orange') + validate_file(<<-EOS +# This is a comment +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + +-nonstandard- + shoes = orange + EOS + ) + end + + it "should modify an existing setting with a different value - with colon in section" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'section:sub', :setting => 'subby', :value => 'foo')) + provider = described_class.new(resource) + provider.exists?.should be true + provider.value.should == 'bar' + provider.value=('foo') + validate_file(<<-EOS +# This is a comment +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=foo + #another comment + ; yet another comment + +-nonstandard- + shoes = purple + EOS + ) + end + + it "should be able to handle settings with non alphanumbering settings " do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :setting => 'url', :value => 'http://192.168.0.1:8080')) + provider = described_class.new(resource) + provider.exists?.should be true + provider.value.should == 'http://192.168.1.1:8080' + provider.value=('http://192.168.0.1:8080') + + validate_file( <<-EOS +# This is a comment +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.0.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + +-nonstandard- + shoes = purple + EOS + ) + end + + it "should be able to handle settings with pre/suffix with non alphanumbering settings " do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'nonstandard', + :setting => 'shoes', :value => 'http://192.168.0.1:8080', + :section_prefix => '-', :section_suffix => '-' )) + provider = described_class.new(resource) + provider.exists?.should be true + provider.value.should == 'purple' + provider.value=('http://192.168.0.1:8080') + + validate_file( <<-EOS +# This is a comment +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + +-nonstandard- + shoes = http://192.168.0.1:8080 + EOS + ) + end + + it "should recognize an existing setting with the specified value" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :setting => 'baz', :value => 'bazvalue')) + provider = described_class.new(resource) + provider.exists?.should be true + end + + it "should recognize an existing setting with pre/suffix with the specified value" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'nonstandard', + :setting => 'shoes', :value => 'purple', + :section_prefix => '-', :section_suffix => '-' )) + provider = described_class.new(resource) + provider.exists?.should be true + end + + it "should add a new section if the section does not exist" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => "section3", :setting => 'huzzah', :value => 'shazaam')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +# This is a comment +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + +-nonstandard- + shoes = purple + +[section3] +huzzah = shazaam + EOS + ) + end + + it "should add a new section with pre/suffix if the section does not exist" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => "section3", :setting => 'huzzah', :value => 'shazaam', + :section_prefix => '-', :section_suffix => '-' )) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +# This is a comment +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + +-nonstandard- + shoes = purple + +-section3- +huzzah = shazaam + EOS + ) + end + + it "should add a new section if the section does not exist - with colon" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => "section:subsection", :setting => 'huzzah', :value => 'shazaam')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +# This is a comment +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + +-nonstandard- + shoes = purple + +[section:subsection] +huzzah = shazaam + EOS + ) + end + + it "should add a new section with pre/suffix if the section does not exist - with colon" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => "section:subsection", :setting => 'huzzah', :value => 'shazaam', + :section_prefix => '-', :section_suffix => '-' )) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +# This is a comment +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + +-nonstandard- + shoes = purple + +-section:subsection- +huzzah = shazaam + EOS + ) + end + + it "should add a new section if no sections exists" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => "section1", :setting => 'setting1', :value => 'hellowworld', :path => emptyfile)) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(" +[section1] +setting1 = hellowworld +", emptyfile) + end + + it "should add a new section with pre/suffix if no sections exists" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => "section1", :setting => 'setting1', :value => 'hellowworld', :path => emptyfile, + :section_prefix => '-', :section_suffix => '-' )) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(" +-section1- +setting1 = hellowworld +", emptyfile) + end + + it "should add a new section with colon if no sections exists" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => "section:subsection", :setting => 'setting1', :value => 'hellowworld', :path => emptyfile)) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(" +[section:subsection] +setting1 = hellowworld +", emptyfile) + end + + it "should add a new section with pre/suffix with colon if no sections exists" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => "section:subsection", :setting => 'setting1', :value => 'hellowworld', :path => emptyfile, + :section_prefix => '-', :section_suffix => '-' )) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(" +-section:subsection- +setting1 = hellowworld +", emptyfile) + end + it "should be able to handle variables of any type" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => "section1", :setting => 'master', :value => true)) + provider = described_class.new(resource) + provider.exists?.should be true + provider.value.should == 'true' + end + + end + + context "when dealing with a global section" do + let(:orig_content) { + <<-EOS +# This is a comment +foo=blah +[section2] +foo = http://192.168.1.1:8080 + ; yet another comment + EOS + } + + + it "should add a missing setting if it doesn't exist" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => '', :setting => 'bar', :value => 'yippee')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +# This is a comment +foo=blah +bar = yippee +[section2] +foo = http://192.168.1.1:8080 + ; yet another comment + EOS + ) + end + + it "should modify an existing setting with a different value" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => '', :setting => 'foo', :value => 'yippee')) + provider = described_class.new(resource) + provider.exists?.should be true + provider.value.should == 'blah' + provider.value=('yippee') + validate_file(<<-EOS +# This is a comment +foo=yippee +[section2] +foo = http://192.168.1.1:8080 + ; yet another comment + EOS + ) + end + + it "should recognize an existing setting with the specified value" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => '', :setting => 'foo', :value => 'blah')) + provider = described_class.new(resource) + provider.exists?.should be true + end + end + + context "when the first line of the file is a section" do + let(:orig_content) { + <<-EOS +[section2] +foo = http://192.168.1.1:8080 + EOS + } + + it "should be able to add a global setting" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => '', :setting => 'foo', :value => 'yippee')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +foo = yippee + +[section2] +foo = http://192.168.1.1:8080 + EOS + ) + end + + it "should modify an existing setting" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'section2', :setting => 'foo', :value => 'yippee')) + provider = described_class.new(resource) + provider.exists?.should be true + provider.value.should == 'http://192.168.1.1:8080' + provider.value=('yippee') + validate_file(<<-EOS +[section2] +foo = yippee + EOS + ) + end + + it "should add a new setting" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'section2', :setting => 'bar', :value => 'baz')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +[section2] +foo = http://192.168.1.1:8080 +bar = baz + EOS + ) + end + end + + context "when overriding the separator" do + let(:orig_content) { + <<-EOS +[section2] +foo=bar + EOS + } + + it "should modify an existing setting" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'section2', + :setting => 'foo', + :value => 'yippee', + :key_val_separator => '=')) + provider = described_class.new(resource) + provider.exists?.should be true + provider.value.should == 'bar' + provider.value=('yippee') + validate_file(<<-EOS +[section2] +foo=yippee + EOS + ) + end + + end + + context "when overriding the separator to something other than =" do + let(:orig_content) { + <<-EOS +[section2] +foo: bar + EOS + } + + it "should modify an existing setting" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'section2', + :setting => 'foo', + :value => 'yippee', + :key_val_separator => ': ')) + provider = described_class.new(resource) + provider.exists?.should be true + provider.value.should == 'bar' + provider.value=('yippee') + validate_file(<<-EOS +[section2] +foo: yippee + EOS + ) + end + + it "should add a new setting" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'section2', + :setting => 'bar', + :value => 'baz', + :key_val_separator => ': ')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +[section2] +foo: bar +bar: baz + EOS + ) + end + + end + + context "when overriding the separator to a space" do + let(:orig_content) { + <<-EOS +[section2] +foo bar + EOS + } + + it "should modify an existing setting" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'section2', + :setting => 'foo', + :value => 'yippee', + :key_val_separator => ' ')) + provider = described_class.new(resource) + provider.exists?.should be true + provider.value.should == 'bar' + provider.value=('yippee') + validate_file(<<-EOS +[section2] +foo yippee + EOS + ) + end + + it "should add a new setting" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'section2', + :setting => 'bar', + :value => 'baz', + :key_val_separator => ' ')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +[section2] +foo bar +bar baz + EOS + ) + end + end + + context "when ensuring that a setting is absent" do + let(:orig_content) { + <<-EOS +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + + -nonstandard- + shoes = purple +EOS + } + + it "should remove a setting that exists" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'section1', :setting => 'foo', :ensure => 'absent')) + provider = described_class.new(resource) + provider.exists?.should be true + provider.destroy + validate_file(<<-EOS +[section1] +; This is also a comment + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + + -nonstandard- + shoes = purple +EOS + ) + end + + it "should remove a setting with pre/suffix that exists" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'nonstandard', :setting => 'shoes', :ensure => 'absent', + :section_prefix => '-', :section_suffix => '-' )) + provider = described_class.new(resource) + provider.exists?.should be true + provider.destroy + validate_file(<<-EOS +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + + -nonstandard- +EOS + ) + end + + it "should do nothing for a setting that does not exist" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'section:sub', :setting => 'foo', :ensure => 'absent')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.destroy + validate_file(<<-EOS +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + + -nonstandard- + shoes = purple + EOS + ) + end + + it "should do nothing for a setting with pre/suffix that does not exist" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'nonstandard', :setting => 'foo', :ensure => 'absent', + :section_prefix => '-', :section_suffix => '-' )) + provider = described_class.new(resource) + provider.exists?.should be false + provider.destroy + validate_file(<<-EOS +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section2] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + + -nonstandard- + shoes = purple + EOS + ) + end + end + + context "when dealing with indentation in sections" do + let(:orig_content) { + <<-EOS +# This is a comment + [section1] + ; This is also a comment + foo=foovalue + + bar = barvalue + master = true + +[section2] + foo= foovalue2 + baz=bazvalue + url = http://192.168.1.1:8080 +[section:sub] + subby=bar + #another comment + fleezy = flam + ; yet another comment + EOS + } + + it "should add a missing setting at the correct indentation when the header is aligned" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'section1', :setting => 'yahoo', :value => 'yippee')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +# This is a comment + [section1] + ; This is also a comment + foo=foovalue + + bar = barvalue + master = true + yahoo = yippee + +[section2] + foo= foovalue2 + baz=bazvalue + url = http://192.168.1.1:8080 +[section:sub] + subby=bar + #another comment + fleezy = flam + ; yet another comment + EOS + ) + end + + it "should update an existing setting at the correct indentation when the header is aligned" do + resource = Puppet::Type::Ini_setting.new( + common_params.merge(:section => 'section1', :setting => 'bar', :value => 'barvalue2')) + provider = described_class.new(resource) + provider.exists?.should be true + provider.create + validate_file(<<-EOS +# This is a comment + [section1] + ; This is also a comment + foo=foovalue + + bar = barvalue2 + master = true + +[section2] + foo= foovalue2 + baz=bazvalue + url = http://192.168.1.1:8080 +[section:sub] + subby=bar + #another comment + fleezy = flam + ; yet another comment + EOS + ) + end + + it "should add a missing setting at the correct indentation when the header is not aligned" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'section2', :setting => 'yahoo', :value => 'yippee')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +# This is a comment + [section1] + ; This is also a comment + foo=foovalue + + bar = barvalue + master = true + +[section2] + foo= foovalue2 + baz=bazvalue + url = http://192.168.1.1:8080 + yahoo = yippee +[section:sub] + subby=bar + #another comment + fleezy = flam + ; yet another comment + EOS + ) + end + + it "should update an existing setting at the correct indentation when the header is not aligned" do + resource = Puppet::Type::Ini_setting.new( + common_params.merge(:section => 'section2', :setting => 'baz', :value => 'bazvalue2')) + provider = described_class.new(resource) + provider.exists?.should be true + provider.create + validate_file(<<-EOS +# This is a comment + [section1] + ; This is also a comment + foo=foovalue + + bar = barvalue + master = true + +[section2] + foo= foovalue2 + baz=bazvalue2 + url = http://192.168.1.1:8080 +[section:sub] + subby=bar + #another comment + fleezy = flam + ; yet another comment + EOS + ) + end + + it "should add a missing setting at the min indentation when the section is not aligned" do + resource = Puppet::Type::Ini_setting.new( + common_params.merge(:section => 'section:sub', :setting => 'yahoo', :value => 'yippee')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +# This is a comment + [section1] + ; This is also a comment + foo=foovalue + + bar = barvalue + master = true + +[section2] + foo= foovalue2 + baz=bazvalue + url = http://192.168.1.1:8080 +[section:sub] + subby=bar + #another comment + fleezy = flam + ; yet another comment + yahoo = yippee + EOS + ) + end + + it "should update an existing setting at the previous indentation when the section is not aligned" do + resource = Puppet::Type::Ini_setting.new( + common_params.merge(:section => 'section:sub', :setting => 'fleezy', :value => 'flam2')) + provider = described_class.new(resource) + provider.exists?.should be true + provider.create + validate_file(<<-EOS +# This is a comment + [section1] + ; This is also a comment + foo=foovalue + + bar = barvalue + master = true + +[section2] + foo= foovalue2 + baz=bazvalue + url = http://192.168.1.1:8080 +[section:sub] + subby=bar + #another comment + fleezy = flam2 + ; yet another comment + EOS + ) + end + + end + + + context "when dealing settings that have a commented version present" do + let(:orig_content) { + <<-EOS + [section1] + # foo=foovalue + bar=barvalue + foo = foovalue2 + +[section2] +# foo = foovalue +;bar=barvalue +blah = blah +#baz= + EOS + } + + it "should add a new setting below a commented version of that setting" do + resource = Puppet::Type::Ini_setting.new( + common_params.merge(:section => 'section2', :setting => 'foo', :value => 'foo3')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS + [section1] + # foo=foovalue + bar=barvalue + foo = foovalue2 + +[section2] +# foo = foovalue +foo = foo3 +;bar=barvalue +blah = blah +#baz= + EOS + ) + end + + it "should update an existing setting in place, even if there is a commented version of that setting" do + resource = Puppet::Type::Ini_setting.new( + common_params.merge(:section => 'section1', :setting => 'foo', :value => 'foo3')) + provider = described_class.new(resource) + provider.exists?.should be true + provider.create + validate_file(<<-EOS + [section1] + # foo=foovalue + bar=barvalue + foo = foo3 + +[section2] +# foo = foovalue +;bar=barvalue +blah = blah +#baz= + EOS + ) + end + + it "should add a new setting below a commented version of that setting, respecting semicolons as comments" do + resource = Puppet::Type::Ini_setting.new( + common_params.merge(:section => 'section2', :setting => 'bar', :value => 'bar3')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS + [section1] + # foo=foovalue + bar=barvalue + foo = foovalue2 + +[section2] +# foo = foovalue +;bar=barvalue +bar=bar3 +blah = blah +#baz= + EOS + ) + end + + it "should add a new setting below an empty commented version of that setting" do + resource = Puppet::Type::Ini_setting.new( + common_params.merge(:section => 'section2', :setting => 'baz', :value => 'bazvalue')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS + [section1] + # foo=foovalue + bar=barvalue + foo = foovalue2 + +[section2] +# foo = foovalue +;bar=barvalue +blah = blah +#baz= +baz=bazvalue + EOS + ) + end + + context 'when a section only contains comments' do + let(:orig_content) { + <<-EOS +[section1] +# foo=foovalue +# bar=bar2 +EOS + } + it 'should be able to add a new setting when a section contains only comments' do + resource = Puppet::Type::Ini_setting.new( + common_params.merge(:section => 'section1', :setting => 'foo', :value => 'foovalue2') + ) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +[section1] +# foo=foovalue +foo=foovalue2 +# bar=bar2 + EOS + ) + end + it 'should be able to add a new setting when it matches a commented out line other than the first one' do + resource = Puppet::Type::Ini_setting.new( + common_params.merge(:section => 'section1', :setting => 'bar', :value => 'barvalue2') + ) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +[section1] +# foo=foovalue +# bar=bar2 +bar=barvalue2 + EOS + ) + end + end + + context "when sections have spaces and dashes" do + let(:orig_content) { + <<-EOS +# This is a comment +[section - one] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section - two] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +[section:sub] +subby=bar + #another comment + ; yet another comment + EOS + } + + it "should add a missing setting to the correct section" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'section - two', :setting => 'yahoo', :value => 'yippee')) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +# This is a comment +[section - one] +; This is also a comment +foo=foovalue + +bar = barvalue +master = true +[section - two] + +foo= foovalue2 +baz=bazvalue +url = http://192.168.1.1:8080 +yahoo = yippee +[section:sub] +subby=bar + #another comment + ; yet another comment + EOS + ) + end + + end + + end + + context "when sections have spaces and quotations" do + let(:orig_content) do + <<-EOS +[branch "master"] + remote = origin + merge = refs/heads/master + +[alias] +to-deploy = log --merges --grep='pull request' --format='%s (%cN)' origin/production..origin/master +[branch "production"] + remote = origin + merge = refs/heads/production + EOS + end + + it "should add a missing setting to the correct section" do + resource = Puppet::Type::Ini_setting.new(common_params.merge( + :section => 'alias', + :setting => 'foo', + :value => 'bar' + )) + provider = described_class.new(resource) + provider.exists?.should be false + provider.create + validate_file(<<-EOS +[branch "master"] + remote = origin + merge = refs/heads/master + +[alias] +to-deploy = log --merges --grep='pull request' --format='%s (%cN)' origin/production..origin/master +foo = bar +[branch "production"] + remote = origin + merge = refs/heads/production + EOS + ) + end + + end + +end diff --git a/puppet/modules/inifile/spec/unit/puppet/provider/ini_subsetting/ruby_spec.rb b/puppet/modules/inifile/spec/unit/puppet/provider/ini_subsetting/ruby_spec.rb new file mode 100755 index 0000000..ca9b07a --- /dev/null +++ b/puppet/modules/inifile/spec/unit/puppet/provider/ini_subsetting/ruby_spec.rb @@ -0,0 +1,181 @@ +require 'spec_helper' +require 'puppet' + +provider_class = Puppet::Type.type(:ini_subsetting).provider(:ruby) +describe provider_class do + include PuppetlabsSpec::Files + + let(:tmpfile) { tmpfilename("ini_setting_test") } + + def validate_file(expected_content,tmpfile = tmpfile) + File.read(tmpfile).should == expected_content + end + + + before :each do + File.open(tmpfile, 'w') do |fh| + fh.write(orig_content) + end + end + + context "when ensuring that a subsetting is present" do + let(:common_params) { { + :title => 'ini_setting_ensure_present_test', + :path => tmpfile, + :section => '', + :key_val_separator => '=', + :setting => 'JAVA_ARGS', + } } + + let(:orig_content) { + <<-EOS +JAVA_ARGS="-Xmx192m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof" + EOS + } + + it "should add a missing subsetting" do + resource = Puppet::Type::Ini_subsetting.new(common_params.merge( + :subsetting => '-Xms', :value => '128m')) + provider = described_class.new(resource) + provider.exists?.should be_nil + provider.create + validate_file(<<-EOS +JAVA_ARGS="-Xmx192m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof -Xms128m" + EOS +) + end + + it "should remove an existing subsetting" do + resource = Puppet::Type::Ini_subsetting.new(common_params.merge( + :subsetting => '-Xmx')) + provider = described_class.new(resource) + provider.exists?.should == "192m" + provider.destroy + validate_file(<<-EOS +JAVA_ARGS="-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof" + EOS +) + end + + it "should modify an existing subsetting" do + resource = Puppet::Type::Ini_subsetting.new(common_params.merge( + :subsetting => '-Xmx', :value => '256m')) + provider = described_class.new(resource) + provider.exists?.should == "192m" + provider.value=('256m') + validate_file(<<-EOS +JAVA_ARGS="-Xmx256m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof" + EOS +) + end + end + + context "when working with subsettings in files with unquoted settings values" do + let(:common_params) { { + :title => 'ini_setting_ensure_present_test', + :path => tmpfile, + :section => 'master', + :setting => 'reports', + } } + + let(:orig_content) { + <<-EOS +[master] + +reports = http,foo + EOS + } + + it "should remove an existing subsetting" do + resource = Puppet::Type::Ini_subsetting.new(common_params.merge( + :subsetting => 'http', :subsetting_separator => ',')) + provider = described_class.new(resource) + provider.exists?.should == "" + provider.destroy + validate_file(<<-EOS +[master] + +reports = foo + EOS + ) + end + + it "should add a new subsetting when the 'parent' setting already exists" do + resource = Puppet::Type::Ini_subsetting.new(common_params.merge( + :subsetting => 'puppetdb', :subsetting_separator => ',')) + provider = described_class.new(resource) + provider.exists?.should be_nil + provider.value=('') + validate_file(<<-EOS +[master] + +reports = http,foo,puppetdb + EOS + ) + end + + it "should add a new subsetting when the 'parent' setting does not already exist" do + resource = Puppet::Type::Ini_subsetting.new(common_params.merge( + :setting => 'somenewsetting', + :subsetting => 'puppetdb', + :subsetting_separator => ',')) + provider = described_class.new(resource) + provider.exists?.should be_nil + provider.value=('') + validate_file(<<-EOS +[master] + +reports = http,foo +somenewsetting = puppetdb + EOS + ) + end + + end + + context "when working with subsettings in files with use_exact_match" do + let(:common_params) { { + :title => 'ini_setting_ensure_present_test', + :path => tmpfile, + :section => 'master', + :setting => 'reports', + :use_exact_match => true, + } } + + let(:orig_content) { + <<-EOS +[master] + +reports = http,foo + EOS + } + + it "should add a new subsetting when the 'parent' setting already exists" do + resource = Puppet::Type::Ini_subsetting.new(common_params.merge( + :subsetting => 'fo', :subsetting_separator => ',')) + provider = described_class.new(resource) + provider.value=('') + validate_file(<<-eos +[master] + +reports = http,foo,fo + eos + ) + end + + it "should not remove substring subsettings" do + resource = Puppet::Type::Ini_subsetting.new(common_params.merge( + :subsetting => 'fo', :subsetting_separator => ',')) + provider = described_class.new(resource) + provider.value=('') + provider.destroy + validate_file(<<-EOS +[master] + +reports = http,foo + EOS + ) + end + end + +end diff --git a/puppet/modules/inifile/spec/unit/puppet/util/external_iterator_spec.rb b/puppet/modules/inifile/spec/unit/puppet/util/external_iterator_spec.rb new file mode 100755 index 0000000..92b17af --- /dev/null +++ b/puppet/modules/inifile/spec/unit/puppet/util/external_iterator_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' +require 'puppet/util/external_iterator' + +describe Puppet::Util::ExternalIterator do + let(:subject) { Puppet::Util::ExternalIterator.new(["a", "b", "c"]) } + + context "#next" do + it "should iterate over the items" do + subject.next.should == ["a", 0] + subject.next.should == ["b", 1] + subject.next.should == ["c", 2] + end + end + + context "#peek" do + it "should return the 0th item repeatedly" do + subject.peek.should == ["a", 0] + subject.peek.should == ["a", 0] + end + + it "should not advance the iterator, but should reflect calls to #next" do + subject.peek.should == ["a", 0] + subject.peek.should == ["a", 0] + subject.next.should == ["a", 0] + subject.peek.should == ["b", 1] + subject.next.should == ["b", 1] + subject.peek.should == ["c", 2] + subject.next.should == ["c", 2] + subject.peek.should == [nil, nil] + subject.next.should == [nil, nil] + end + end + + +end diff --git a/puppet/modules/inifile/spec/unit/puppet/util/ini_file_spec.rb b/puppet/modules/inifile/spec/unit/puppet/util/ini_file_spec.rb new file mode 100755 index 0000000..7a92090 --- /dev/null +++ b/puppet/modules/inifile/spec/unit/puppet/util/ini_file_spec.rb @@ -0,0 +1,287 @@ +require 'spec_helper' +require 'stringio' +require 'puppet/util/ini_file' + +describe Puppet::Util::IniFile do + let(:subject) { Puppet::Util::IniFile.new("/my/ini/file/path") } + + before :each do + File.should_receive(:file?).with("/my/ini/file/path") { true } + described_class.should_receive(:readlines).once.with("/my/ini/file/path") do + sample_content + end + end + + context "when parsing a file" do + let(:sample_content) { + template = <<-EOS +# This is a comment +[section1] +; This is also a comment +foo=foovalue + +bar = barvalue +baz = +[section2] + +foo= foovalue2 +baz=bazvalue + ; commented = out setting + #another comment + ; yet another comment + zot = multi word value + xyzzy['thing1']['thing2']=xyzzyvalue + l=git log + EOS + template.split("\n") + } + + it "should parse the correct number of sections" do + # there is always a "global" section, so our count should be 3. + subject.section_names.length.should == 3 + end + + it "should parse the correct section_names" do + # there should always be a "global" section named "" at the beginning of the list + subject.section_names.should == ["", "section1", "section2"] + end + + it "should expose settings for sections" do + subject.get_settings("section1").should == { + "bar" => "barvalue", + "baz" => "", + "foo" => "foovalue" + } + + subject.get_settings("section2").should == { + "baz" => "bazvalue", + "foo" => "foovalue2", + "l" => "git log", + "xyzzy['thing1']['thing2']" => "xyzzyvalue", + "zot" => "multi word value" + } + end + + end + + context "when parsing a file whose first line is a section" do + let(:sample_content) { + template = <<-EOS +[section1] +; This is a comment +foo=foovalue + EOS + template.split("\n") + } + + it "should parse the correct number of sections" do + # there is always a "global" section, so our count should be 2. + subject.section_names.length.should == 2 + end + + it "should parse the correct section_names" do + # there should always be a "global" section named "" at the beginning of the list + subject.section_names.should == ["", "section1"] + end + + it "should expose settings for sections" do + subject.get_value("section1", "foo").should == "foovalue" + end + + end + + context "when parsing a file with a 'global' section" do + let(:sample_content) { + template = <<-EOS +foo = bar +[section1] +; This is a comment +foo=foovalue + EOS + template.split("\n") + } + + it "should parse the correct number of sections" do + # there is always a "global" section, so our count should be 2. + subject.section_names.length.should == 2 + end + + it "should parse the correct section_names" do + # there should always be a "global" section named "" at the beginning of the list + subject.section_names.should == ["", "section1"] + end + + it "should expose settings for sections" do + subject.get_value("", "foo").should == "bar" + subject.get_value("section1", "foo").should == "foovalue" + end + end + + context "when updating a file with existing empty values" do + let(:sample_content) { + template = <<-EOS +[section1] +foo= +#bar= +#xyzzy['thing1']['thing2']='xyzzyvalue' + EOS + template.split("\n") + } + + it "should properly update uncommented values" do + subject.get_value("section1", "far").should == nil + subject.set_value("section1", "foo", "foovalue") + subject.get_value("section1", "foo").should == "foovalue" + end + + it "should properly update commented values" do + subject.get_value("section1", "bar").should == nil + subject.set_value("section1", "bar", "barvalue") + subject.get_value("section1", "bar").should == "barvalue" + subject.get_value("section1", "xyzzy['thing1']['thing2']").should == nil + subject.set_value("section1", "xyzzy['thing1']['thing2']", "xyzzyvalue") + subject.get_value("section1", "xyzzy['thing1']['thing2']").should == "xyzzyvalue" + end + + it "should properly add new empty values" do + subject.get_value("section1", "baz").should == nil + subject.set_value("section1", "baz", "bazvalue") + subject.get_value("section1", "baz").should == "bazvalue" + end + end + + context 'the file has quotation marks in its section names' do + let(:sample_content) do + template = <<-EOS +[branch "master"] + remote = origin + merge = refs/heads/master + +[alias] +to-deploy = log --merges --grep='pull request' --format='%s (%cN)' origin/production..origin/master +[branch "production"] + remote = origin + merge = refs/heads/production + EOS + template.split("\n") + end + + it 'should parse the sections' do + subject.section_names.should match_array ['', + 'branch "master"', + 'alias', + 'branch "production"' + ] + end + end + + context 'Samba INI file with dollars in section names' do + let(:sample_content) do + template = <<-EOS + [global] + workgroup = FELLOWSHIP + ; ... + idmap config * : backend = tdb + + [printers] + comment = All Printers + ; ... + browseable = No + + [print$] + comment = Printer Drivers + path = /var/lib/samba/printers + + [Shares] + path = /home/shares + read only = No + guest ok = Yes + EOS + template.split("\n") + end + + it "should parse the correct section_names" do + subject.section_names.should match_array [ + '', + 'global', + 'printers', + 'print$', + 'Shares' + ] + end + end + + context 'section names with forward slashes in them' do + let(:sample_content) do + template = <<-EOS +[monitor:///var/log/*.log] +disabled = test_value + EOS + template.split("\n") + end + + it "should parse the correct section_names" do + subject.section_names.should match_array [ + '', + 'monitor:///var/log/*.log' + ] + end + end + + context 'KDE Configuration with braces in setting names' do + let(:sample_content) do + template = <<-EOS + [khotkeys] +_k_friendly_name=khotkeys +{5465e8c7-d608-4493-a48f-b99d99fdb508}=Print,none,PrintScreen +{d03619b6-9b3c-48cc-9d9c-a2aadb485550}=Search,none,Search +EOS + template.split("\n") + end + + it "should expose settings for sections" do + subject.get_value("khotkeys", "{5465e8c7-d608-4493-a48f-b99d99fdb508}").should == "Print,none,PrintScreen" + subject.get_value("khotkeys", "{d03619b6-9b3c-48cc-9d9c-a2aadb485550}").should == "Search,none,Search" + end + end + + context 'Configuration with colons in setting names' do + let(:sample_content) do + template = <<-EOS + [Drive names] +A:=5.25" Floppy +B:=3.5" Floppy +C:=Winchester +EOS + template.split("\n") + end + + it "should expose settings for sections" do + subject.get_value("Drive names", "A:").should eq '5.25" Floppy' + subject.get_value("Drive names", "B:").should eq '3.5" Floppy' + subject.get_value("Drive names", "C:").should eq 'Winchester' + end + end + + context 'Configuration with spaces in setting names' do + let(:sample_content) do + template = <<-EOS + [global] + # log files split per-machine: + log file = /var/log/samba/log.%m + + kerberos method = system keytab + passdb backend = tdbsam + security = ads +EOS + template.split("\n") + end + + it "should expose settings for sections" do + subject.get_value("global", "log file").should eq '/var/log/samba/log.%m' + subject.get_value("global", "kerberos method").should eq 'system keytab' + subject.get_value("global", "passdb backend").should eq 'tdbsam' + subject.get_value("global", "security").should eq 'ads' + end + end +end diff --git a/puppet/modules/inifile/spec/unit/puppet/util/setting_value_spec.rb b/puppet/modules/inifile/spec/unit/puppet/util/setting_value_spec.rb new file mode 100755 index 0000000..8514724 --- /dev/null +++ b/puppet/modules/inifile/spec/unit/puppet/util/setting_value_spec.rb @@ -0,0 +1,103 @@ +require 'spec_helper' +require 'puppet/util/setting_value' + +describe Puppet::Util::SettingValue do + + describe "space subsetting separator" do + INIT_VALUE_SPACE = "\"-Xmx192m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof\"" + + before :each do + @setting_value = Puppet::Util::SettingValue.new(INIT_VALUE_SPACE, " ") + end + + it "should get the original value" do + @setting_value.get_value.should == INIT_VALUE_SPACE + end + + it "should get the correct value" do + @setting_value.get_subsetting_value("-Xmx").should == "192m" + end + + it "should add a new value" do + @setting_value.add_subsetting("-Xms", "256m") + @setting_value.get_subsetting_value("-Xms").should == "256m" + @setting_value.get_value.should == INIT_VALUE_SPACE[0, INIT_VALUE_SPACE.length - 1] + " -Xms256m\"" + end + + it "should change existing value" do + @setting_value.add_subsetting("-Xmx", "512m") + @setting_value.get_subsetting_value("-Xmx").should == "512m" + end + + it "should remove existing value" do + @setting_value.remove_subsetting("-Xmx") + @setting_value.get_subsetting_value("-Xmx").should == nil + end + end + + describe "comma subsetting separator" do + INIT_VALUE_COMMA = "\"-Xmx192m,-XX:+HeapDumpOnOutOfMemoryError,-XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof\"" + + before :each do + @setting_value = Puppet::Util::SettingValue.new(INIT_VALUE_COMMA, ",") + end + + it "should get the original value" do + @setting_value.get_value.should == INIT_VALUE_COMMA + end + + it "should get the correct value" do + @setting_value.get_subsetting_value("-Xmx").should == "192m" + end + + it "should add a new value" do + @setting_value.add_subsetting("-Xms", "256m") + @setting_value.get_subsetting_value("-Xms").should == "256m" + @setting_value.get_value.should == INIT_VALUE_COMMA[0, INIT_VALUE_COMMA.length - 1] + ",-Xms256m\"" + end + + it "should change existing value" do + @setting_value.add_subsetting("-Xmx", "512m") + @setting_value.get_subsetting_value("-Xmx").should == "512m" + end + + it "should remove existing value" do + @setting_value.remove_subsetting("-Xmx") + @setting_value.get_subsetting_value("-Xmx").should == nil + end + end + + describe "quote_char parameter" do + QUOTE_CHAR = '"' + INIT_VALUE_UNQUOTED = '-Xmx192m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof' + + it "should get quoted empty string if original value was empty" do + setting_value = Puppet::Util::SettingValue.new(nil, ' ', QUOTE_CHAR) + setting_value.get_value.should == QUOTE_CHAR * 2 + end + + it "should quote the setting when adding a value" do + setting_value = Puppet::Util::SettingValue.new(INIT_VALUE_UNQUOTED, ' ', QUOTE_CHAR) + setting_value.add_subsetting("-Xms", "256m") + + setting_value.get_subsetting_value("-Xms").should == "256m" + setting_value.get_value.should == QUOTE_CHAR + INIT_VALUE_UNQUOTED + ' -Xms256m' + QUOTE_CHAR + end + + it "should quote the setting when changing an existing value" do + setting_value = Puppet::Util::SettingValue.new(INIT_VALUE_UNQUOTED, ' ', QUOTE_CHAR) + setting_value.add_subsetting("-Xmx", "512m") + + setting_value.get_subsetting_value("-Xmx").should == "512m" + setting_value.get_value.should =~ /^#{Regexp.quote(QUOTE_CHAR)}.*#{Regexp.quote(QUOTE_CHAR)}$/ + end + + it "should quote the setting when removing an existing value" do + setting_value = Puppet::Util::SettingValue.new(INIT_VALUE_UNQUOTED, ' ', QUOTE_CHAR) + setting_value.remove_subsetting("-Xmx") + + setting_value.get_subsetting_value("-Xmx").should == nil + setting_value.get_value.should =~ /^#{Regexp.quote(QUOTE_CHAR)}.*#{Regexp.quote(QUOTE_CHAR)}$/ + end + end +end diff --git a/puppet/modules/phpmanager/files/scripts/phpmanager b/puppet/modules/phpmanager/files/scripts/phpmanager index bd76473..47ff587 100755 --- a/puppet/modules/phpmanager/files/scripts/phpmanager +++ b/puppet/modules/phpmanager/files/scripts/phpmanager @@ -2,7 +2,7 @@ ## # Joomlatools PHP Manager script - https://github.com/joomlatools/joomla-vagrant # -# @copyright Copyright (C) 2011 - 2014 Johan Janssens and Timble CVBA. (http://www.timble.net) +# @copyright Copyright (C) 2011 - 2015 Johan Janssens and Timble CVBA. (http://www.timble.net) # @license MPL 2.0 # @link http://github.com/joomlatools/joomla-vagrant for the canonical source repository ## @@ -164,6 +164,18 @@ command_use() { [[ -f "/usr/lib/apache2/modules/${DELNAME}" ]] && sudo rm "/usr/lib/apache2/modules/${DELNAME}" sudo cp "/opt/php/${VERSION}/lib/apache/${LIBNAME}" "/usr/lib/apache2/modules/${LIBNAME}" + # Update the Z-Ray vhost + if [[ "$SHORT" -ge 5500 ]] && [[ "$SHORT" -lt 5600 ]]; then + sudo a2ensite 00-zray-php5.5 &> /dev/null + sudo a2dissite 00-zray-php5.6 &> /dev/null + elif [[ "$SHORT" -ge 5600 ]] && [[ "$SHORT" -lt 7000 ]]; then + sudo a2ensite 00-zray-php5.6 &> /dev/null + sudo a2dissite 00-zray-php5.5 &> /dev/null + else + sudo a2dissite 00-zray-php5.6 &> /dev/null + sudo a2dissite 00-zray-php5.5 &> /dev/null + fi + echo -n "Restarting Apache .. " sudo service apache2 restart &> /dev/null @@ -281,6 +293,9 @@ command_install() { sub_xdebug "$VERSION" "$LOGFILE" fi + # Install z-ray if applicable + sub_zray "$VERSION" + # Build APC or APCu+Opcache if [[ "$SHORT" -lt 7000 ]] ; then if [[ "$SHORT" -lt 5500 ]] ; then @@ -348,6 +363,9 @@ command_restore() { sudo cp "/usr/lib/apache2/modules/libphp5.so.original" "/usr/lib/apache2/modules/libphp5.so" + sudo a2ensite 00-zray-php5.6 &> /dev/null + sudo a2dissite 00-zray-php5.5 &> /dev/null + echo -n "Restarting Apache .. " sudo a2enmod php5 &> /dev/null sudo service apache2 restart &> /dev/null @@ -427,6 +445,17 @@ sub_pear() { done } +# Symlink z-ray ini files +sub_zray() { + VERSION="$1" + + if [[ "$SHORT" -ge 5500 ]] && [[ "$SHORT" -lt 5600 ]]; then + cp /etc/php5/mods-available/zray-php5.5.ini "/opt/php/${VERSION}/etc/conf.d/zray-php5.5.ini" + elif [[ "$SHORT" -ge 5600 ]] && [[ "$SHORT" -lt 7000 ]]; then + cp /etc/php5/mods-available/zray-php5.6.ini "/opt/php/${VERSION}/etc/conf.d/zray-php5.6.ini" + fi +} + # Build Xdebug for the given version sub_xdebug() { VERSION="$1" @@ -456,13 +485,12 @@ sub_xdebug() { if [[ -f "${SOURCE_XDEBUG}/modules/xdebug.so" ]] ; then EXTENSION=$(sub_getextensionnumber $VERSION) LIB="/opt/php/${VERSION}/lib/php/extensions/no-debug-non-zts-${EXTENSION}/xdebug.so" - INI="/opt/php/${VERSION}/etc/conf.d/zzz_xdebug.ini" + INI="/opt/php/${VERSION}/etc/conf.d/xdebug.ini" sudo cp "${SOURCE_XDEBUG}/modules/xdebug.so" "$LIB" # Note: the zend_extension directive requires the FULL path! sudo echo "zend_extension=\"${LIB}\"" > "${INI}" - sudo cat /etc/php5/apache2/conf.d/zzz_xdebug.ini >> "${INI}" else echo -e "\033[31mERROR: Failed to build Xdebug!\e[0m" fi @@ -487,7 +515,7 @@ sub_apc() { if [[ -f "$LIB" ]] ; then echo -e "\033[92mfinished\033[0m" - sudo echo "extension=\"apc.so\"" > "/opt/php/${VERSION}/etc/conf.d/zzz_apc.ini" + sudo echo "extension=\"apc.so\"" > "/opt/php/${VERSION}/etc/conf.d/apc.ini" else echo "\033[31mFailed\e[0m" fi @@ -509,9 +537,9 @@ sub_apcu() { if [[ -f "$LIB" ]] ; then echo -e "\033[92mfinished\033[0m" - sudo echo "extension=\"apcu.so\"" > "/opt/php/${VERSION}/etc/conf.d/zzz_apcu.ini" + sudo echo "extension=\"apcu.so\"" > "/opt/php/${VERSION}/etc/conf.d/apcu.ini" - sudo echo "zend_extension=\"opcache.so\"" > "/opt/php/${VERSION}/etc/conf.d/zzz_opcache.ini" + sudo echo "zend_extension=\"opcache.so\"" > "/opt/php/${VERSION}/etc/conf.d/opcache.ini" else echo "\033[31mFailed\e[0m" fi @@ -573,10 +601,10 @@ sub_getoptions() { OPENSSL="--with-openssl=/opt/openssl-0.9.7g" patch -p1 < /home/vagrant/phpmanager/patches/openssl.ssl2.patch &> /dev/null elif [[ "$SHORT" -le 5306 ]] ; then - OPENSSL="--with-openssl" + OPENSSL="--with-openssl=/opt/openssl-1.0.1f" patch -p1 < /home/vagrant/phpmanager/patches/openssl.ssl2.patch &> /dev/null else - OPENSSL="--with-openssl" + OPENSSL="--with-openssl=/opt/openssl-1.0.1f" fi OPTIONS="$OPTIONS $OPENSSL" @@ -618,7 +646,7 @@ sub_setupini() { sudo cp "${SOURCE}/php.ini-development" "/opt/php/${VERSION}/lib/php.ini" fi - sudo cp /etc/php5/apache2/conf.d/zzz_custom.ini "/opt/php/${VERSION}/etc/conf.d/zzz_custom.ini" + sudo cp /etc/php5/mods-available/custom.ini "/opt/php/${VERSION}/etc/conf.d/99-custom.ini" sudo chown vagrant:vagrant "/opt/php/${VERSION}/lib/php.ini" sudo chown -R vagrant:vagrant "/opt/php/${VERSION}/etc/conf.d" @@ -627,12 +655,12 @@ sub_setupini() { # according to the docs at http://be2.php.net/dl but for most builds this isn't the case. # So let's make sure we properly set the extension_dir directive : EXTENSION=$(sub_getextensionnumber $VERSION) - echo "extension_dir=/opt/php/${VERSION}/lib/php/extensions/no-debug-non-zts-${EXTENSION}/" >> "/opt/php/${VERSION}/etc/conf.d/zzz_custom.ini" + echo "extension_dir=/opt/php/${VERSION}/lib/php/extensions/no-debug-non-zts-${EXTENSION}/" >> "/opt/php/${VERSION}/etc/conf.d/99-custom.ini" # Configure the MySQL socket - echo "mysql.default_socket=/var/run/mysqld/mysqld.sock" > "/opt/php/${VERSION}/etc/conf.d/zzz_mysql.ini" - echo "mysqli.default_socket=/var/run/mysqld/mysqld.sock" >> "/opt/php/${VERSION}/etc/conf.d/zzz_mysql.ini" - echo "pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock" >> "/opt/php/${VERSION}/etc/conf.d/zzz_mysql.ini" + echo "mysql.default_socket=/var/run/mysqld/mysqld.sock" > "/opt/php/${VERSION}/etc/conf.d/mysql.ini" + echo "mysqli.default_socket=/var/run/mysqld/mysqld.sock" >> "/opt/php/${VERSION}/etc/conf.d/mysql.ini" + echo "pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock" >> "/opt/php/${VERSION}/etc/conf.d/mysql.ini" } # Get the available PHP tags diff --git a/puppet/modules/phpmanager/manifests/init.pp b/puppet/modules/phpmanager/manifests/init.pp index 6f005a3..12eb939 100644 --- a/puppet/modules/phpmanager/manifests/init.pp +++ b/puppet/modules/phpmanager/manifests/init.pp @@ -53,8 +53,8 @@ } exec { 'add-phpmanager-to-path': - command => 'echo "export PATH=\$PATH:/home/vagrant/phpmanager" >> /home/vagrant/.profile', - unless => 'grep ":/home/vagrant/phpmanager" /home/vagrant/.profile', + command => 'echo "export PATH=\$PATH:/home/vagrant/phpmanager" >> /home/vagrant/.bash_profile', + unless => 'grep ":/home/vagrant/phpmanager" /home/vagrant/.bash_profile', require => Exec['make-phpmanager-executable'] } @@ -107,7 +107,16 @@ retrieve_args => '--no-check-certificate', extracted_dir => 'openssl-0.9.7g', destination_dir => $phpmanager::source_path, - postextract_command => "${phpmanager::source_path}/openssl-0.9.7g/config --prefix=${phpmanager::installation_path}/openssl-0.9.7g -fPIC no-gost && make && sudo make install && ln -s /opt/openssl-0.9.7g/lib /opt/openssl-0.9.7g/lib/x86_64-linux-gnu", + postextract_command => "${phpmanager::source_path}/openssl-0.9.7g/config --prefix=${phpmanager::installation_path}/openssl-0.9.7g -fPIC no-gost && make && make install && ln -s /opt/openssl-0.9.7g/lib /opt/openssl-0.9.7g/lib/x86_64-linux-gnu", + require => Package['build-essential'] + } + + puppi::netinstall { 'openssl-1.0.1f': + url => 'ftp://ftp.openssl.org/source/old/1.0.1/openssl-1.0.1f.tar.gz', + retrieve_args => '--no-check-certificate', + extracted_dir => 'openssl-1.0.1f', + destination_dir => $phpmanager::source_path, + postextract_command => "${phpmanager::source_path}/openssl-1.0.1f/config --prefix=${phpmanager::installation_path}/openssl-1.0.1f -fPIC no-gost && make && make depend && make install_sw && ln -s /opt/openssl-1.0.1f/lib /opt/openssl-1.0.1f/lib/x86_64-linux-gnu", require => Package['build-essential'] } diff --git a/puppet/modules/phpmetrics/manifests/init.pp b/puppet/modules/phpmetrics/manifests/init.pp index 8846572..fa0b799 100644 --- a/puppet/modules/phpmetrics/manifests/init.pp +++ b/puppet/modules/phpmetrics/manifests/init.pp @@ -15,8 +15,8 @@ } exec { 'add-phpmetrics-to-path': - command => 'echo "export PATH=\$PATH:/usr/share/phpmetrics/vendor/bin" >> /home/vagrant/.profile', - unless => 'grep ":/usr/share/phpmetrics/vendor/bin" /home/vagrant/.profile', + command => 'echo "export PATH=\$PATH:/usr/share/phpmetrics/vendor/bin" >> /home/vagrant/.bash_profile', + unless => 'grep ":/usr/share/phpmetrics/vendor/bin" /home/vagrant/.bash_profile', user => vagrant, require => Exec['install-phpmetrics'] } diff --git a/puppet/modules/scripts/files/scripts/apc-dashboard.php b/puppet/modules/scripts/files/scripts/apc-dashboard.php index ca1277f..89ad4d0 100644 --- a/puppet/modules/scripts/files/scripts/apc-dashboard.php +++ b/puppet/modules/scripts/files/scripts/apc-dashboard.php @@ -1,5 +1,5 @@
  • phpMyAdmin
  • -
  • MailCatcher
  • +
  • MailCatcher
  • APC dashboard
  • + +
  • Z-Ray
  • + + +
  • Webgrind
  • +
    diff --git a/puppet/modules/scripts/files/scripts/updater/login.sh b/puppet/modules/scripts/files/scripts/updater/login.sh new file mode 100755 index 0000000..2c5a25a --- /dev/null +++ b/puppet/modules/scripts/files/scripts/updater/login.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +nohup /usr/bin/php5 /home/vagrant/scripts/updater/updater.php >/dev/null 2>&1 & + +if [ -f /home/vagrant/scripts/updater/UPDATE_AVAILABLE ]; then + VERSION=`cat /home/vagrant/scripts/updater/UPDATE_AVAILABLE` + echo "" + echo "New release $VERSION available for joomla-console." + + read -r -p "${1:-Do you want to update now? [y/N]} " response + case $response in + [yY][eE][sS]|[yY]) + sudo composer self-update + composer global require joomlatools/joomla-console:$VERSION + rm -f /home/vagrant/scripts/updater/UPDATE_AVAILABLE + ;; + *) + exit + ;; + esac +fi + diff --git a/puppet/modules/scripts/files/scripts/updater/updater.php b/puppet/modules/scripts/files/scripts/updater/updater.php new file mode 100644 index 0000000..845611d --- /dev/null +++ b/puppet/modules/scripts/files/scripts/updater/updater.php @@ -0,0 +1,76 @@ +#!/usr/bin/php5 +&1", $result, $code); + +if ($code === 1) { + exit(1); // Failed to fetch info from packagist +} + +$versions = array(); +foreach ($result as $line => $content) +{ + $content = trim($content); + + if (strpos($content, 'versions') === 0) + { + $parts = explode(':', $content); + + if (count($parts) > 1) + { + $versions = explode(', ', $parts[1]); + break; + } + } +} + +$versions = array_map('trim', $versions); +array_filter($versions); + +if (!count($versions)) { + exit(1); // No available versions found! +} + +$manifest = json_decode(file_get_contents('/home/vagrant/.composer/composer.lock')); +if (!$manifest) { + exit(1); // No composer.lock file? +} + +$currentVersion = false; +foreach ($manifest->packages as $package) +{ + if ($package->name == 'joomlatools/joomla-console') + { + if (substr($package->version, 0, 1) != 'v') { + return; // Only update stable releases + } + + $currentVersion = substr($package->version, 1); + + break; + } +} + +if (!$currentVersion) { + exit(1); // Could not find current version +} + +$latest = '0.1'; +foreach ($versions as $version) +{ + if (preg_match('/^v[0-9]+\.[0-9]+\.[0-9]+$/', $version)) + { + $version = substr($version, 1); + + if (version_compare($version, $currentVersion, '>') && version_compare($version, $latest, '>')) { + $latest = $version; + } + } +} + +if ($latest != '0.1') { + file_put_contents('/home/vagrant/scripts/updater/UPDATE_AVAILABLE', $latest); +} diff --git a/puppet/modules/scripts/manifests/init.pp b/puppet/modules/scripts/manifests/init.pp index feef9e4..828226b 100644 --- a/puppet/modules/scripts/manifests/init.pp +++ b/puppet/modules/scripts/manifests/init.pp @@ -8,22 +8,46 @@ } exec { 'make-scripts-executable': - command => 'chmod +x /home/vagrant/scripts/remove_dotunderscore', + command => 'chmod +x /home/vagrant/scripts/remove_dotunderscore /home/vagrant/scripts/updater/login.sh', require => File['/home/vagrant/scripts'] } exec { 'add-scripts-to-path': - command => 'echo "export PATH=\$PATH:/home/vagrant/.composer/vendor/bin" >> /home/vagrant/.profile', - unless => 'grep ":/home/vagrant/.composer/vendor/bin" /home/vagrant/.profile', + command => 'echo "export PATH=\$PATH:/home/vagrant/.composer/vendor/bin" >> /home/vagrant/.bash_profile', + unless => 'grep ":/home/vagrant/.composer/vendor/bin" /home/vagrant/.bash_profile', require => Exec['make-scripts-executable'] } exec { 'add-console': - command => 'composer global require joomlatools/joomla-console:1.* --no-interaction', + command => 'composer global require joomlatools/joomla-console:* --no-interaction', unless => '[ -d /home/vagrant/.composer/vendor/joomlatools/joomla-console ]', require => [File['/home/vagrant/scripts'], Class['Composer']], user => vagrant, environment => 'COMPOSER_HOME=/home/vagrant/.composer' } + file {'/home/vagrant/.bash_profile': + ensure => file, + owner => vagrant, + group => vagrant, + notify => [File_line['joomla-console-updater'], File_line['cd-to-www-dir']] + } + + file_line { 'joomla-console-updater': + path => '/home/vagrant/.bash_profile', + line => '/home/vagrant/scripts/updater/login.sh', + require => Exec['make-scripts-executable'] + } + + file_line { 'load-bashrc': + path => '/home/vagrant/.bash_profile', + line => '[ -f ~/.bashrc ] && . ~/.bashrc', + require => File['/home/vagrant/.bash_profile'] + } + + file_line { 'cd-to-www-dir': + path => '/home/vagrant/.bash_profile', + line => '[ -d /var/www ] && cd /var/www', + require => File_Line['load-bashrc'] + } } \ No newline at end of file diff --git a/puppet/modules/stdlib/.gemspec b/puppet/modules/stdlib/.gemspec new file mode 100755 index 0000000..e274950 --- /dev/null +++ b/puppet/modules/stdlib/.gemspec @@ -0,0 +1,40 @@ +# +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = "puppetmodule-stdlib" + + s.version = "4.0.2" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["Puppet Labs"] + s.date = "2013-04-12" + s.description = [ 'This Gem format of the stdlib module is intended to make', + 'it easier for _module authors_ to resolve dependencies', + 'using a Gemfile when running automated testing jobs like', + 'Travis or Jenkins. The recommended best practice for', + 'installation by end users is to use the `puppet module', + 'install` command to install stdlib from the [Puppet', + 'Forge](http://forge.puppetlabs.com/puppetlabs/stdlib).' ].join(' ') + s.email = "puppet-dev@puppetlabs.com" + s.executables = [] + s.files = [ 'CHANGELOG', 'CONTRIBUTING.md', 'Gemfile', 'LICENSE', 'Modulefile', + 'README.markdown', 'README_DEVELOPER.markdown', 'RELEASE_PROCESS.markdown', + 'Rakefile', 'spec/spec.opts' ] + s.files += Dir['lib/**/*.rb'] + Dir['manifests/**/*.pp'] + Dir['tests/**/*.pp'] + Dir['spec/**/*.rb'] + s.homepage = "http://forge.puppetlabs.com/puppetlabs/stdlib" + s.rdoc_options = ["--title", "Puppet Standard Library Development Gem", "--main", "README.markdown", "--line-numbers"] + s.require_paths = ["lib"] + s.rubyforge_project = "puppetmodule-stdlib" + s.rubygems_version = "1.8.24" + s.summary = "This gem provides a way to make the standard library available for other module spec testing tasks." + + if s.respond_to? :specification_version then + s.specification_version = 3 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + else + end + else + end +end diff --git a/puppet/modules/stdlib/.gitignore b/puppet/modules/stdlib/.gitignore new file mode 100755 index 0000000..2e3ca63 --- /dev/null +++ b/puppet/modules/stdlib/.gitignore @@ -0,0 +1,8 @@ +pkg/ +.DS_Store +metadata.json +coverage/ +spec/fixtures/ +Gemfile.lock +.bundle/ +vendor/bundle/ diff --git a/puppet/modules/stdlib/.rspec b/puppet/modules/stdlib/.rspec old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/.travis.yml b/puppet/modules/stdlib/.travis.yml new file mode 100755 index 0000000..1bb1889 --- /dev/null +++ b/puppet/modules/stdlib/.travis.yml @@ -0,0 +1,25 @@ +language: ruby +bundler_args: --without development +script: "bundle exec rake spec SPEC_OPTS='--color --format documentation'" +rvm: + - 1.8.7 + - 1.9.3 + - 2.0.0 + - ruby-head +env: + - PUPPET_GEM_VERSION=">= 3.0.0" +matrix: + allow_failures: + - rvm: 2.0.0 + - rvm: ruby-head + include: + - rvm: 1.8.7 + env: PUPPET_GEM_VERSION="~> 2.7" +notifications: + email: false + webhooks: + urls: + - https://puppet-dev-community.herokuapp.com/event/travis-ci/ + on_success: always + on_failure: always + on_start: yes diff --git a/puppet/modules/stdlib/CHANGELOG b/puppet/modules/stdlib/CHANGELOG old mode 100644 new mode 100755 index b7c3ced..e1a095f --- a/puppet/modules/stdlib/CHANGELOG +++ b/puppet/modules/stdlib/CHANGELOG @@ -1,30 +1,153 @@ -2012-11-28 - Peter Meier - 2.6.0 - * Add reject() function (a79b2cd) +2013-05-06 - Jeff McCune - 4.1.0 + * (#20582) Restore facter_dot_d to stdlib for PE users (3b887c8) + * (maint) Update Gemfile with GEM_FACTER_VERSION (f44d535) -2012-09-18 - Chad Metcalf - 2.6.0 +2013-05-06 - Alex Cline - 4.1.0 + * Terser method of string to array conversion courtesy of ethooz. (d38bce0) + +2013-05-06 - Alex Cline 4.1.0 + * Refactor ensure_resource expectations (b33cc24) + +2013-05-06 - Alex Cline 4.1.0 + * Changed str-to-array conversion and removed abbreviation. (de253db) + +2013-05-03 - Alex Cline 4.1.0 + * (#20548) Allow an array of resource titles to be passed into the ensure_resource function (e08734a) + +2013-05-02 - Raphaël Pinson - 4.1.0 + * Add a dirname function (2ba9e47) + +2013-04-29 - Mark Smith-Guerrero - 4.1.0 + * (maint) Fix a small typo in hash() description (928036a) + +2013-04-12 - Jeff McCune - 4.0.2 + * Update user information in gemspec to make the intent of the Gem clear. + +2013-04-11 - Jeff McCune - 4.0.1 + * Fix README function documentation (ab3e30c) + +2013-04-11 - Jeff McCune - 4.0.0 + * stdlib 4.0 drops support with Puppet 2.7 + * stdlib 4.0 preserves support with Puppet 3 + +2013-04-11 - Jeff McCune - 4.0.0 + * Add ability to use puppet from git via bundler (9c5805f) + +2013-04-10 - Jeff McCune - 4.0.0 + * (maint) Make stdlib usable as a Ruby GEM (e81a45e) + +2013-04-10 - Erik Dalén - 4.0.0 + * Add a count function (f28550e) + +2013-03-31 - Amos Shapira - 4.0.0 + * (#19998) Implement any2array (7a2fb80) + +2013-03-29 - Steve Huff - 4.0.0 + * (19864) num2bool match fix (8d217f0) + +2013-03-20 - Erik Dalén - 4.0.0 + * Allow comparisons of Numeric and number as String (ff5dd5d) + +2013-03-26 - Richard Soderberg - 4.0.0 + * add suffix function to accompany the prefix function (88a93ac) + +2013-03-19 - Kristof Willaert - 4.0.0 + * Add floor function implementation and unit tests (0527341) + +2012-04-03 - Eric Shamow - 4.0.0 + * (#13610) Add is_function_available to stdlib (961dcab) + +2012-12-17 - Justin Lambert - 4.0.0 + * str2bool should return a boolean if called with a boolean (5d5a4d4) + +2012-10-23 - Uwe Stuehler - 4.0.0 + * Fix number of arguments check in flatten() (e80207b) + +2013-03-11 - Jeff McCune - 4.0.0 + * Add contributing document (96e19d0) + +2013-03-04 - Raphaël Pinson - 4.0.0 + * Add missing documentation for validate_augeas and validate_cmd to README.markdown (a1510a1) + +2013-02-14 - Joshua Hoblitt - 4.0.0 + * (#19272) Add has_element() function (95cf3fe) + +2013-02-07 - Raphaël Pinson - 4.0.0 + * validate_cmd(): Use Puppet::Util::Execution.execute when available (69248df) + +2012-12-06 - Raphaël Pinson - 4.0.0 + * Add validate_augeas function (3a97c23) + +2012-12-06 - Raphaël Pinson - 4.0.0 + * Add validate_cmd function (6902cc5) + +2013-01-14 - David Schmitt - 4.0.0 + * Add geppetto project definition (b3fc0a3) + +2013-01-02 - Jaka Hudoklin - 4.0.0 + * Add getparam function to get defined resource parameters (20e0e07) + +2013-01-05 - Jeff McCune - 4.0.0 + * (maint) Add Travis CI Support (d082046) + +2012-12-04 - Jeff McCune - 4.0.0 + * Clarify that stdlib 3 supports Puppet 3 (3a6085f) + +2012-11-30 - Erik Dalén - 4.0.0 + * maint: style guideline fixes (7742e5f) + +2012-11-09 - James Fryman - 4.0.0 + * puppet-lint cleanup (88acc52) + +2012-11-06 - Joe Julian - 4.0.0 + * Add function, uriescape, to URI.escape strings. Redmine #17459 (fd52b8d) + +2012-09-18 - Chad Metcalf - 3.2.0 * Add an ensure_packages function. (8a8c09e) -2012-11-23 - Erik Dalén - 2.6.0 +2012-11-23 - Erik Dalén - 3.2.0 * (#17797) min() and max() functions (9954133) -2012-05-23 - Peter Meier - 2.6.0 +2012-05-23 - Peter Meier - 3.2.0 * (#14670) autorequire a file_line resource's path (dfcee63) -2012-11-19 - Joshua Harlan Lifton - 2.6.0 +2012-11-19 - Joshua Harlan Lifton - 3.2.0 * Add join_keys_to_values function (ee0f2b3) -2012-11-17 - Joshua Harlan Lifton - 2.6.0 +2012-11-17 - Joshua Harlan Lifton - 3.2.0 * Extend delete function for strings and hashes (7322e4d) -2012-08-03 - Gary Larizza - 2.6.0 +2012-08-03 - Gary Larizza - 3.2.0 * Add the pick() function (ba6dd13) -2012-03-20 - Wil Cooley - 2.6.0 +2012-03-20 - Wil Cooley - 3.2.0 * (#13974) Add predicate functions for interface facts (f819417) -2012-11-06 - Joe Julian - 2.6.0 +2012-11-06 - Joe Julian - 3.2.0 * Add function, uriescape, to URI.escape strings. Redmine #17459 (70f4a0e) +2012-10-25 - Jeff McCune - 3.1.1 + * (maint) Fix spec failures resulting from Facter API changes (97f836f) + +2012-10-23 - Matthaus Owens - 3.1.0 + * Add PE facts to stdlib (cdf3b05) + +2012-08-16 - Jeff McCune - 3.0.1 + * Fix accidental removal of facts_dot_d.rb in 3.0.0 release + +2012-08-16 - Jeff McCune - 3.0.0 + * stdlib 3.0 drops support with Puppet 2.6 + * stdlib 3.0 preserves support with Puppet 2.7 + +2012-08-07 - Dan Bode - 3.0.0 + * Add function ensure_resource and defined_with_params (ba789de) + +2012-07-10 - Hailee Kenney - 3.0.0 + * (#2157) Remove facter_dot_d for compatibility with external facts (f92574f) + +2012-04-10 - Chris Price - 3.0.0 + * (#13693) moving logic from local spec_helper to puppetlabs_spec_helper (85f96df) + 2012-10-25 - Jeff McCune - 2.5.1 * (maint) Fix spec failures resulting from Facter API changes (97f836f) diff --git a/puppet/modules/stdlib/CONTRIBUTING.md b/puppet/modules/stdlib/CONTRIBUTING.md new file mode 100755 index 0000000..bd11f63 --- /dev/null +++ b/puppet/modules/stdlib/CONTRIBUTING.md @@ -0,0 +1,65 @@ +# How to contribute + +Third-party patches are essential for keeping stdlib great. We simply can't +access the huge number of platforms and myriad configurations for running +stdlib. We want to keep it as easy as possible to contribute changes that +get things working 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. + +## Getting Started + +* Make sure you have a [Redmine account](http://projects.puppetlabs.com) +* Make sure you have a [GitHub account](https://github.com/signup/free) +* Submit a ticket for your issue, assuming one does not already exist. + * Clearly describe the issue including steps to reproduce when it is a bug. + * Make sure you fill in the earliest version that you know has the issue. +* Fork the repository on GitHub + +## Making Changes + +* Create a topic branch from where you want to base your work. + * This is usually the master branch. + * Only target release branches if you are certain your fix must be on that + branch. + * To quickly create a topic branch based on master; `git branch + fix/master/my_contribution master` then checkout the new branch with `git + checkout fix/master/my_contribution`. Please avoid working directly on the + `master` branch. +* Make commits of logical units. +* Check for unnecessary whitespace with `git diff --check` before committing. +* Make sure your commit messages are in the proper format. + +```` + (#99999) Make the example in CONTRIBUTING imperative and concrete + + Without this patch applied the example commit message in the CONTRIBUTING + document is not a concrete example. This is a problem because the + contributor is left to imagine what the commit message should look like + based on a description rather than an example. This patch fixes the + problem by making the example concrete and imperative. + + The first line is a real life imperative statement with a ticket number + from our issue tracker. The body describes the behavior without the patch, + why this is a problem, and how the patch fixes the problem when applied. +```` + +* Make sure you have added the necessary tests for your changes. +* Run _all_ the tests to assure nothing else was accidentally broken. + +## Submitting Changes + +* Sign the [Contributor License Agreement](http://links.puppetlabs.com/cla). +* Push your changes to a topic branch in your fork of the repository. +* Submit a pull request to the repository in the puppetlabs organization. +* Update your Redmine ticket to mark that you have submitted code and are ready for it to be reviewed. + * Include a link to the pull request in the ticket + +# Additional Resources + +* [More information on contributing](http://links.puppetlabs.com/contribute-to-puppet) +* [Bug tracker (Redmine)](http://projects.puppetlabs.com) +* [Contributor License Agreement](http://links.puppetlabs.com/cla) +* [General GitHub documentation](http://help.github.com/) +* [GitHub pull request documentation](http://help.github.com/send-pull-requests/) +* #puppet-dev IRC channel on freenode.org diff --git a/puppet/modules/stdlib/Gemfile b/puppet/modules/stdlib/Gemfile new file mode 100755 index 0000000..197cc6b --- /dev/null +++ b/puppet/modules/stdlib/Gemfile @@ -0,0 +1,42 @@ +source "https://rubygems.org" + +def location_for(place, fake_version = nil) + mdata = /^(git:[^#]*)#(.*)/.match(place) + if mdata + [fake_version, { :git => mdata[1], :branch => mdata[2], :require => false }].compact + elsif place =~ /^file:\/\/(.*)/ + ['>= 0', { :path => File.expand_path(mdata[1]), :require => false }] + else + [place, { :require => false }] + end +end + +group :development do + gem 'watchr' +end + +group :development, :test do + gem 'rake' + gem 'puppetmodule-stdlib', ">= 1.0.0", :path => File.expand_path("..", __FILE__) + gem 'rspec', "~> 2.11.0", :require => false + gem 'mocha', "~> 0.10.5", :require => false + gem 'puppetlabs_spec_helper', :require => false + gem 'rspec-puppet', :require => false +end + +facterversion = ENV['GEM_FACTER_VERSION'] +if facterversion + gem 'facter', *location_for(facterversion) +else + gem 'facter', :require => false +end + +ENV['GEM_PUPPET_VERSION'] ||= ENV['PUPPET_GEM_VERSION'] +puppetversion = ENV['GEM_PUPPET_VERSION'] +if puppetversion + gem 'puppet', *location_for(puppetversion) +else + gem 'puppet', :require => false +end + +# vim:ft=ruby diff --git a/puppet/modules/stdlib/LICENSE b/puppet/modules/stdlib/LICENSE old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/Modulefile b/puppet/modules/stdlib/Modulefile old mode 100644 new mode 100755 index c3568e0..9d2e8c2 --- a/puppet/modules/stdlib/Modulefile +++ b/puppet/modules/stdlib/Modulefile @@ -1,6 +1,6 @@ name 'puppetlabs-stdlib' -version '2.6.0' -source 'git://github.com/puppetlabs/puppetlabs-stdlib' +version '4.1.0' +source 'git://github.com/puppetlabs/puppetlabs-stdlib.git' author 'puppetlabs' license 'Apache 2.0' summary 'Puppet Module Standard Library' diff --git a/puppet/modules/stdlib/README.markdown b/puppet/modules/stdlib/README.markdown old mode 100644 new mode 100755 index 9fa4c38..7b45b17 --- a/puppet/modules/stdlib/README.markdown +++ b/puppet/modules/stdlib/README.markdown @@ -1,5 +1,7 @@ # Puppet Labs Standard Library # +[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-stdlib.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-stdlib) + This module provides a "standard library" of resources for developing Puppet Modules. This modules will include the following additions to Puppet @@ -14,6 +16,9 @@ This module is officially curated and provided by Puppet Labs. The modules Puppet Labs writes and distributes will make heavy use of this standard library. +To report or research a bug with any part of this module, please go to +[http://projects.puppetlabs.com/projects/stdlib](http://projects.puppetlabs.com/projects/stdlib) + # Versions # This module follows semver.org (v1.0.0) versioning guidelines. The standard @@ -23,9 +28,11 @@ older versions of Puppet Enterprise that Puppet Labs still supports will have bugfix maintenance branches periodically "merged up" into master. The current list of integration branches are: - * v2.1.x (v2.1.1 released in PE 1.2, 1.2.1, 1.2.3, 1.2.4) + * v2.1.x (v2.1.1 released in PE 1) * v2.2.x (Never released as part of PE, only to the Forge) - * v2.3.x (Scheduled for next PE feature release) + * v2.3.x (Released in PE 2) + * v3.0.x (Never released as part of PE, only to the Forge) + * v4.0.x (Drops support for Puppet 2.7) * master (mainline development branch) The first Puppet Enterprise version including the stdlib module is Puppet @@ -33,50 +40,1155 @@ Enterprise 1.2. # Compatibility # -## stdlib v2.1.x, v2.2.x ## +Puppet Versions | < 2.6 | 2.6 | 2.7 | 3.x | +:---------------|:-----:|:---:|:---:|:----: +**stdlib 2.x** | no | **yes** | **yes** | no +**stdlib 3.x** | no | no | **yes** | **yes** +**stdlib 4.x** | no | no | no | **yes** + +The stdlib module does not work with Puppet versions released prior to Puppet +2.6.0. + +## stdlib 2.x ## -v2.1.x and v2.2.x of this module are designed to work with Puppet versions -2.6.x and 2.7.x. There are currently no plans for a Puppet 0.25 standard -library module. +All stdlib releases in the 2.0 major version support Puppet 2.6 and Puppet 2.7. -## stdlib v2.3.x ## +## stdlib 3.x ## -While not yet released, the standard library may only work with Puppet 2.7.x. +The 3.0 major release of stdlib drops support for Puppet 2.6. Stdlib 3.x +supports Puppet 2 and Puppet 3. + +## stdlib 4.x ## + +The 4.0 major release of stdlib drops support for Puppet 2.7. Stdlib 4.x +supports Puppet 3. Notably, ruby 1.8.5 is no longer supported though ruby +1.8.7, 1.9.3, and 2.0.0 are fully supported. # Functions # - Please see `puppet doc -r function` for documentation on each function. The - current list of functions is: +abs +--- +Returns the absolute value of a number, for example -34.56 becomes +34.56. Takes a single integer and float value as an argument. + + +- *Type*: rvalue + +any2array +--------- +This converts any object to an array containing that object. Empty argument +lists are converted to an empty array. Arrays are left untouched. Hashes are +converted to arrays of alternating keys and values. + + +- *Type*: rvalue + +bool2num +-------- +Converts a boolean to a number. Converts the values: +false, f, 0, n, and no to 0 +true, t, 1, y, and yes to 1 + Requires a single boolean or string as an input. + + +- *Type*: rvalue + +capitalize +---------- +Capitalizes the first letter of a string or array of strings. +Requires either a single string or an array as an input. + + +- *Type*: rvalue + +chomp +----- +Removes the record separator from the end of a string or an array of +strings, for example `hello\n` becomes `hello`. +Requires a single string or array as an input. + + +- *Type*: rvalue + +chop +---- +Returns a new string with the last character removed. If the string ends +with `\r\n`, both characters are removed. Applying chop to an empty +string returns an empty string. If you wish to merely remove record +separators then you should use the `chomp` function. +Requires a string or array of strings as input. + + +- *Type*: rvalue + +concat +------ +Appends the contents of array 2 onto array 1. + +*Example:* + + concat(['1','2','3'],['4','5','6']) + +Would result in: + + ['1','2','3','4','5','6'] + + +- *Type*: rvalue + +count +----- +Takes an array as first argument and an optional second argument. +Count the number of elements in array that matches second argument. +If called with only an array it counts the number of elements that are not nil/undef. + + +- *Type*: rvalue + +defined_with_params +------------------- +Takes a resource reference and an optional hash of attributes. + +Returns true if a resource with the specified attributes has already been added +to the catalog, and false otherwise. + + user { 'dan': + ensure => present, + } + + if ! defined_with_params(User[dan], {'ensure' => 'present' }) { + user { 'dan': ensure => present, } + } + + +- *Type*: rvalue + +delete +------ +Deletes all instances of a given element from an array, substring from a +string, or key from a hash. + +*Examples:* + + delete(['a','b','c','b'], 'b') + Would return: ['a','c'] + + delete({'a'=>1,'b'=>2,'c'=>3}, 'b') + Would return: {'a'=>1,'c'=>3} + + delete('abracadabra', 'bra') + Would return: 'acada' + + +- *Type*: rvalue + +delete_at +--------- +Deletes a determined indexed value from an array. + +*Examples:* + + delete_at(['a','b','c'], 1) + +Would return: ['a','c'] + + +- *Type*: rvalue + +dirname +------- +Returns the `dirname` of a path. + +*Examples:* + + dirname('/path/to/a/file.ext') + +Would return: '/path/to/a' + +downcase +-------- +Converts the case of a string or all strings in an array to lower case. + + +- *Type*: rvalue + +empty +----- +Returns true if the variable is empty. + + +- *Type*: rvalue + +ensure_packages +--------------- +Takes a list of packages and only installs them if they don't already exist. + + +- *Type*: statement + +ensure_resource +--------------- +Takes a resource type, title, and a list of attributes that describe a +resource. + + user { 'dan': + ensure => present, + } + +This example only creates the resource if it does not already exist: + + ensure_resource('user, 'dan', {'ensure' => 'present' }) + +If the resource already exists but does not match the specified parameters, +this function will attempt to recreate the resource leading to a duplicate +resource definition error. + +An array of resources can also be passed in and each will be created with +the type and parameters specified if it doesn't already exist. + + ensure_resource('user', ['dan','alex'], {'ensure' => 'present'}) + + + +- *Type*: statement + +flatten +------- +This function flattens any deeply nested arrays and returns a single flat array +as a result. + +*Examples:* + + flatten(['a', ['b', ['c']]]) + +Would return: ['a','b','c'] + + +- *Type*: rvalue + +floor +----- +Returns the largest integer less or equal to the argument. +Takes a single numeric value as an argument. + + +- *Type*: rvalue + +fqdn_rotate +----------- +Rotates an array a random number of times based on a nodes fqdn. + + +- *Type*: rvalue + +get_module_path +--------------- +Returns the absolute path of the specified module for the current +environment. + +Example: + $module_path = get_module_path('stdlib') + + +- *Type*: rvalue + +getparam +-------- +Takes a resource reference and name of the parameter and +returns value of resource's parameter. + +*Examples:* + + define example_resource($param) { + } + + example_resource { "example_resource_instance": + param => "param_value" + } + + getparam(Example_resource["example_resource_instance"], "param") + +Would return: param_value + + +- *Type*: rvalue + +getvar +------ +Lookup a variable in a remote namespace. + +For example: + + $foo = getvar('site::data::foo') + # Equivalent to $foo = $site::data::foo + +This is useful if the namespace itself is stored in a string: + + $datalocation = 'site::data' + $bar = getvar("${datalocation}::bar") + # Equivalent to $bar = $site::data::bar + + +- *Type*: rvalue + +grep +---- +This function searches through an array and returns any elements that match +the provided regular expression. + +*Examples:* + + grep(['aaa','bbb','ccc','aaaddd'], 'aaa') + +Would return: + + ['aaa','aaaddd'] + + +- *Type*: rvalue + +has_interface_with +------------------ +Returns boolean based on kind and value: +* macaddress +* netmask +* ipaddress +* network + +has_interface_with("macaddress", "x:x:x:x:x:x") +has_interface_with("ipaddress", "127.0.0.1") => true +etc. + +If no "kind" is given, then the presence of the interface is checked: +has_interface_with("lo") => true + + +- *Type*: rvalue + +has_ip_address +-------------- +Returns true if the client has the requested IP address on some interface. + +This function iterates through the 'interfaces' fact and checks the +'ipaddress_IFACE' facts, performing a simple string comparison. + + +- *Type*: rvalue + +has_ip_network +-------------- +Returns true if the client has an IP address within the requested network. + +This function iterates through the 'interfaces' fact and checks the +'network_IFACE' facts, performing a simple string comparision. + + +- *Type*: rvalue + +has_key +------- +Determine if a hash has a certain key value. + +Example: + + $my_hash = {'key_one' => 'value_one'} + if has_key($my_hash, 'key_two') { + notice('we will not reach here') + } + if has_key($my_hash, 'key_one') { + notice('this will be printed') + } + + + +- *Type*: rvalue + +hash +---- +This function converts an array into a hash. + +*Examples:* + + hash(['a',1,'b',2,'c',3]) + +Would return: {'a'=>1,'b'=>2,'c'=>3} + + +- *Type*: rvalue + +is_array +-------- +Returns true if the variable passed to this function is an array. + +- *Type*: rvalue + +is_domain_name +-------------- +Returns true if the string passed to this function is a syntactically correct domain name. + +- *Type*: rvalue + +is_float +-------- +Returns true if the variable passed to this function is a float. + +- *Type*: rvalue + +is_function_available +--------------------- +This function accepts a string as an argument, determines whether the +Puppet runtime has access to a function by that name. It returns a +true if the function exists, false if not. + +- *Type*: rvalue + +is_hash +------- +Returns true if the variable passed to this function is a hash. + +- *Type*: rvalue + +is_integer +---------- +Returns true if the variable returned to this string is an integer. + +- *Type*: rvalue + +is_ip_address +------------- +Returns true if the string passed to this function is a valid IP address. + +- *Type*: rvalue + +is_mac_address +-------------- +Returns true if the string passed to this function is a valid mac address. + +- *Type*: rvalue + +is_numeric +---------- +Returns true if the variable passed to this function is a number. + +- *Type*: rvalue + +is_string +--------- +Returns true if the variable passed to this function is a string. + +- *Type*: rvalue + +join +---- +This function joins an array into a string using a seperator. + +*Examples:* + + join(['a','b','c'], ",") + +Would result in: "a,b,c" + +- *Type*: rvalue + +join_keys_to_values +------------------- +This function joins each key of a hash to that key's corresponding value with a +separator. Keys and values are cast to strings. The return value is an array in +which each element is one joined key/value pair. + +*Examples:* + + join_keys_to_values({'a'=>1,'b'=>2}, " is ") + +Would result in: ["a is 1","b is 2"] + +- *Type*: rvalue + +keys +---- +Returns the keys of a hash as an array. + +- *Type*: rvalue + +loadyaml +-------- +Load a YAML file containing an array, string, or hash, and return the data +in the corresponding native data type. + +For example: + + $myhash = loadyaml('/etc/puppet/data/myhash.yaml') + + +- *Type*: rvalue + +lstrip +------ +Strips leading spaces to the left of a string. + +- *Type*: rvalue + +max +--- +Returns the highest value of all arguments. +Requires at least one argument. + +- *Type*: rvalue + +member +------ +This function determines if a variable is a member of an array. + +*Examples:* + + member(['a','b'], 'b') + +Would return: true + + member(['a','b'], 'c') + +Would return: false + +- *Type*: rvalue + +merge +----- +Merges two or more hashes together and returns the resulting hash. + +For example: + + $hash1 = {'one' => 1, 'two', => 2} + $hash2 = {'two' => 'dos', 'three', => 'tres'} + $merged_hash = merge($hash1, $hash2) + # The resulting hash is equivalent to: + # $merged_hash = {'one' => 1, 'two' => 'dos', 'three' => 'tres'} + +When there is a duplicate key, the key in the rightmost hash will "win." + +- *Type*: rvalue + +min +--- +Returns the lowest value of all arguments. +Requires at least one argument. + +- *Type*: rvalue + +num2bool +-------- +This function converts a number or a string representation of a number into a +true boolean. Zero or anything non-numeric becomes false. Numbers higher then 0 +become true. + +- *Type*: rvalue + +parsejson +--------- +This function accepts JSON as a string and converts into the correct Puppet +structure. + +- *Type*: rvalue + +parseyaml +--------- +This function accepts YAML as a string and converts it into the correct +Puppet structure. + +- *Type*: rvalue + +pick +---- +This function is similar to a coalesce function in SQL in that it will return +the first value in a list of values that is not undefined or an empty string +(two things in Puppet that will return a boolean false value). Typically, +this function is used to check for a value in the Puppet Dashboard/Enterprise +Console, and failover to a default value like the following: + + $real_jenkins_version = pick($::jenkins_version, '1.449') + +The value of $real_jenkins_version will first look for a top-scope variable +called 'jenkins_version' (note that parameters set in the Puppet Dashboard/ +Enterprise Console are brought into Puppet as top-scope variables), and, +failing that, will use a default value of 1.449. + +- *Type*: rvalue + +prefix +------ +This function applies a prefix to all elements in an array. + +*Examples:* + + prefix(['a','b','c'], 'p') + +Will return: ['pa','pb','pc'] + +- *Type*: rvalue + +range +----- +When given range in the form of (start, stop) it will extrapolate a range as +an array. + +*Examples:* + + range("0", "9") + +Will return: [0,1,2,3,4,5,6,7,8,9] + + range("00", "09") + +Will return: [0,1,2,3,4,5,6,7,8,9] (Zero padded strings are converted to +integers automatically) + + range("a", "c") + +Will return: ["a","b","c"] + + range("host01", "host10") + +Will return: ["host01", "host02", ..., "host09", "host10"] + +- *Type*: rvalue + +reject +------ +This function searches through an array and rejects all elements that match +the provided regular expression. + +*Examples:* + + reject(['aaa','bbb','ccc','aaaddd'], 'aaa') + +Would return: + + ['bbb','ccc'] + + +- *Type*: rvalue + +reverse +------- +Reverses the order of a string or array. + +- *Type*: rvalue + +rstrip +------ +Strips leading spaces to the right of the string. + +- *Type*: rvalue + +shuffle +------- +Randomizes the order of a string or array elements. + +- *Type*: rvalue + +size +---- +Returns the number of elements in a string or array. + +- *Type*: rvalue + +sort +---- +Sorts strings and arrays lexically. + +- *Type*: rvalue + +squeeze +------- +Returns a new string where runs of the same character that occur in this set +are replaced by a single character. + +- *Type*: rvalue + +str2bool +-------- +This converts a string to a boolean. This attempt to convert strings that +contain things like: y, 1, t, true to 'true' and strings that contain things +like: 0, f, n, false, no to 'false'. + + +- *Type*: rvalue + +str2saltedsha512 +---------------- +This converts a string to a salted-SHA512 password hash (which is used for +OS X versions >= 10.7). Given any simple string, you will get a hex version +of a salted-SHA512 password hash that can be inserted into your Puppet +manifests as a valid password attribute. + + +- *Type*: rvalue + +strftime +-------- +This function returns formatted time. + +*Examples:* + +To return the time since epoch: + + strftime("%s") + +To return the date: + + strftime("%Y-%m-%d") + +*Format meaning:* + + %a - The abbreviated weekday name (``Sun'') + %A - The full weekday name (``Sunday'') + %b - The abbreviated month name (``Jan'') + %B - The full month name (``January'') + %c - The preferred local date and time representation + %C - Century (20 in 2009) + %d - Day of the month (01..31) + %D - Date (%m/%d/%y) + %e - Day of the month, blank-padded ( 1..31) + %F - Equivalent to %Y-%m-%d (the ISO 8601 date format) + %h - Equivalent to %b + %H - Hour of the day, 24-hour clock (00..23) + %I - Hour of the day, 12-hour clock (01..12) + %j - Day of the year (001..366) + %k - hour, 24-hour clock, blank-padded ( 0..23) + %l - hour, 12-hour clock, blank-padded ( 0..12) + %L - Millisecond of the second (000..999) + %m - Month of the year (01..12) + %M - Minute of the hour (00..59) + %n - Newline ( +) + %N - Fractional seconds digits, default is 9 digits (nanosecond) + %3N millisecond (3 digits) + %6N microsecond (6 digits) + %9N nanosecond (9 digits) + %p - Meridian indicator (``AM'' or ``PM'') + %P - Meridian indicator (``am'' or ``pm'') + %r - time, 12-hour (same as %I:%M:%S %p) + %R - time, 24-hour (%H:%M) + %s - Number of seconds since 1970-01-01 00:00:00 UTC. + %S - Second of the minute (00..60) + %t - Tab character ( ) + %T - time, 24-hour (%H:%M:%S) + %u - Day of the week as a decimal, Monday being 1. (1..7) + %U - Week number of the current year, + starting with the first Sunday as the first + day of the first week (00..53) + %v - VMS date (%e-%b-%Y) + %V - Week number of year according to ISO 8601 (01..53) + %W - Week number of the current year, + starting with the first Monday as the first + day of the first week (00..53) + %w - Day of the week (Sunday is 0, 0..6) + %x - Preferred representation for the date alone, no time + %X - Preferred representation for the time alone, no date + %y - Year without a century (00..99) + %Y - Year with century + %z - Time zone as hour offset from UTC (e.g. +0900) + %Z - Time zone name + %% - Literal ``%'' character + + +- *Type*: rvalue + +strip +----- +This function removes leading and trailing whitespace from a string or from +every string inside an array. + +*Examples:* + + strip(" aaa ") + +Would result in: "aaa" + + +- *Type*: rvalue + +suffix +------ +This function applies a suffix to all elements in an array. + +*Examples:* + + suffix(['a','b','c'], 'p') + +Will return: ['ap','bp','cp'] + + +- *Type*: rvalue + +swapcase +-------- +This function will swap the existing case of a string. + +*Examples:* + + swapcase("aBcD") + +Would result in: "AbCd" + + +- *Type*: rvalue + +time +---- +This function will return the current time since epoch as an integer. + +*Examples:* + + time() + +Will return something like: 1311972653 + + +- *Type*: rvalue + +to_bytes +-------- +Converts the argument into bytes, for example 4 kB becomes 4096. +Takes a single string value as an argument. + + +- *Type*: rvalue + +type +---- +Returns the type when passed a variable. Type can be one of: + +* string +* array +* hash +* float +* integer +* boolean + + +- *Type*: rvalue + +unique +------ +This function will remove duplicates from strings and arrays. + +*Examples:* + + unique("aabbcc") + +Will return: + + abc + +You can also use this with arrays: + + unique(["a","a","b","b","c","c"]) + +This returns: + + ["a","b","c"] + + +- *Type*: rvalue + +upcase +------ +Converts a string or an array of strings to uppercase. + +*Examples:* + + upcase("abcd") + +Will return: + + ASDF + + +- *Type*: rvalue + +uriescape +--------- +Urlencodes a string or array of strings. +Requires either a single string or an array as an input. + + +- *Type*: rvalue + +validate_absolute_path +---------------------- +Validate the string represents an absolute path in the filesystem. This function works +for windows and unix style paths. + +The following values will pass: + + $my_path = "C:/Program Files (x86)/Puppet Labs/Puppet" + validate_absolute_path($my_path) + $my_path2 = "/var/lib/puppet" + validate_absolute_path($my_path2) + + +The following values will fail, causing compilation to abort: + + validate_absolute_path(true) + validate_absolute_path([ 'var/lib/puppet', '/var/foo' ]) + validate_absolute_path([ '/var/lib/puppet', 'var/foo' ]) + $undefined = undef + validate_absolute_path($undefined) + + + +- *Type*: statement + +validate_array +-------------- +Validate that all passed values are array data structures. Abort catalog +compilation if any value fails this check. + +The following values will pass: + + $my_array = [ 'one', 'two' ] + validate_array($my_array) + +The following values will fail, causing compilation to abort: + + validate_array(true) + validate_array('some_string') + $undefined = undef + validate_array($undefined) + + + +- *Type*: statement + +validate_augeas +--------------- +Perform validation of a string using an Augeas lens +The first argument of this function should be a string to +test, and the second argument should be the name of the Augeas lens to use. +If Augeas fails to parse the string with the lens, the compilation will +abort with a parse error. + +A third argument can be specified, listing paths which should +not be found in the file. The `$file` variable points to the location +of the temporary file being tested in the Augeas tree. + +For example, if you want to make sure your passwd content never contains +a user `foo`, you could write: + + validate_augeas($passwdcontent, 'Passwd.lns', ['$file/foo']) + +Or if you wanted to ensure that no users used the '/bin/barsh' shell, +you could use: + + validate_augeas($passwdcontent, 'Passwd.lns', ['$file/*[shell="/bin/barsh"]'] + +If a fourth argument is specified, this will be the error message raised and +seen by the user. + +A helpful error message can be returned like this: + + validate_augeas($sudoerscontent, 'Sudoers.lns', [], 'Failed to validate sudoers content with Augeas') + + + +- *Type*: statement + +validate_bool +------------- +Validate that all passed values are either true or false. Abort catalog +compilation if any value fails this check. + +The following values will pass: + + $iamtrue = true + validate_bool(true) + validate_bool(true, true, false, $iamtrue) + +The following values will fail, causing compilation to abort: + + $some_array = [ true ] + validate_bool("false") + validate_bool("true") + validate_bool($some_array) + + + +- *Type*: statement + +validate_cmd +------------ +Perform validation of a string with an external command. +The first argument of this function should be a string to +test, and the second argument should be a path to a test command +taking a file as last argument. If the command, launched against +a tempfile containing the passed string, returns a non-null value, +compilation will abort with a parse error. + +If a third argument is specified, this will be the error message raised and +seen by the user. + +A helpful error message can be returned like this: + +Example: + + validate_cmd($sudoerscontent, '/usr/sbin/visudo -c -f', 'Visudo failed to validate sudoers content') + + + +- *Type*: statement + +validate_hash +------------- +Validate that all passed values are hash data structures. Abort catalog +compilation if any value fails this check. + +The following values will pass: + + $my_hash = { 'one' => 'two' } + validate_hash($my_hash) + +The following values will fail, causing compilation to abort: + + validate_hash(true) + validate_hash('some_string') + $undefined = undef + validate_hash($undefined) + + + +- *Type*: statement + +validate_re +----------- +Perform simple validation of a string against one or more regular +expressions. The first argument of this function should be a string to +test, and the second argument should be a stringified regular expression +(without the // delimiters) or an array of regular expressions. If none +of the regular expressions match the string passed in, compilation will +abort with a parse error. + +If a third argument is specified, this will be the error message raised and +seen by the user. + +The following strings will validate against the regular expressions: + + validate_re('one', '^one$') + validate_re('one', [ '^one', '^two' ]) + +The following strings will fail to validate, causing compilation to abort: + + validate_re('one', [ '^two', '^three' ]) + +A helpful error message can be returned like this: + + validate_re($::puppetversion, '^2.7', 'The $puppetversion fact value does not match 2.7') + + + +- *Type*: statement + +validate_slength +---------------- +Validate that the first argument is a string (or an array of strings), and +less/equal to than the length of the second argument. It fails if the first +argument is not a string or array of strings, and if arg 2 is not convertable +to a number. + +The following values will pass: + + validate_slength("discombobulate",17) + validate_slength(["discombobulate","moo"],17) + +The following valueis will not: + + validate_slength("discombobulate",1) + validate_slength(["discombobulate","thermometer"],5) + + + +- *Type*: statement + +validate_string +--------------- +Validate that all passed values are string data structures. Abort catalog +compilation if any value fails this check. + +The following values will pass: + + $my_string = "one two" + validate_string($my_string, 'three') + +The following values will fail, causing compilation to abort: + + validate_string(true) + validate_string([ 'some', 'array' ]) + $undefined = undef + validate_string($undefined) + + +- *Type*: statement + +values +------ +When given a hash this function will return the values of that hash. + +*Examples:* + + $hash = { + 'a' => 1, + 'b' => 2, + 'c' => 3, + } + values($hash) + +This example would return: + + [1,2,3] + + +- *Type*: rvalue + +values_at +--------- +Finds value inside an array based on location. + +The first argument is the array you want to analyze, and the second element can +be a combination of: + +* A single numeric index +* A range in the form of 'start-stop' (eg. 4-9) +* An array combining the above + +*Examples*: + + values_at(['a','b','c'], 2) + +Would return ['c']. + + values_at(['a','b','c'], ["0-1"]) + +Would return ['a','b']. + + values_at(['a','b','c','d','e'], [0, "2-3"]) + +Would return ['a','c','d']. + - * getvar - * has\_key - * loadyaml - * merge.rb - * validate\_array - * validate\_bool - * validate\_hash - * validate\_re - * validate\_string +- *Type*: rvalue -## validate\_hash ## +zip +--- +Takes one element from first array and merges corresponding elements from second array. This generates a sequence of n-element arrays, where n is one more than the count of arguments. - $somehash = { 'one' => 'two' } - validate\_hash($somehash) +*Example:* -## getvar() ## + zip(['1','2','3'],['4','5','6']) -This function aims to look up variables in user-defined namespaces within -puppet. Note, if the namespace is a class, it should already be evaluated -before the function is used. +Would result in: - $namespace = 'site::data' - include "${namespace}" - $myvar = getvar("${namespace}::myvar") + ["1", "4"], ["2", "5"], ["3", "6"] -## Facts ## -Facts in `/etc/facter/facts.d` and `/etc/puppetlabs/facter/facts.d` are now loaded -automatically. This is a direct copy of R.I. Pienaar's custom facter fact -located at: -[https://github.com/ripienaar/facter-facts/tree/master/facts-dot-d](https://github.com/ripienaar/facter-facts/tree/master/facts-dot-d) +- *Type*: rvalue +*This page autogenerated on 2013-04-11 13:54:25 -0700* diff --git a/puppet/modules/stdlib/README_DEVELOPER.markdown b/puppet/modules/stdlib/README_DEVELOPER.markdown old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/README_SPECS.markdown b/puppet/modules/stdlib/README_SPECS.markdown new file mode 100755 index 0000000..917b631 --- /dev/null +++ b/puppet/modules/stdlib/README_SPECS.markdown @@ -0,0 +1,7 @@ +NOTE +==== + +This project's specs depend on puppet core, and thus they require the +`puppetlabs_spec_helper` project. For more information please see the README +in that project, which can be found here: [puppetlabs spec +helper](https://github.com/puppetlabs/puppetlabs_spec_helper) diff --git a/puppet/modules/stdlib/RELEASE_PROCESS.markdown b/puppet/modules/stdlib/RELEASE_PROCESS.markdown old mode 100644 new mode 100755 index 3982c84..0f9328e --- a/puppet/modules/stdlib/RELEASE_PROCESS.markdown +++ b/puppet/modules/stdlib/RELEASE_PROCESS.markdown @@ -22,4 +22,3 @@ * Build a new package with puppet-module or the rake build task if it exists * Publish the new package to the forge * Bonus points for an announcement to puppet-users. - diff --git a/puppet/modules/stdlib/Rakefile b/puppet/modules/stdlib/Rakefile old mode 100644 new mode 100755 index 01b2a31..14f1c24 --- a/puppet/modules/stdlib/Rakefile +++ b/puppet/modules/stdlib/Rakefile @@ -1,16 +1,2 @@ -require 'rake' -require 'rspec/core/rake_task' - -task :default => [:test] - -desc 'Run RSpec' -RSpec::Core::RakeTask.new(:test) do |t| - t.pattern = 'spec/{unit}/**/*.rb' - t.rspec_opts = ['--color'] -end - -desc 'Generate code coverage' -RSpec::Core::RakeTask.new(:coverage) do |t| - t.rcov = true - t.rcov_opts = ['--exclude', 'spec'] -end +require 'rubygems' +require 'puppetlabs_spec_helper/rake_tasks' diff --git a/puppet/modules/stdlib/lib/facter/facter_dot_d.rb b/puppet/modules/stdlib/lib/facter/facter_dot_d.rb old mode 100644 new mode 100755 index c43801c..e414b20 --- a/puppet/modules/stdlib/lib/facter/facter_dot_d.rb +++ b/puppet/modules/stdlib/lib/facter/facter_dot_d.rb @@ -13,181 +13,190 @@ # fact scripts more often than is needed class Facter::Util::DotD - require 'yaml' + require 'yaml' - def initialize(dir="/etc/facts.d", cache_file="/tmp/facts_cache.yml") - @dir = dir - @cache_file = cache_file - @cache = nil - @types = {".txt" => :txt, ".json" => :json, ".yaml" => :yaml} - end + def initialize(dir="/etc/facts.d", cache_file="/tmp/facts_cache.yml") + @dir = dir + @cache_file = cache_file + @cache = nil + @types = {".txt" => :txt, ".json" => :json, ".yaml" => :yaml} + end - def entries - Dir.entries(@dir).reject{|f| f =~ /^\.|\.ttl$/}.sort.map {|f| File.join(@dir, f) } - rescue - [] - end + def entries + Dir.entries(@dir).reject{|f| f =~ /^\.|\.ttl$/}.sort.map {|f| File.join(@dir, f) } + rescue + [] + end - def fact_type(file) - extension = File.extname(file) + def fact_type(file) + extension = File.extname(file) - type = @types[extension] || :unknown + type = @types[extension] || :unknown - type = :script if type == :unknown && File.executable?(file) + type = :script if type == :unknown && File.executable?(file) - return type - end + return type + end - def txt_parser(file) - File.readlines(file).each do |line| - if line =~ /^(.+)=(.+)$/ - var = $1; val = $2 + def txt_parser(file) + File.readlines(file).each do |line| + if line =~ /^(.+)=(.+)$/ + var = $1; val = $2 - Facter.add(var) do - setcode { val } - end - end + Facter.add(var) do + setcode { val } end - rescue Exception => e - Facter.warn("Failed to handle #{file} as text facts: #{e.class}: #{e}") + end end - - def json_parser(file) - begin - require 'json' - rescue LoadError - retry if require 'rubygems' - raise - end - - JSON.load(File.read(file)).each_pair do |f, v| - Facter.add(f) do - setcode { v } - end - end - rescue Exception => e - Facter.warn("Failed to handle #{file} as json facts: #{e.class}: #{e}") + rescue Exception => e + Facter.warn("Failed to handle #{file} as text facts: #{e.class}: #{e}") + end + + def json_parser(file) + begin + require 'json' + rescue LoadError + retry if require 'rubygems' + raise end - def yaml_parser(file) - require 'yaml' - - YAML.load_file(file).each_pair do |f, v| - Facter.add(f) do - setcode { v } - end - end - rescue Exception => e - Facter.warn("Failed to handle #{file} as yaml facts: #{e.class}: #{e}") + JSON.load(File.read(file)).each_pair do |f, v| + Facter.add(f) do + setcode { v } + end end + rescue Exception => e + Facter.warn("Failed to handle #{file} as json facts: #{e.class}: #{e}") + end - def script_parser(file) - result = cache_lookup(file) - ttl = cache_time(file) - - unless result - result = Facter::Util::Resolution.exec(file) - - if ttl > 0 - Facter.debug("Updating cache for #{file}") - cache_store(file, result) - cache_save! - end - else - Puppet.deprecation_warning("TTL for external facts is being removed. See http://links.puppetlabs.com/factercaching for more information.") - Facter.debug("Using cached data for #{file}") - end - - result.split("\n").each do |line| - if line =~ /^(.+)=(.+)$/ - var = $1; val = $2 + def yaml_parser(file) + require 'yaml' - Facter.add(var) do - setcode { val } - end - end - end - rescue Exception => e - Facter.warn("Failed to handle #{file} as script facts: #{e.class}: #{e}") - Facter.debug(e.backtrace.join("\n\t")) + YAML.load_file(file).each_pair do |f, v| + Facter.add(f) do + setcode { v } + end end - - def cache_save! - cache = load_cache - File.open(@cache_file, "w", 0600) {|f| f.write(YAML.dump(cache)) } - rescue + rescue Exception => e + Facter.warn("Failed to handle #{file} as yaml facts: #{e.class}: #{e}") + end + + def script_parser(file) + result = cache_lookup(file) + ttl = cache_time(file) + + unless result + result = Facter::Util::Resolution.exec(file) + + if ttl > 0 + Facter.debug("Updating cache for #{file}") + cache_store(file, result) + cache_save! + end + else + Facter.debug("Using cached data for #{file}") end - def cache_store(file, data) - load_cache + result.split("\n").each do |line| + if line =~ /^(.+)=(.+)$/ + var = $1; val = $2 - @cache[file] = {:data => data, :stored => Time.now.to_i} - rescue + Facter.add(var) do + setcode { val } + end + end end + rescue Exception => e + Facter.warn("Failed to handle #{file} as script facts: #{e.class}: #{e}") + Facter.debug(e.backtrace.join("\n\t")) + end - def cache_lookup(file) - cache = load_cache + def cache_save! + cache = load_cache + File.open(@cache_file, "w", 0600) {|f| f.write(YAML.dump(cache)) } + rescue + end - return nil if cache.empty? + def cache_store(file, data) + load_cache - ttl = cache_time(file) + @cache[file] = {:data => data, :stored => Time.now.to_i} + rescue + end - if cache[file] - now = Time.now.to_i - - return cache[file][:data] if ttl == -1 - return cache[file][:data] if (now - cache[file][:stored]) <= ttl - return nil - else - return nil - end - rescue - return nil - end + def cache_lookup(file) + cache = load_cache - def cache_time(file) - meta = file + ".ttl" + return nil if cache.empty? - return File.read(meta).chomp.to_i - rescue - return 0 - end + ttl = cache_time(file) - def load_cache - unless @cache - if File.exist?(@cache_file) - @cache = YAML.load_file(@cache_file) - else - @cache = {} - end - end + if cache[file] + now = Time.now.to_i - return @cache - rescue + return cache[file][:data] if ttl == -1 + return cache[file][:data] if (now - cache[file][:stored]) <= ttl + return nil + else + return nil + end + rescue + return nil + end + + def cache_time(file) + meta = file + ".ttl" + + return File.read(meta).chomp.to_i + rescue + return 0 + end + + def load_cache + unless @cache + if File.exist?(@cache_file) + @cache = YAML.load_file(@cache_file) + else @cache = {} - return @cache + end end - def create - entries.each do |fact| - type = fact_type(fact) - parser = "#{type}_parser" + return @cache + rescue + @cache = {} + return @cache + end - if respond_to?("#{type}_parser") - Facter.debug("Parsing #{fact} using #{parser}") + def create + entries.each do |fact| + type = fact_type(fact) + parser = "#{type}_parser" - send(parser, fact) - end - end + if respond_to?("#{type}_parser") + Facter.debug("Parsing #{fact} using #{parser}") + + send(parser, fact) + end end + end end -Facter::Util::DotD.new("/etc/facter/facts.d").create -Facter::Util::DotD.new("/etc/puppetlabs/facter/facts.d").create -# Windows has a different configuration directory that defaults to a vendor -# specific sub directory of the %COMMON_APPDATA% directory. -if Dir.const_defined? 'COMMON_APPDATA' then - windows_facts_dot_d = File.join(Dir::COMMON_APPDATA, 'PuppetLabs', 'facter', 'facts.d') - Facter::Util::DotD.new(windows_facts_dot_d).create +mdata = Facter.version.match(/(\d+)\.(\d+)\.(\d+)/) +if mdata + (major, minor, patch) = mdata.captures.map { |v| v.to_i } + if major < 2 + # Facter 1.7 introduced external facts support directly + unless major == 1 and minor > 6 + Facter::Util::DotD.new("/etc/facter/facts.d").create + Facter::Util::DotD.new("/etc/puppetlabs/facter/facts.d").create + + # Windows has a different configuration directory that defaults to a vendor + # specific sub directory of the %COMMON_APPDATA% directory. + if Dir.const_defined? 'COMMON_APPDATA' then + windows_facts_dot_d = File.join(Dir::COMMON_APPDATA, 'PuppetLabs', 'facter', 'facts.d') + Facter::Util::DotD.new(windows_facts_dot_d).create + end + end + end end diff --git a/puppet/modules/stdlib/lib/facter/pe_version.rb b/puppet/modules/stdlib/lib/facter/pe_version.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/facter/puppet_vardir.rb b/puppet/modules/stdlib/lib/facter/puppet_vardir.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/facter/root_home.rb b/puppet/modules/stdlib/lib/facter/root_home.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/facter/util/puppet_settings.rb b/puppet/modules/stdlib/lib/facter/util/puppet_settings.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/abs.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/abs.rb old mode 100644 new mode 100755 index ade5462..11d2d7f --- a/puppet/modules/stdlib/lib/puppet/parser/functions/abs.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/abs.rb @@ -4,7 +4,7 @@ module Puppet::Parser::Functions newfunction(:abs, :type => :rvalue, :doc => <<-EOS - Returns the absolute value of a number, for example -34.56 becomes + Returns the absolute value of a number, for example -34.56 becomes 34.56. Takes a single integer and float value as an argument. EOS ) do |arguments| diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/any2array.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/any2array.rb new file mode 100755 index 0000000..e71407e --- /dev/null +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/any2array.rb @@ -0,0 +1,33 @@ +# +# any2array.rb +# + +module Puppet::Parser::Functions + newfunction(:any2array, :type => :rvalue, :doc => <<-EOS +This converts any object to an array containing that object. Empty argument +lists are converted to an empty array. Arrays are left untouched. Hashes are +converted to arrays of alternating keys and values. + EOS + ) do |arguments| + + if arguments.empty? + return [] + end + + if arguments.length == 1 + if arguments[0].kind_of?(Array) + return arguments[0] + elsif arguments[0].kind_of?(Hash) + result = [] + arguments[0].each do |key, value| + result << key << value + end + return result + end + end + + return arguments + end +end + +# vim: set ts=2 sw=2 et : diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/bool2num.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/bool2num.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/capitalize.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/capitalize.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/chomp.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/chomp.rb old mode 100644 new mode 100755 index c99d139..4564a00 --- a/puppet/modules/stdlib/lib/puppet/parser/functions/chomp.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/chomp.rb @@ -4,7 +4,7 @@ module Puppet::Parser::Functions newfunction(:chomp, :type => :rvalue, :doc => <<-'EOS' - Removes the record separator from the end of a string or an array of + Removes the record separator from the end of a string or an array of strings, for example `hello\n` becomes `hello`. Requires a single string or array as an input. EOS diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/chop.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/chop.rb old mode 100644 new mode 100755 index 636b990..f242af3 --- a/puppet/modules/stdlib/lib/puppet/parser/functions/chop.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/chop.rb @@ -4,9 +4,9 @@ module Puppet::Parser::Functions newfunction(:chop, :type => :rvalue, :doc => <<-'EOS' - Returns a new string with the last character removed. If the string ends - with `\r\n`, both characters are removed. Applying chop to an empty - string returns an empty string. If you wish to merely remove record + Returns a new string with the last character removed. If the string ends + with `\r\n`, both characters are removed. Applying chop to an empty + string returns an empty string. If you wish to merely remove record separators then you should use the `chomp` function. Requires a string or array of strings as input. EOS diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/concat.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/concat.rb new file mode 100755 index 0000000..c86aa00 --- /dev/null +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/concat.rb @@ -0,0 +1,37 @@ +# +# concat.rb +# + +module Puppet::Parser::Functions + newfunction(:concat, :type => :rvalue, :doc => <<-EOS +Appends the contents of array 2 onto array 1. + +*Example:* + + concat(['1','2','3'],['4','5','6']) + +Would result in: + + ['1','2','3','4','5','6'] + EOS + ) do |arguments| + + # Check that 2 arguments have been given ... + raise(Puppet::ParseError, "concat(): Wrong number of arguments " + + "given (#{arguments.size} for 2)") if arguments.size != 2 + + a = arguments[0] + b = arguments[1] + + # Check that both args are arrays. + unless a.is_a?(Array) and b.is_a?(Array) + raise(Puppet::ParseError, 'concat(): Requires array to work with') + end + + result = a.concat(b) + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/count.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/count.rb new file mode 100755 index 0000000..52de1b8 --- /dev/null +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/count.rb @@ -0,0 +1,22 @@ +module Puppet::Parser::Functions + newfunction(:count, :type => :rvalue, :arity => -2, :doc => <<-EOS +Takes an array as first argument and an optional second argument. +Count the number of elements in array that matches second argument. +If called with only an array it counts the number of elements that are not nil/undef. + EOS + ) do |args| + + if (args.size > 2) then + raise(ArgumentError, "count(): Wrong number of arguments "+ + "given #{args.size} for 1 or 2.") + end + + collection, item = args + + if item then + collection.count item + else + collection.count { |obj| obj != nil && obj != :undef && obj != '' } + end + end +end diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/defined_with_params.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/defined_with_params.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/delete.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/delete.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/delete_at.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/delete_at.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/dirname.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/dirname.rb new file mode 100755 index 0000000..ea8cc1e --- /dev/null +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/dirname.rb @@ -0,0 +1,15 @@ +module Puppet::Parser::Functions + newfunction(:dirname, :type => :rvalue, :doc => <<-EOS + Returns the dirname of a path. + EOS + ) do |arguments| + + raise(Puppet::ParseError, "dirname(): Wrong number of arguments " + + "given (#{arguments.size} for 1)") if arguments.size < 1 + + path = arguments[0] + return File.dirname(path) + end +end + +# vim: set ts=2 sw=2 et : diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/downcase.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/downcase.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/empty.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/empty.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/ensure_packages.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/ensure_packages.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/ensure_resource.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/ensure_resource.rb old mode 100644 new mode 100755 index fba2035..a9a1733 --- a/puppet/modules/stdlib/lib/puppet/parser/functions/ensure_resource.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/ensure_resource.rb @@ -19,17 +19,27 @@ this function will attempt to recreate the resource leading to a duplicate resource definition error. +An array of resources can also be passed in and each will be created with +the type and parameters specified if it doesn't already exist. + + ensure_resource('user', ['dan','alex'], {'ensure' => 'present'}) + ENDOFDOC ) do |vals| type, title, params = vals raise(ArgumentError, 'Must specify a type') unless type raise(ArgumentError, 'Must specify a title') unless title params ||= {} - Puppet::Parser::Functions.function(:defined_with_params) - if function_defined_with_params(["#{type}[#{title}]", params]) - Puppet.debug("Resource #{type}[#{title}] not created b/c it already exists") - else - Puppet::Parser::Functions.function(:create_resources) - function_create_resources([type.capitalize, { title => params }]) + + items = [title].flatten + + items.each do |item| + Puppet::Parser::Functions.function(:defined_with_params) + if function_defined_with_params(["#{type}[#{item}]", params]) + Puppet.debug("Resource #{type}[#{item}] not created because it already exists") + else + Puppet::Parser::Functions.function(:create_resources) + function_create_resources([type.capitalize, { item => params }]) + end end end diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/flatten.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/flatten.rb old mode 100644 new mode 100755 index 781da78..a1ed183 --- a/puppet/modules/stdlib/lib/puppet/parser/functions/flatten.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/flatten.rb @@ -16,7 +16,7 @@ module Puppet::Parser::Functions ) do |arguments| raise(Puppet::ParseError, "flatten(): Wrong number of arguments " + - "given (#{arguments.size} for 1)") if arguments.size < 1 + "given (#{arguments.size} for 1)") if arguments.size != 1 array = arguments[0] diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/floor.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/floor.rb new file mode 100755 index 0000000..a401923 --- /dev/null +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/floor.rb @@ -0,0 +1,20 @@ +module Puppet::Parser::Functions + newfunction(:floor, :type => :rvalue, :doc => <<-EOS + Returns the largest integer less or equal to the argument. + Takes a single numeric value as an argument. + EOS + ) do |arguments| + + raise(Puppet::ParseError, "floor(): Wrong number of arguments " + + "given (#{arguments.size} for 1)") if arguments.size != 1 + + arg = arguments[0] + + raise(Puppet::ParseError, "floor(): Wrong argument type " + + "given (#{arg.class} for Numeric)") if arg.is_a?(Numeric) == false + + arg.floor + end +end + +# vim: set ts=2 sw=2 et : diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/fqdn_rotate.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/fqdn_rotate.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/get_module_path.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/get_module_path.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/getparam.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/getparam.rb new file mode 100755 index 0000000..6d51006 --- /dev/null +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/getparam.rb @@ -0,0 +1,35 @@ +# Test whether a given class or definition is defined +require 'puppet/parser/functions' + +Puppet::Parser::Functions.newfunction(:getparam, + :type => :rvalue, + :doc => <<-'ENDOFDOC' +Takes a resource reference and name of the parameter and +returns value of resource's parameter. + +*Examples:* + + define example_resource($param) { + } + + example_resource { "example_resource_instance": + param => "param_value" + } + + getparam(Example_resource["example_resource_instance"], "param") + +Would return: param_value +ENDOFDOC +) do |vals| + reference, param = vals + raise(ArgumentError, 'Must specify a reference') unless reference + raise(ArgumentError, 'Must specify name of a parameter') unless param and param.instance_of? String + + return '' if param.empty? + + if resource = findresource(reference.to_s) + return resource[param] if resource[param] + end + + return '' +end diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/getvar.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/getvar.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/grep.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/grep.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/has_interface_with.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/has_interface_with.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/has_ip_address.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/has_ip_address.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/has_ip_network.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/has_ip_network.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/has_key.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/has_key.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/hash.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/hash.rb old mode 100644 new mode 100755 index 453ba1e..8cc4823 --- a/puppet/modules/stdlib/lib/puppet/parser/functions/hash.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/hash.rb @@ -4,7 +4,7 @@ module Puppet::Parser::Functions newfunction(:hash, :type => :rvalue, :doc => <<-EOS -This function converts and array into a hash. +This function converts an array into a hash. *Examples:* diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_array.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_array.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_domain_name.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_domain_name.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_float.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_float.rb old mode 100644 new mode 100755 index 2fc05ba..911f3c2 --- a/puppet/modules/stdlib/lib/puppet/parser/functions/is_float.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_float.rb @@ -15,7 +15,7 @@ module Puppet::Parser::Functions value = arguments[0] - if value != value.to_f.to_s then + if value != value.to_f.to_s and !value.is_a? Float then return false else return true diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_function_available.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_function_available.rb new file mode 100755 index 0000000..6cbd35c --- /dev/null +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_function_available.rb @@ -0,0 +1,23 @@ +# +# is_function_available.rb +# + +module Puppet::Parser::Functions + newfunction(:is_function_available, :type => :rvalue, :doc => <<-EOS +This function accepts a string as an argument, determines whether the +Puppet runtime has access to a function by that name. It returns a +true if the function exists, false if not. + EOS + ) do |arguments| + + if (arguments.size != 1) then + raise(Puppet::ParseError, "is_function_available?(): Wrong number of arguments "+ + "given #{arguments.size} for 1") + end + + function = Puppet::Parser::Functions.function(arguments[0].to_sym) + function.is_a?(String) and not function.empty? + end +end + +# vim: set ts=2 sw=2 et : diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_hash.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_hash.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_integer.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_integer.rb old mode 100644 new mode 100755 index 8ee34f6..6b29e98 --- a/puppet/modules/stdlib/lib/puppet/parser/functions/is_integer.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_integer.rb @@ -15,7 +15,7 @@ module Puppet::Parser::Functions value = arguments[0] - if value != value.to_i.to_s then + if value != value.to_i.to_s and !value.is_a? Fixnum then return false else return true diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_ip_address.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_ip_address.rb old mode 100644 new mode 100755 index b4a9a15..a90adab --- a/puppet/modules/stdlib/lib/puppet/parser/functions/is_ip_address.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_ip_address.rb @@ -15,7 +15,7 @@ module Puppet::Parser::Functions "given #{arguments.size} for 1") end - begin + begin ip = IPAddr.new(arguments[0]) rescue ArgumentError return false diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_mac_address.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_mac_address.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_numeric.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_numeric.rb old mode 100644 new mode 100755 index ce13ece..abf0321 --- a/puppet/modules/stdlib/lib/puppet/parser/functions/is_numeric.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/is_numeric.rb @@ -15,7 +15,7 @@ module Puppet::Parser::Functions value = arguments[0] - if value == value.to_f.to_s or value == value.to_i.to_s then + if value == value.to_f.to_s or value == value.to_i.to_s or value.is_a? Numeric then return true else return false diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/is_string.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/is_string.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/join.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/join.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/join_keys_to_values.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/join_keys_to_values.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/keys.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/keys.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/loadyaml.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/loadyaml.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/lstrip.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/lstrip.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/max.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/max.rb old mode 100644 new mode 100755 index 10b6f74..60fb94a --- a/puppet/modules/stdlib/lib/puppet/parser/functions/max.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/max.rb @@ -8,6 +8,14 @@ module Puppet::Parser::Functions raise(Puppet::ParseError, "max(): Wrong number of arguments " + "need at least one") if args.size == 0 - return args.max + # Sometimes we get numbers as numerics and sometimes as strings. + # We try to compare them as numbers when possible + return args.max do |a,b| + if a.to_s =~ /\A-?\d+(.\d+)?\z/ and b.to_s =~ /\A-?\d+(.\d+)?\z/ then + a.to_f <=> b.to_f + else + a.to_s <=> b.to_s + end + end end end diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/member.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/member.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/merge.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/merge.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/min.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/min.rb old mode 100644 new mode 100755 index abf1b62..6bd6ebf --- a/puppet/modules/stdlib/lib/puppet/parser/functions/min.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/min.rb @@ -8,6 +8,14 @@ module Puppet::Parser::Functions raise(Puppet::ParseError, "min(): Wrong number of arguments " + "need at least one") if args.size == 0 - return args.min + # Sometimes we get numbers as numerics and sometimes as strings. + # We try to compare them as numbers when possible + return args.min do |a,b| + if a.to_s =~ /\A^-?\d+(.\d+)?\z/ and b.to_s =~ /\A-?\d+(.\d+)?\z/ then + a.to_f <=> b.to_f + else + a.to_s <=> b.to_s + end + end end end diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/num2bool.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/num2bool.rb old mode 100644 new mode 100755 index 874db22..af0e6ed --- a/puppet/modules/stdlib/lib/puppet/parser/functions/num2bool.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/num2bool.rb @@ -2,38 +2,41 @@ # num2bool.rb # -# TODO(Krzysztof Wilczynski): We probably need to approach numeric values differently ... - module Puppet::Parser::Functions newfunction(:num2bool, :type => :rvalue, :doc => <<-EOS -This function converts a number into a true boolean. Zero becomes false. Numbers -higher then 0 become true. +This function converts a number or a string representation of a number into a +true boolean. Zero or anything non-numeric becomes false. Numbers higher then 0 +become true. EOS ) do |arguments| raise(Puppet::ParseError, "num2bool(): Wrong number of arguments " + - "given (#{arguments.size} for 1)") if arguments.size < 1 + "given (#{arguments.size} for 1)") if arguments.size != 1 number = arguments[0] - # Only numbers allowed ... - unless number.match(/^\-?\d+$/) - raise(Puppet::ParseError, 'num2bool(): Requires integer to work with') + case number + when Numeric + # Yay, it's a number + when String + begin + number = Float(number) + rescue ArgumentError => ex + raise(Puppet::ParseError, "num2bool(): '#{number}' does not look like a number: #{ex.message}") + end + else + begin + number = number.to_s + rescue NoMethodError => ex + raise(Puppet::ParseError, "num2bool(): Unable to parse argument: #{ex.message}") + end end - result = case number - when /^0$/ - false - when /^\-?\d+$/ - # Numbers in Puppet are often string-encoded which is troublesome ... - number = number.to_i - # We yield true for any positive number and false otherwise ... - number > 0 ? true : false - else - raise(Puppet::ParseError, 'num2bool(): Unknown numeric format given') - end + # Truncate Floats + number = number.to_i - return result + # Return true for any positive number and false otherwise + return number > 0 end end diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/parsejson.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/parsejson.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/parseyaml.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/parseyaml.rb old mode 100644 new mode 100755 index e8ac8a4..53d54fa --- a/puppet/modules/stdlib/lib/puppet/parser/functions/parseyaml.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/parseyaml.rb @@ -4,7 +4,7 @@ module Puppet::Parser::Functions newfunction(:parseyaml, :type => :rvalue, :doc => <<-EOS -This function accepts YAML as a string and converts it into the correct +This function accepts YAML as a string and converts it into the correct Puppet structure. EOS ) do |arguments| diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/pick.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/pick.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/prefix.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/prefix.rb old mode 100644 new mode 100755 index 4593976..62211ae --- a/puppet/modules/stdlib/lib/puppet/parser/functions/prefix.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/prefix.rb @@ -6,7 +6,7 @@ module Puppet::Parser::Functions newfunction(:prefix, :type => :rvalue, :doc => <<-EOS This function applies a prefix to all elements in an array. -*Examles:* +*Examples:* prefix(['a','b','c'], 'p') @@ -21,14 +21,14 @@ module Puppet::Parser::Functions array = arguments[0] unless array.is_a?(Array) - raise(Puppet::ParseError, 'prefix(): Requires array to work with') + raise Puppet::ParseError, "prefix(): expected first argument to be an Array, got #{array.inspect}" end prefix = arguments[1] if arguments[1] if prefix unless prefix.is_a?(String) - raise(Puppet::ParseError, 'prefix(): Requires string to work with') + raise Puppet::ParseError, "prefix(): expected second argument to be a String, got #{suffix.inspect}" end end diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/range.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/range.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/reject.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/reject.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/reverse.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/reverse.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/rstrip.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/rstrip.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/shuffle.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/shuffle.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/size.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/size.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/sort.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/sort.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/squeeze.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/squeeze.rb old mode 100644 new mode 100755 index 65c174a..81fadfd --- a/puppet/modules/stdlib/lib/puppet/parser/functions/squeeze.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/squeeze.rb @@ -14,9 +14,9 @@ module Puppet::Parser::Functions end item = arguments[0] - squeezeval = arguments[1] + squeezeval = arguments[1] - if item.is_a?(Array) then + if item.is_a?(Array) then if squeezeval then item.collect { |i| i.squeeze(squeezeval) } else diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/str2bool.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/str2bool.rb old mode 100644 new mode 100755 index c320da6..fece7a6 --- a/puppet/modules/stdlib/lib/puppet/parser/functions/str2bool.rb +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/str2bool.rb @@ -4,7 +4,7 @@ module Puppet::Parser::Functions newfunction(:str2bool, :type => :rvalue, :doc => <<-EOS -This converts a string to a boolean. This attempt to convert strings that +This converts a string to a boolean. This attempt to convert strings that contain things like: y, 1, t, true to 'true' and strings that contain things like: 0, f, n, false, no to 'false'. EOS @@ -14,6 +14,11 @@ module Puppet::Parser::Functions "given (#{arguments.size} for 1)") if arguments.size < 1 string = arguments[0] + + # If string is already Boolean, return it + if !!string == string + return string + end unless string.is_a?(String) raise(Puppet::ParseError, 'str2bool(): Requires either ' + diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/str2saltedsha512.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/str2saltedsha512.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/strftime.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/strftime.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/strip.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/strip.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/suffix.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/suffix.rb new file mode 100755 index 0000000..f7792d6 --- /dev/null +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/suffix.rb @@ -0,0 +1,45 @@ +# +# suffix.rb +# + +module Puppet::Parser::Functions + newfunction(:suffix, :type => :rvalue, :doc => <<-EOS +This function applies a suffix to all elements in an array. + +*Examples:* + + suffix(['a','b','c'], 'p') + +Will return: ['ap','bp','cp'] + EOS + ) do |arguments| + + # Technically we support two arguments but only first is mandatory ... + raise(Puppet::ParseError, "suffix(): Wrong number of arguments " + + "given (#{arguments.size} for 1)") if arguments.size < 1 + + array = arguments[0] + + unless array.is_a?(Array) + raise Puppet::ParseError, "suffix(): expected first argument to be an Array, got #{array.inspect}" + end + + suffix = arguments[1] if arguments[1] + + if suffix + unless suffix.is_a? String + raise Puppet::ParseError, "suffix(): expected second argument to be a String, got #{suffix.inspect}" + end + end + + # Turn everything into string same as join would do ... + result = array.collect do |i| + i = i.to_s + suffix ? i + suffix : i + end + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/swapcase.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/swapcase.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/time.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/time.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/to_bytes.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/to_bytes.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/type.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/type.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/unique.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/unique.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/upcase.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/upcase.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/uriescape.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/uriescape.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_absolute_path.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_absolute_path.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_array.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_array.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_augeas.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_augeas.rb new file mode 100755 index 0000000..154d660 --- /dev/null +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_augeas.rb @@ -0,0 +1,81 @@ +module Puppet::Parser::Functions + newfunction(:validate_augeas, :doc => <<-'ENDHEREDOC') do |args| + Perform validation of a string using an Augeas lens + The first argument of this function should be a string to + test, and the second argument should be the name of the Augeas lens to use. + If Augeas fails to parse the string with the lens, the compilation will + abort with a parse error. + + A third argument can be specified, listing paths which should + not be found in the file. The `$file` variable points to the location + of the temporary file being tested in the Augeas tree. + + For example, if you want to make sure your passwd content never contains + a user `foo`, you could write: + + validate_augeas($passwdcontent, 'Passwd.lns', ['$file/foo']) + + Or if you wanted to ensure that no users used the '/bin/barsh' shell, + you could use: + + validate_augeas($passwdcontent, 'Passwd.lns', ['$file/*[shell="/bin/barsh"]'] + + If a fourth argument is specified, this will be the error message raised and + seen by the user. + + A helpful error message can be returned like this: + + validate_augeas($sudoerscontent, 'Sudoers.lns', [], 'Failed to validate sudoers content with Augeas') + + ENDHEREDOC + unless Puppet.features.augeas? + raise Puppet::ParseError, ("validate_augeas(): this function requires the augeas feature. See http://projects.puppetlabs.com/projects/puppet/wiki/Puppet_Augeas#Pre-requisites for how to activate it.") + end + + if (args.length < 2) or (args.length > 4) then + raise Puppet::ParseError, ("validate_augeas(): wrong number of arguments (#{args.length}; must be 2, 3, or 4)") + end + + msg = args[3] || "validate_augeas(): Failed to validate content against #{args[1].inspect}" + + require 'augeas' + aug = Augeas::open(nil, nil, Augeas::NO_MODL_AUTOLOAD) + begin + content = args[0] + + # Test content in a temporary file + tmpfile = Tempfile.new("validate_augeas") + begin + tmpfile.write(content) + ensure + tmpfile.close + end + + # Check for syntax + lens = args[1] + aug.transform( + :lens => lens, + :name => 'Validate_augeas', + :incl => tmpfile.path + ) + aug.load! + + unless aug.match("/augeas/files#{tmpfile.path}//error").empty? + error = aug.get("/augeas/files#{tmpfile.path}//error/message") + msg += " with error: #{error}" + raise Puppet::ParseError, (msg) + end + + # Launch unit tests + tests = args[2] || [] + aug.defvar('file', "/files#{tmpfile.path}") + tests.each do |t| + msg += " testing path #{t}" + raise Puppet::ParseError, (msg) unless aug.match(t).empty? + end + ensure + aug.close + tmpfile.unlink + end + end +end diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_bool.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_bool.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_cmd.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_cmd.rb new file mode 100755 index 0000000..344a80c --- /dev/null +++ b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_cmd.rb @@ -0,0 +1,47 @@ +require 'puppet/util/execution' + +module Puppet::Parser::Functions + newfunction(:validate_cmd, :doc => <<-'ENDHEREDOC') do |args| + Perform validation of a string with an external command. + The first argument of this function should be a string to + test, and the second argument should be a path to a test command + taking a file as last argument. If the command, launched against + a tempfile containing the passed string, returns a non-null value, + compilation will abort with a parse error. + + If a third argument is specified, this will be the error message raised and + seen by the user. + + A helpful error message can be returned like this: + + Example: + + validate_cmd($sudoerscontent, '/usr/sbin/visudo -c -f', 'Visudo failed to validate sudoers content') + + ENDHEREDOC + if (args.length < 2) or (args.length > 3) then + raise Puppet::ParseError, ("validate_cmd(): wrong number of arguments (#{args.length}; must be 2 or 3)") + end + + msg = args[2] || "validate_cmd(): failed to validate content with command #{args[1].inspect}" + + content = args[0] + checkscript = args[1] + + # Test content in a temporary file + tmpfile = Tempfile.new("validate_cmd") + begin + tmpfile.write(content) + if Puppet::Util::Execution.respond_to?('execute') + Puppet::Util::Execution.execute("#{checkscript} #{tmpfile.path}") + else + Puppet::Util.execute("#{checkscript} #{tmpfile.path}") + end + rescue Puppet::ExecutionFailure => detail + msg += "\n#{detail}" + raise Puppet::ParseError, msg + ensure + tmpfile.unlink + end + end +end diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_hash.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_hash.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_re.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_re.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_slength.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_slength.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/validate_string.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/validate_string.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/values.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/values.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/values_at.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/values_at.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/parser/functions/zip.rb b/puppet/modules/stdlib/lib/puppet/parser/functions/zip.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/lib/puppet/provider/file_line/ruby.rb b/puppet/modules/stdlib/lib/puppet/provider/file_line/ruby.rb old mode 100644 new mode 100755 index e21eaa8..a3219d3 --- a/puppet/modules/stdlib/lib/puppet/provider/file_line/ruby.rb +++ b/puppet/modules/stdlib/lib/puppet/provider/file_line/ruby.rb @@ -34,7 +34,7 @@ def lines def handle_create_with_match() regex = resource[:match] ? Regexp.new(resource[:match]) : nil - match_count = lines.select { |l| regex.match(l) }.count + match_count = lines.select { |l| regex.match(l) }.size if match_count > 1 raise Puppet::Error, "More than one line in file '#{resource[:path]}' matches pattern '#{resource[:match]}'" end diff --git a/puppet/modules/stdlib/lib/puppet/type/anchor.rb b/puppet/modules/stdlib/lib/puppet/type/anchor.rb old mode 100644 new mode 100755 index 6b81732..fe1e5aa --- a/puppet/modules/stdlib/lib/puppet/type/anchor.rb +++ b/puppet/modules/stdlib/lib/puppet/type/anchor.rb @@ -38,4 +38,9 @@ class { 'mcollective': } -> class { 'ntp': } desc "The name of the anchor resource." end + def refresh + # We don't do anything with them, but we need this to + # show that we are "refresh aware" and not break the + # chain of propagation. + end end diff --git a/puppet/modules/stdlib/lib/puppet/type/file_line.rb b/puppet/modules/stdlib/lib/puppet/type/file_line.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/manifests/init.pp b/puppet/modules/stdlib/manifests/init.pp old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/manifests/stages.pp b/puppet/modules/stdlib/manifests/stages.pp old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/classes/anchor_spec.rb b/puppet/modules/stdlib/spec/classes/anchor_spec.rb new file mode 100755 index 0000000..2dd17de --- /dev/null +++ b/puppet/modules/stdlib/spec/classes/anchor_spec.rb @@ -0,0 +1,32 @@ +require 'puppet' +require 'rspec-puppet' + +describe "anchorrefresh" do + let(:node) { 'testhost.example.com' } + let :pre_condition do + <<-ANCHORCLASS +class anchored { + anchor { 'anchored::begin': } + ~> anchor { 'anchored::end': } +} + +class anchorrefresh { + notify { 'first': } + ~> class { 'anchored': } + ~> anchor { 'final': } +} + ANCHORCLASS + end + + def apply_catalog_and_return_exec_rsrc + catalog = subject.to_ral + transaction = catalog.apply + transaction.resource_status("Anchor[final]") + end + + it 'propagates events through the anchored class' do + resource = apply_catalog_and_return_exec_rsrc + + expect(resource.restarted).to eq(true) + end +end diff --git a/puppet/modules/stdlib/spec/functions/defined_with_params_spec.rb b/puppet/modules/stdlib/spec/functions/defined_with_params_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/functions/ensure_packages_spec.rb b/puppet/modules/stdlib/spec/functions/ensure_packages_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/functions/ensure_resource_spec.rb b/puppet/modules/stdlib/spec/functions/ensure_resource_spec.rb old mode 100644 new mode 100755 index 611666e..2e8aefc --- a/puppet/modules/stdlib/spec/functions/ensure_resource_spec.rb +++ b/puppet/modules/stdlib/spec/functions/ensure_resource_spec.rb @@ -4,17 +4,16 @@ require 'rspec-puppet' describe 'ensure_resource' do describe 'when a type or title is not specified' do - it do - should run.with_params().and_raise_error(ArgumentError) - should run.with_params(['type']).and_raise_error(ArgumentError) - end + it { should run.with_params().and_raise_error(ArgumentError) } + it { should run.with_params(['type']).and_raise_error(ArgumentError) } end + describe 'when compared against a resource with no attributes' do let :pre_condition do 'user { "dan": }' end - it do - should run.with_params('user', 'dan', {}) + it "should contain the the ensured resources" do + subject.should run.with_params('user', 'dan', {}) compiler.catalog.resource('User[dan]').to_s.should == 'User[dan]' end end @@ -23,18 +22,43 @@ let :pre_condition do 'user { "dan": ensure => present, shell => "/bin/csh", managehome => false}' end - it do - # these first three should not fail - should run.with_params('User', 'dan', {}) - should run.with_params('User', 'dan', '') - should run.with_params('User', 'dan', {'ensure' => 'present'}) - should run.with_params('User', 'dan', - {'ensure' => 'present', 'managehome' => false} - ) - # test that this fails - should run.with_params('User', 'dan', - {'ensure' => 'absent', 'managehome' => false} - ).and_raise_error(Puppet::Error) + # these first three should not fail + it { should run.with_params('User', 'dan', {}) } + it { should run.with_params('User', 'dan', '') } + it { should run.with_params('User', 'dan', {'ensure' => 'present'}) } + it { should run.with_params('User', 'dan', {'ensure' => 'present', 'managehome' => false}) } + # test that this fails + it { should run.with_params('User', 'dan', {'ensure' => 'absent', 'managehome' => false}).and_raise_error(Puppet::Error) } + end + + describe 'when an array of new resources are passed in' do + it "should contain the ensured resources" do + subject.should run.with_params('User', ['dan', 'alex'], {}) + compiler.catalog.resource('User[dan]').to_s.should == 'User[dan]' + compiler.catalog.resource('User[alex]').to_s.should == 'User[alex]' + end + end + + describe 'when an array of existing resources is compared against existing resources' do + let :pre_condition do + 'user { "dan": ensure => present; "alex": ensure => present }' + end + it "should return the existing resources" do + subject.should run.with_params('User', ['dan', 'alex'], {}) + compiler.catalog.resource('User[dan]').to_s.should == 'User[dan]' + compiler.catalog.resource('User[alex]').to_s.should == 'User[alex]' + end + end + + describe 'when compared against existing resources with attributes' do + let :pre_condition do + 'user { "dan": ensure => present; "alex": ensure => present }' end + # These should not fail + it { should run.with_params('User', ['dan', 'alex'], {}) } + it { should run.with_params('User', ['dan', 'alex'], '') } + it { should run.with_params('User', ['dan', 'alex'], {'ensure' => 'present'}) } + # This should fail + it { should run.with_params('User', ['dan', 'alex'], {'ensure' => 'absent'}).and_raise_error(Puppet::Error) } end end diff --git a/puppet/modules/stdlib/spec/functions/getparam_spec.rb b/puppet/modules/stdlib/spec/functions/getparam_spec.rb new file mode 100755 index 0000000..d9c50a6 --- /dev/null +++ b/puppet/modules/stdlib/spec/functions/getparam_spec.rb @@ -0,0 +1,34 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +require 'rspec-puppet' +describe 'getparam' do + describe 'when a resource is not specified' do + it do + should run.with_params().and_raise_error(ArgumentError) + should run.with_params('User[dan]').and_raise_error(ArgumentError) + should run.with_params('User[dan]', {}).and_raise_error(ArgumentError) + should run.with_params('User[dan]', '').and_return('') + end + end + describe 'when compared against a resource with no params' do + let :pre_condition do + 'user { "dan": }' + end + it do + should run.with_params('User[dan]', 'shell').and_return('') + end + end + + describe 'when compared against a resource with params' do + let :pre_condition do + 'user { "dan": ensure => present, shell => "/bin/sh", managehome => false}' + end + it do + should run.with_params('User[dan]', 'shell').and_return('/bin/sh') + should run.with_params('User[dan]', '').and_return('') + should run.with_params('User[dan]', 'ensure').and_return('present') + should run.with_params('User[dan]', 'managehome').and_return(false) + end + end +end diff --git a/puppet/modules/stdlib/spec/lib/puppet_spec/files.rb b/puppet/modules/stdlib/spec/lib/puppet_spec/files.rb deleted file mode 100755 index 30fb4fc..0000000 --- a/puppet/modules/stdlib/spec/lib/puppet_spec/files.rb +++ /dev/null @@ -1,53 +0,0 @@ -require 'fileutils' -require 'tempfile' - -# A support module for testing files. -module PuppetSpec::Files - # This code exists only to support tests that run as root, pretty much. - # Once they have finally been eliminated this can all go... --daniel 2011-04-08 - if Puppet.features.posix? then - def self.in_tmp(path) - path =~ /^\/tmp/ or path =~ /^\/var\/folders/ - end - elsif Puppet.features.microsoft_windows? - def self.in_tmp(path) - tempdir = File.expand_path(File.join(Dir::LOCAL_APPDATA, "Temp")) - path =~ /^#{tempdir}/ - end - else - fail "Help! Can't find in_tmp for this platform" - end - - def self.cleanup - $global_tempfiles ||= [] - while path = $global_tempfiles.pop do - fail "Not deleting tmpfile #{path} outside regular tmpdir" unless in_tmp(path) - - begin - FileUtils.rm_r path, :secure => true - rescue Errno::ENOENT - # nothing to do - end - end - end - - def tmpfile(name) - # Generate a temporary file, just for the name... - source = Tempfile.new(name) - path = source.path - source.close! - - # ...record it for cleanup, - $global_tempfiles ||= [] - $global_tempfiles << File.expand_path(path) - - # ...and bam. - path - end - - def tmpdir(name) - path = tmpfile(name) - FileUtils.mkdir_p(path) - path - end -end diff --git a/puppet/modules/stdlib/spec/lib/puppet_spec/fixtures.rb b/puppet/modules/stdlib/spec/lib/puppet_spec/fixtures.rb deleted file mode 100755 index 7f6bc2a..0000000 --- a/puppet/modules/stdlib/spec/lib/puppet_spec/fixtures.rb +++ /dev/null @@ -1,28 +0,0 @@ -module PuppetSpec::Fixtures - def fixtures(*rest) - File.join(PuppetSpec::FIXTURE_DIR, *rest) - end - def my_fixture_dir - callers = caller - while line = callers.shift do - next unless found = line.match(%r{/spec/(.*)_spec\.rb:}) - return fixtures(found[1]) - end - fail "sorry, I couldn't work out your path from the caller stack!" - end - def my_fixture(name) - file = File.join(my_fixture_dir, name) - unless File.readable? file then - fail Puppet::DevError, "fixture '#{name}' for #{my_fixture_dir} is not readable" - end - return file - end - def my_fixtures(glob = '*', flags = 0) - files = Dir.glob(File.join(my_fixture_dir, glob), flags) - unless files.length > 0 then - fail Puppet::DevError, "fixture '#{glob}' for #{my_fixture_dir} had no files!" - end - block_given? and files.each do |file| yield file end - files - end -end diff --git a/puppet/modules/stdlib/spec/lib/puppet_spec/matchers.rb b/puppet/modules/stdlib/spec/lib/puppet_spec/matchers.rb deleted file mode 100644 index 77f5803..0000000 --- a/puppet/modules/stdlib/spec/lib/puppet_spec/matchers.rb +++ /dev/null @@ -1,87 +0,0 @@ -require 'stringio' - -######################################################################## -# Backward compatibility for Jenkins outdated environment. -module RSpec - module Matchers - module BlockAliases - alias_method :to, :should unless method_defined? :to - alias_method :to_not, :should_not unless method_defined? :to_not - alias_method :not_to, :should_not unless method_defined? :not_to - end - end -end - - -######################################################################## -# Custom matchers... -RSpec::Matchers.define :have_matching_element do |expected| - match do |actual| - actual.any? { |item| item =~ expected } - end -end - - -RSpec::Matchers.define :exit_with do |expected| - actual = nil - match do |block| - begin - block.call - rescue SystemExit => e - actual = e.status - end - actual and actual == expected - end - failure_message_for_should do |block| - "expected exit with code #{expected} but " + - (actual.nil? ? " exit was not called" : "we exited with #{actual} instead") - end - failure_message_for_should_not do |block| - "expected that exit would not be called with #{expected}" - end - description do - "expect exit with #{expected}" - end -end - - -RSpec::Matchers.define :have_printed do |expected| - match do |block| - $stderr = $stdout = StringIO.new - - begin - block.call - ensure - $stdout.rewind - @actual = $stdout.read - - $stdout = STDOUT - $stderr = STDERR - end - - if @actual then - case expected - when String - @actual.include? expected - when Regexp - expected.match @actual - else - raise ArgumentError, "No idea how to match a #{@actual.class.name}" - end - end - end - - failure_message_for_should do |actual| - if actual.nil? then - "expected #{expected.inspect}, but nothing was printed" - else - "expected #{expected.inspect} to be printed; got:\n#{actual}" - end - end - - description do - "expect #{expected.inspect} to be printed" - end - - diffable -end diff --git a/puppet/modules/stdlib/spec/lib/puppet_spec/verbose.rb b/puppet/modules/stdlib/spec/lib/puppet_spec/verbose.rb deleted file mode 100755 index d9834f2..0000000 --- a/puppet/modules/stdlib/spec/lib/puppet_spec/verbose.rb +++ /dev/null @@ -1,9 +0,0 @@ -# Support code for running stuff with warnings disabled. -module Kernel - def with_verbose_disabled - verbose, $VERBOSE = $VERBOSE, nil - result = yield - $VERBOSE = verbose - return result - end -end diff --git a/puppet/modules/stdlib/spec/monkey_patches/publicize_methods.rb b/puppet/modules/stdlib/spec/monkey_patches/publicize_methods.rb index b39e9c0..f3a1abf 100755 --- a/puppet/modules/stdlib/spec/monkey_patches/publicize_methods.rb +++ b/puppet/modules/stdlib/spec/monkey_patches/publicize_methods.rb @@ -8,4 +8,3 @@ def publicize_methods(*methods) self.class_eval { private(*saved_private_instance_methods) } end end - diff --git a/puppet/modules/stdlib/spec/spec.opts b/puppet/modules/stdlib/spec/spec.opts old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/spec_helper.rb b/puppet/modules/stdlib/spec/spec_helper.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/facter/pe_required_facts_spec.rb b/puppet/modules/stdlib/spec/unit/facter/pe_required_facts_spec.rb new file mode 100755 index 0000000..f219b37 --- /dev/null +++ b/puppet/modules/stdlib/spec/unit/facter/pe_required_facts_spec.rb @@ -0,0 +1,69 @@ +# Puppet Enterprise requires the following facts to be set in order to operate. +# These facts are set using the file ???? and the two facts are +# `fact_stomp_port`, and `fact_stomp_server`. +# + +require 'spec_helper' + +describe "External facts in /etc/puppetlabs/facter/facts.d/puppet_enterprise_installer.txt" do + context "With Facter 1.6.17 which does not have external facts support" do + before :each do + Facter.stubs(:version).returns("1.6.17") + # Stub out the filesystem for stdlib + Dir.stubs(:entries).with("/etc/puppetlabs/facter/facts.d"). + returns(['puppet_enterprise_installer.txt']) + Dir.stubs(:entries).with("/etc/facter/facts.d").returns([]) + File.stubs(:readlines).with('/etc/puppetlabs/facter/facts.d/puppet_enterprise_installer.txt'). + returns([ + "fact_stomp_port=61613\n", + "fact_stomp_server=puppetmaster.acme.com\n", + "fact_is_puppetagent=true\n", + "fact_is_puppetmaster=false\n", + "fact_is_puppetca=false\n", + "fact_is_puppetconsole=false\n", + ]) + if Facter.collection.respond_to? :load + Facter.collection.load(:facter_dot_d) + else + Facter.collection.loader.load(:facter_dot_d) + end + end + + it 'defines fact_stomp_port' do + Facter.fact(:fact_stomp_port).value.should == '61613' + end + it 'defines fact_stomp_server' do + Facter.fact(:fact_stomp_server).value.should == 'puppetmaster.acme.com' + end + it 'defines fact_is_puppetagent' do + Facter.fact(:fact_is_puppetagent).value.should == 'true' + end + it 'defines fact_is_puppetmaster' do + Facter.fact(:fact_is_puppetmaster).value.should == 'false' + end + it 'defines fact_is_puppetca' do + Facter.fact(:fact_is_puppetca).value.should == 'false' + end + it 'defines fact_is_puppetconsole' do + Facter.fact(:fact_is_puppetconsole).value.should == 'false' + end + end + + [ '1.7.1', '2.0.1' ].each do |v| + context "With Facter #{v} which has external facts support" do + before :each do + Facter.stubs(:version).returns(v) + end + + it 'does not call Facter::Util::DotD.new' do + Facter::Util::DotD.expects(:new).never + + if Facter.collection.respond_to? :load + Facter.collection.load(:facter_dot_d) + else + Facter.collection.loader.load(:facter_dot_d) + end + end + end + end +end diff --git a/puppet/modules/stdlib/spec/unit/facter/pe_version_spec.rb b/puppet/modules/stdlib/spec/unit/facter/pe_version_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/facter/root_home_spec.rb b/puppet/modules/stdlib/spec/unit/facter/root_home_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/facter/util/puppet_settings_spec.rb b/puppet/modules/stdlib/spec/unit/facter/util/puppet_settings_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/any2array_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/any2array_spec.rb new file mode 100755 index 0000000..b266e84 --- /dev/null +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/any2array_spec.rb @@ -0,0 +1,55 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the any2array function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("any2array").should == "function_any2array" + end + + it "should return an empty array if there is less than 1 argument" do + result = scope.function_any2array([]) + result.should(eq([])) + end + + it "should convert boolean true to [ true ] " do + result = scope.function_any2array([true]) + result.should(eq([true])) + end + + it "should convert one object to [object]" do + result = scope.function_any2array(['one']) + result.should(eq(['one'])) + end + + it "should convert multiple objects to [objects]" do + result = scope.function_any2array(['one', 'two']) + result.should(eq(['one', 'two'])) + end + + it "should return empty array it was called with" do + result = scope.function_any2array([[]]) + result.should(eq([])) + end + + it "should return one-member array it was called with" do + result = scope.function_any2array([['string']]) + result.should(eq(['string'])) + end + + it "should return multi-member array it was called with" do + result = scope.function_any2array([['one', 'two']]) + result.should(eq(['one', 'two'])) + end + + it "should return members of a hash it was called with" do + result = scope.function_any2array([{ 'key' => 'value' }]) + result.should(eq(['key', 'value'])) + end + + it "should return an empty array if it was called with an empty hash" do + result = scope.function_any2array([{ }]) + result.should(eq([])) + end +end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/concat_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/concat_spec.rb new file mode 100755 index 0000000..123188b --- /dev/null +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/concat_spec.rb @@ -0,0 +1,15 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the concat function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should raise a ParseError if there is less than 1 arguments" do + lambda { scope.function_concat([]) }.should( raise_error(Puppet::ParseError)) + end + + it "should be able to concat an array" do + result = scope.function_concat([['1','2','3'],['4','5','6']]) + result.should(eq(['1','2','3','4','5','6'])) + end +end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/count_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/count_spec.rb new file mode 100755 index 0000000..2453815 --- /dev/null +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/count_spec.rb @@ -0,0 +1,31 @@ +#! /usr/bin/env ruby -S rspec + +require 'spec_helper' + +describe "the count function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("count").should == "function_count" + end + + it "should raise a ArgumentError if there is more than 2 arguments" do + lambda { scope.function_count(['foo', 'bar', 'baz']) }.should( raise_error(ArgumentError)) + end + + it "should be able to count arrays" do + scope.function_count([["1","2","3"]]).should(eq(3)) + end + + it "should be able to count matching elements in arrays" do + scope.function_count([["1", "2", "2"], "2"]).should(eq(2)) + end + + it "should not count nil or empty strings" do + scope.function_count([["foo","bar",nil,""]]).should(eq(2)) + end + + it 'does not count an undefined hash key or an out of bound array index (which are both :undef)' do + expect(scope.function_count([["foo",:undef,:undef]])).to eq(1) + end +end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/dirname_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/dirname_spec.rb new file mode 100755 index 0000000..fb3b4fe --- /dev/null +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/dirname_spec.rb @@ -0,0 +1,24 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the dirname function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("dirname").should == "function_dirname" + end + + it "should raise a ParseError if there is less than 1 arguments" do + lambda { scope.function_dirname([]) }.should( raise_error(Puppet::ParseError)) + end + + it "should return dirname for an absolute path" do + result = scope.function_dirname(['/path/to/a/file.ext']) + result.should(eq('/path/to/a')) + end + + it "should return dirname for a relative path" do + result = scope.function_dirname(['path/to/a/file.ext']) + result.should(eq('path/to/a')) + end +end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/flatten_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/flatten_spec.rb index d4dfd20..dba7a6b 100755 --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/flatten_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/flatten_spec.rb @@ -11,6 +11,10 @@ lambda { scope.function_flatten([]) }.should( raise_error(Puppet::ParseError)) end + it "should raise a ParseError if there is more than 1 argument" do + lambda { scope.function_flatten([[], []]) }.should( raise_error(Puppet::ParseError)) + end + it "should flatten a complex data structure" do result = scope.function_flatten([["a","b",["c",["d","e"],"f","g"]]]) result.should(eq(["a","b","c","d","e","f","g"])) diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/floor_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/floor_spec.rb new file mode 100755 index 0000000..dbc8c77 --- /dev/null +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/floor_spec.rb @@ -0,0 +1,39 @@ +#! /usr/bin/env ruby -S rspec + +require 'spec_helper' + +describe "the floor function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("floor").should == "function_floor" + end + + it "should raise a ParseError if there is less than 1 argument" do + lambda { scope.function_floor([]) }.should( raise_error(Puppet::ParseError, /Wrong number of arguments/)) + end + + it "should should raise a ParseError if input isn't numeric (eg. String)" do + lambda { scope.function_floor(["foo"]) }.should( raise_error(Puppet::ParseError, /Wrong argument type/)) + end + + it "should should raise a ParseError if input isn't numeric (eg. Boolean)" do + lambda { scope.function_floor([true]) }.should( raise_error(Puppet::ParseError, /Wrong argument type/)) + end + + it "should return an integer when a numeric type is passed" do + result = scope.function_floor([12.4]) + result.is_a?(Integer).should(eq(true)) + end + + it "should return the input when an integer is passed" do + result = scope.function_floor([7]) + result.should(eq(7)) + end + + it "should return the largest integer less than or equal to the input" do + result = scope.function_floor([3.8]) + result.should(eq(3)) + end +end + diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/fqdn_rotate_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/fqdn_rotate_spec.rb old mode 100644 new mode 100755 index 4eb799d..2577723 --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/fqdn_rotate_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/fqdn_rotate_spec.rb @@ -19,7 +19,7 @@ end it "should rotate a string to give the same results for one host" do - scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1").twice + scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1").twice scope.function_fqdn_rotate(["abcdefg"]).should eql(scope.function_fqdn_rotate(["abcdefg"])) end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/get_module_path_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/get_module_path_spec.rb old mode 100644 new mode 100755 index e761706..486bef6 --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/get_module_path_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/get_module_path_spec.rb @@ -15,11 +15,11 @@ def scope(environment = "production") end it 'should only allow one argument' do - expect { scope.function_get_module_path([]) }.should raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/) - expect { scope.function_get_module_path(['1','2','3']) }.should raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/) + expect { scope.function_get_module_path([]) }.to raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/) + expect { scope.function_get_module_path(['1','2','3']) }.to raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/) end it 'should raise an exception when the module cannot be found' do - expect { scope.function_get_module_path(['foo']) }.should raise_error(Puppet::ParseError, /Could not find module/) + expect { scope.function_get_module_path(['foo']) }.to raise_error(Puppet::ParseError, /Could not find module/) end describe 'when locating a module' do let(:modulepath) { "/tmp/does_not_exist" } diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/getvar_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/getvar_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/has_key_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/has_key_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/hash_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/hash_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_array_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_array_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_domain_name_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_domain_name_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_float_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_float_spec.rb old mode 100644 new mode 100755 index 2f527d9..b7d73b0 --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_float_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_float_spec.rb @@ -26,4 +26,8 @@ result = scope.function_is_float(["3"]) result.should(eq(false)) end + it "should return true if a float is created from an arithmetical operation" do + result = scope.function_is_float([3.2*2]) + result.should(eq(true)) + end end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_function_available.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_function_available.rb new file mode 100755 index 0000000..bd40c51 --- /dev/null +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_function_available.rb @@ -0,0 +1,31 @@ +#!/usr/bin/env rspec +require 'spec_helper' + +describe "the is_function_available function" do + before :all do + Puppet::Parser::Functions.autoloader.loadall + end + + before :each do + @scope = Puppet::Parser::Scope.new + end + + it "should exist" do + Puppet::Parser::Functions.function("is_function_available").should == "function_is_function_available" + end + + it "should raise a ParseError if there is less than 1 arguments" do + lambda { @scope.function_is_function_available([]) }.should( raise_error(Puppet::ParseError)) + end + + it "should return false if a nonexistent function is passed" do + result = @scope.function_is_function_available(['jeff_mccunes_left_sock']) + result.should(eq(false)) + end + + it "should return true if an available function is passed" do + result = @scope.function_is_function_available(['require']) + result.should(eq(true)) + end + +end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_hash_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_hash_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_integer_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_integer_spec.rb old mode 100644 new mode 100755 index 5afbba4..4335795 --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_integer_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_integer_spec.rb @@ -26,4 +26,9 @@ result = scope.function_is_integer(["asdf"]) result.should(eq(false)) end + + it "should return true if an integer is created from an arithmetical operation" do + result = scope.function_is_integer([3*2]) + result.should(eq(true)) + end end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_ip_address_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_ip_address_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_mac_address_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_mac_address_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_numeric_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_numeric_spec.rb old mode 100644 new mode 100755 index 4078b37..d7440fb --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_numeric_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_numeric_spec.rb @@ -22,6 +22,16 @@ result.should(eq(true)) end + it "should return true if an integer is created from an arithmetical operation" do + result = scope.function_is_numeric([3*2]) + result.should(eq(true)) + end + + it "should return true if a float is created from an arithmetical operation" do + result = scope.function_is_numeric([3.2*2]) + result.should(eq(true)) + end + it "should return false if a string" do result = scope.function_is_numeric(["asdf"]) result.should(eq(false)) diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_string_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/is_string_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/join_keys_to_values_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/join_keys_to_values_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/join_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/join_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/keys_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/keys_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/lstrip_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/lstrip_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/max_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/max_spec.rb index 604927e..ff6f2b3 100755 --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/max_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/max_spec.rb @@ -20,4 +20,8 @@ it "should be able to compare numbers" do scope.function_max([6,8,4]).should(eq(8)) end + + it "should be able to compare a number with a stringified number" do + scope.function_max([1,"2"]).should(eq("2")) + end end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/member_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/member_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/merge_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/merge_spec.rb old mode 100644 new mode 100755 index db7d837..04169e7 --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/merge_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/merge_spec.rb @@ -25,7 +25,7 @@ describe 'when calling merge on the scope instance' do it 'should require all parameters are hashes' do - expect { new_hash = scope.function_merge([{}, '2'])}.should raise_error(Puppet::ParseError, /unexpected argument type String/) + expect { new_hash = scope.function_merge([{}, '2'])}.to raise_error(Puppet::ParseError, /unexpected argument type String/) end it 'should be able to merge two hashes' do diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/min_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/min_spec.rb index 781422c..71d593e 100755 --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/min_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/min_spec.rb @@ -20,4 +20,8 @@ it "should be able to compare numbers" do scope.function_min([6,8,4]).should(eq(4)) end + + it "should be able to compare a number with a stringified number" do + scope.function_min([1,"2"]).should(eq(1)) + end end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/num2bool_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/num2bool_spec.rb old mode 100644 new mode 100755 index 640c689..b56196d --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/num2bool_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/num2bool_spec.rb @@ -8,17 +8,60 @@ Puppet::Parser::Functions.function("num2bool").should == "function_num2bool" end - it "should raise a ParseError if there is less than 1 arguments" do + it "should raise a ParseError if there are no arguments" do lambda { scope.function_num2bool([]) }.should( raise_error(Puppet::ParseError)) end - it "should return true if 1" do + it "should raise a ParseError if there are more than 1 arguments" do + lambda { scope.function_num2bool(["foo","bar"]) }.should( raise_error(Puppet::ParseError)) + end + + it "should raise a ParseError if passed something non-numeric" do + lambda { scope.function_num2bool(["xyzzy"]) }.should( raise_error(Puppet::ParseError)) + end + + it "should return true if passed string 1" do result = scope.function_num2bool(["1"]) result.should(be_true) end - it "should return false if 0" do + it "should return true if passed string 1.5" do + result = scope.function_num2bool(["1.5"]) + result.should(be_true) + end + + it "should return true if passed number 1" do + result = scope.function_num2bool([1]) + result.should(be_true) + end + + it "should return false if passed string 0" do result = scope.function_num2bool(["0"]) result.should(be_false) end + + it "should return false if passed number 0" do + result = scope.function_num2bool([0]) + result.should(be_false) + end + + it "should return false if passed string -1" do + result = scope.function_num2bool(["-1"]) + result.should(be_false) + end + + it "should return false if passed string -1.5" do + result = scope.function_num2bool(["-1.5"]) + result.should(be_false) + end + + it "should return false if passed number -1" do + result = scope.function_num2bool([-1]) + result.should(be_false) + end + + it "should return false if passed float -1.5" do + result = scope.function_num2bool([-1.5]) + result.should(be_false) + end end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/parsejson_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/parsejson_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/parseyaml_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/parseyaml_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/pick_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/pick_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/prefix_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/prefix_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/range_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/range_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/reverse_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/reverse_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/rstrip_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/rstrip_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/shuffle_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/shuffle_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/size_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/size_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/sort_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/sort_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/squeeze_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/squeeze_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/str2bool_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/str2bool_spec.rb old mode 100644 new mode 100755 index 2782bbe..ef6350f --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/str2bool_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/str2bool_spec.rb @@ -21,4 +21,11 @@ result = scope.function_str2bool(["undef"]) result.should(eq(false)) end + + it "should return the boolean it was called with" do + result = scope.function_str2bool([true]) + result.should(eq(true)) + result = scope.function_str2bool([false]) + result.should(eq(false)) + end end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/str2saltedsha512_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/str2saltedsha512_spec.rb old mode 100644 new mode 100755 index a692c31..df8fb8e --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/str2saltedsha512_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/str2saltedsha512_spec.rb @@ -9,11 +9,11 @@ end it "should raise a ParseError if there is less than 1 argument" do - expect { scope.function_str2saltedsha512([]) }.should( raise_error(Puppet::ParseError) ) + expect { scope.function_str2saltedsha512([]) }.to( raise_error(Puppet::ParseError) ) end it "should raise a ParseError if there is more than 1 argument" do - expect { scope.function_str2saltedsha512(['foo', 'bar', 'baz']) }.should( raise_error(Puppet::ParseError) ) + expect { scope.function_str2saltedsha512(['foo', 'bar', 'baz']) }.to( raise_error(Puppet::ParseError) ) end it "should return a salted-sha512 password hash 136 characters in length" do @@ -22,7 +22,7 @@ end it "should raise an error if you pass a non-string password" do - expect { scope.function_str2saltedsha512([1234]) }.should( raise_error(Puppet::ParseError) ) + expect { scope.function_str2saltedsha512([1234]) }.to( raise_error(Puppet::ParseError) ) end it "should generate a valid password" do diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/strftime_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/strftime_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/strip_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/strip_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/suffix_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/suffix_spec.rb new file mode 100755 index 0000000..c28f719 --- /dev/null +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/suffix_spec.rb @@ -0,0 +1,19 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the suffix function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("suffix").should == "function_suffix" + end + + it "should raise a ParseError if there is less than 1 arguments" do + lambda { scope.function_suffix([]) }.should( raise_error(Puppet::ParseError)) + end + + it "should return a suffixed array" do + result = scope.function_suffix([['a','b','c'], 'p']) + result.should(eq(['ap','bp','cp'])) + end +end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/swapcase_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/swapcase_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/time_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/time_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/type_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/type_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/unique_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/unique_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/upcase_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/upcase_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/uriescape_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/uriescape_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_absolute_path_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_absolute_path_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_array_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_array_spec.rb old mode 100644 new mode 100755 index 8eee72a..4b31cfd --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_array_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_array_spec.rb @@ -9,12 +9,12 @@ %w{ true false }.each do |the_string| it "should not compile when #{the_string} is a string" do Puppet[:code] = "validate_array('#{the_string}')" - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not an Array/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not an Array/) end it "should not compile when #{the_string} is a bare word" do Puppet[:code] = "validate_array(#{the_string})" - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not an Array/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not an Array/) end end @@ -32,7 +32,7 @@ $foo = undef validate_array($foo) ENDofPUPPETcode - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not an Array/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not an Array/) end end end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_augeas_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_augeas_spec.rb new file mode 100755 index 0000000..ab5c140 --- /dev/null +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_augeas_spec.rb @@ -0,0 +1,102 @@ +require 'spec_helper' + +describe Puppet::Parser::Functions.function(:validate_augeas), :if => Puppet.features.augeas? do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + # The subject of these examplres is the method itself. + subject do + # This makes sure the function is loaded within each test + function_name = Puppet::Parser::Functions.function(:validate_augeas) + scope.method(function_name) + end + + context 'Using Puppet::Parser::Scope.new' do + + describe 'Garbage inputs' do + inputs = [ + [ nil ], + [ [ nil ] ], + [ { 'foo' => 'bar' } ], + [ { } ], + [ '' ], + [ "one", "one", "MSG to User", "4th arg" ], + ] + + inputs.each do |input| + it "validate_augeas(#{input.inspect}) should fail" do + expect { subject.call [input] }.to raise_error Puppet::ParseError + end + end + end + + describe 'Valid inputs' do + inputs = [ + [ "root:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns' ], + [ "proc /proc proc nodev,noexec,nosuid 0 0\n", 'Fstab.lns'], + ] + + inputs.each do |input| + it "validate_augeas(#{input.inspect}) should not fail" do + expect { subject.call input }.not_to raise_error + end + end + end + + describe "Valid inputs which should raise an exception without a message" do + # The intent here is to make sure valid inputs raise exceptions when they + # don't specify an error message to display. This is the behvior in + # 2.2.x and prior. + inputs = [ + [ "root:x:0:0:root\n", 'Passwd.lns' ], + [ "127.0.1.1\n", 'Hosts.lns' ], + ] + + inputs.each do |input| + it "validate_augeas(#{input.inspect}) should fail" do + expect { subject.call input }.to raise_error /validate_augeas.*?matched less than it should/ + end + end + end + + describe "Nicer Error Messages" do + # The intent here is to make sure the function returns the 3rd argument + # in the exception thrown + inputs = [ + [ "root:x:0:0:root\n", 'Passwd.lns', [], 'Failed to validate passwd content' ], + [ "127.0.1.1\n", 'Hosts.lns', [], 'Wrong hosts content' ], + ] + + inputs.each do |input| + it "validate_augeas(#{input.inspect}) should fail" do + expect { subject.call input }.to raise_error /#{input[2]}/ + end + end + end + + describe "Passing simple unit tests" do + inputs = [ + [ "root:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns', ['$file/foobar']], + [ "root:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns', ['$file/root/shell[.="/bin/sh"]', 'foobar']], + ] + + inputs.each do |input| + it "validate_augeas(#{input.inspect}) should fail" do + expect { subject.call input }.not_to raise_error + end + end + end + + describe "Failing simple unit tests" do + inputs = [ + [ "foobar:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns', ['$file/foobar']], + [ "root:x:0:0:root:/root:/bin/sh\n", 'Passwd.lns', ['$file/root/shell[.="/bin/sh"]', 'foobar']], + ] + + inputs.each do |input| + it "validate_augeas(#{input.inspect}) should fail" do + expect { subject.call input }.to raise_error /testing path/ + end + end + end + end +end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_bool_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_bool_spec.rb old mode 100644 new mode 100755 index 31ab8fb..261fb23 --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_bool_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_bool_spec.rb @@ -10,7 +10,7 @@ it "should not compile when #{the_string} is a string" do Puppet[:code] = "validate_bool('#{the_string}')" - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a boolean/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a boolean/) end it "should compile when #{the_string} is a bare word" do @@ -22,12 +22,12 @@ it "should not compile when an arbitrary string is passed" do Puppet[:code] = 'validate_bool("jeff and dan are awesome")' - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a boolean/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a boolean/) end it "should not compile when no arguments are passed" do Puppet[:code] = 'validate_bool()' - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /wrong number of arguments/) end it "should compile when multiple boolean arguments are passed" do @@ -45,7 +45,7 @@ $bar = false validate_bool($foo, $bar, true, false, 'jeff') ENDofPUPPETcode - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a boolean/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a boolean/) end end end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_cmd_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_cmd_spec.rb new file mode 100755 index 0000000..69ea7f4 --- /dev/null +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_cmd_spec.rb @@ -0,0 +1,81 @@ +require 'spec_helper' + +describe Puppet::Parser::Functions.function(:validate_cmd) do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + # The subject of these examplres is the method itself. + subject do + # This makes sure the function is loaded within each test + function_name = Puppet::Parser::Functions.function(:validate_cmd) + scope.method(function_name) + end + + context 'Using Puppet::Parser::Scope.new' do + + describe 'Garbage inputs' do + inputs = [ + [ nil ], + [ [ nil ] ], + [ { 'foo' => 'bar' } ], + [ { } ], + [ '' ], + [ "one", "one", "MSG to User", "4th arg" ], + ] + + inputs.each do |input| + it "validate_cmd(#{input.inspect}) should fail" do + expect { subject.call [input] }.to raise_error Puppet::ParseError + end + end + end + + describe 'Valid inputs' do + inputs = [ + [ '/full/path/to/something', '/bin/echo' ], + [ '/full/path/to/something', '/bin/cat' ], + ] + + inputs.each do |input| + it "validate_cmd(#{input.inspect}) should not fail" do + expect { subject.call input }.not_to raise_error + end + end + end + + describe "Valid inputs which should raise an exception without a message" do + # The intent here is to make sure valid inputs raise exceptions when they + # don't specify an error message to display. This is the behvior in + # 2.2.x and prior. + inputs = [ + [ "hello", "/bin/false" ], + ] + + inputs.each do |input| + it "validate_cmd(#{input.inspect}) should fail" do + expect { subject.call input }.to raise_error /validate_cmd.*?failed to validate content with command/ + end + end + end + + describe "Nicer Error Messages" do + # The intent here is to make sure the function returns the 3rd argument + # in the exception thrown + inputs = [ + [ "hello", [ "bye", "later", "adios" ], "MSG to User" ], + [ "greetings", "salutations", "Error, greetings does not match salutations" ], + ] + + inputs.each do |input| + it "validate_cmd(#{input.inspect}) should fail" do + expect { subject.call input }.to raise_error /#{input[2]}/ + end + end + end + + describe "Test output message" do + it "validate_cmd('whatever', 'kthnksbye') should fail" do + expect { subject.call ['whatever', 'kthnksbye'] }.to raise_error /kthnksbye.* returned 1/ + end + end + end +end diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_hash_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_hash_spec.rb old mode 100644 new mode 100755 index f63db1d..a0c35c2 --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_hash_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_hash_spec.rb @@ -11,12 +11,12 @@ it "should not compile when #{the_string} is a string" do Puppet[:code] = "validate_hash('#{the_string}')" - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a Hash/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a Hash/) end it "should not compile when #{the_string} is a bare word" do Puppet[:code] = "validate_hash(#{the_string})" - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a Hash/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a Hash/) end end @@ -35,10 +35,9 @@ $foo = undef validate_hash($foo) ENDofPUPPETcode - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a Hash/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a Hash/) end end end - diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_re_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_re_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_string_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_string_spec.rb old mode 100644 new mode 100755 index f40bf2a..3b4fb3e --- a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_string_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/validate_string_spec.rb @@ -29,7 +29,7 @@ it "should not compile when #{the_string} is a bare word" do Puppet[:code] = "validate_string(#{the_string})" - expect { scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a string/) + expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a string/) end end @@ -58,4 +58,3 @@ end end end - diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/values_at_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/values_at_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/values_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/values_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/parser/functions/zip_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/parser/functions/zip_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/provider/file_line/ruby_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/provider/file_line/ruby_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/type/anchor_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/type/anchor_spec.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/spec/unit/puppet/type/file_line_spec.rb b/puppet/modules/stdlib/spec/unit/puppet/type/file_line_spec.rb old mode 100644 new mode 100755 index 0cd8a26..edc64bd --- a/puppet/modules/stdlib/spec/unit/puppet/type/file_line_spec.rb +++ b/puppet/modules/stdlib/spec/unit/puppet/type/file_line_spec.rb @@ -37,13 +37,13 @@ file_line[:path].should == '/tmp/path' end it 'should not accept unqualified path' do - expect { file_line[:path] = 'file' }.should raise_error(Puppet::Error, /File paths must be fully qualified/) + expect { file_line[:path] = 'file' }.to raise_error(Puppet::Error, /File paths must be fully qualified/) end it 'should require that a line is specified' do - expect { Puppet::Type.type(:file_line).new(:name => 'foo', :path => '/tmp/file') }.should raise_error(Puppet::Error, /Both line and path are required attributes/) + expect { Puppet::Type.type(:file_line).new(:name => 'foo', :path => '/tmp/file') }.to raise_error(Puppet::Error, /Both line and path are required attributes/) end it 'should require that a file is specified' do - expect { Puppet::Type.type(:file_line).new(:name => 'foo', :line => 'path') }.should raise_error(Puppet::Error, /Both line and path are required attributes/) + expect { Puppet::Type.type(:file_line).new(:name => 'foo', :line => 'path') }.to raise_error(Puppet::Error, /Both line and path are required attributes/) end it 'should default to ensure => present' do file_line[:ensure].should eq :present diff --git a/puppet/modules/stdlib/spec/watchr.rb b/puppet/modules/stdlib/spec/watchr.rb old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/tests/file_line.pp b/puppet/modules/stdlib/tests/file_line.pp old mode 100644 new mode 100755 diff --git a/puppet/modules/stdlib/tests/has_interface_with.pp b/puppet/modules/stdlib/tests/has_interface_with.pp old mode 100644 new mode 100755 index 8b9e51e..e1f1353 --- a/puppet/modules/stdlib/tests/has_interface_with.pp +++ b/puppet/modules/stdlib/tests/has_interface_with.pp @@ -1,10 +1,10 @@ include stdlib -info("has_interface_with('lo'):", has_interface_with('lo')) -info("has_interface_with('loX'):", has_interface_with('loX')) -info("has_interface_with('ipaddress', '127.0.0.1'):", has_interface_with('ipaddress', '127.0.0.1')) -info("has_interface_with('ipaddress', '127.0.0.100'):", has_interface_with('ipaddress', '127.0.0.100')) -info("has_interface_with('network', '127.0.0.0'):", has_interface_with('network', '127.0.0.0')) -info("has_interface_with('network', '128.0.0.0'):", has_interface_with('network', '128.0.0.0')) -info("has_interface_with('netmask', '255.0.0.0'):", has_interface_with('netmask', '255.0.0.0')) -info("has_interface_with('netmask', '256.0.0.0'):", has_interface_with('netmask', '256.0.0.0')) +info('has_interface_with(\'lo\'):', has_interface_with('lo')) +info('has_interface_with(\'loX\'):', has_interface_with('loX')) +info('has_interface_with(\'ipaddress\', \'127.0.0.1\'):', has_interface_with('ipaddress', '127.0.0.1')) +info('has_interface_with(\'ipaddress\', \'127.0.0.100\'):', has_interface_with('ipaddress', '127.0.0.100')) +info('has_interface_with(\'network\', \'127.0.0.0\'):', has_interface_with('network', '127.0.0.0')) +info('has_interface_with(\'network\', \'128.0.0.0\'):', has_interface_with('network', '128.0.0.0')) +info('has_interface_with(\'netmask\', \'255.0.0.0\'):', has_interface_with('netmask', '255.0.0.0')) +info('has_interface_with(\'netmask\', \'256.0.0.0\'):', has_interface_with('netmask', '256.0.0.0')) diff --git a/puppet/modules/stdlib/tests/has_ip_address.pp b/puppet/modules/stdlib/tests/has_ip_address.pp old mode 100644 new mode 100755 index e770a11..8429a88 --- a/puppet/modules/stdlib/tests/has_ip_address.pp +++ b/puppet/modules/stdlib/tests/has_ip_address.pp @@ -1,3 +1,3 @@ include stdlib -info("has_ip_address('192.168.1.256'):", has_ip_address('192.168.1.256')) -info("has_ip_address('127.0.0.1'):", has_ip_address('127.0.0.1')) +info('has_ip_address(\'192.168.1.256\'):', has_ip_address('192.168.1.256')) +info('has_ip_address(\'127.0.0.1\'):', has_ip_address('127.0.0.1')) diff --git a/puppet/modules/stdlib/tests/has_ip_network.pp b/puppet/modules/stdlib/tests/has_ip_network.pp old mode 100644 new mode 100755 index 036d649..a15d8c0 --- a/puppet/modules/stdlib/tests/has_ip_network.pp +++ b/puppet/modules/stdlib/tests/has_ip_network.pp @@ -1,4 +1,4 @@ include stdlib -info("has_ip_network('127.0.0.0'):", has_ip_network('127.0.0.0')) -info("has_ip_network('128.0.0.0'):", has_ip_network('128.0.0.0')) +info('has_ip_network(\'127.0.0.0\'):', has_ip_network('127.0.0.0')) +info('has_ip_network(\'128.0.0.0\'):', has_ip_network('128.0.0.0')) diff --git a/puppet/modules/stdlib/tests/init.pp b/puppet/modules/stdlib/tests/init.pp old mode 100644 new mode 100755 diff --git a/puppet/modules/triggers/files/triggers/backup.sh b/puppet/modules/triggers/files/triggers/backup.sh new file mode 100644 index 0000000..ca22f73 --- /dev/null +++ b/puppet/modules/triggers/files/triggers/backup.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +ARCHIVE="${1:-/vagrant/joomla-box-backup.tar}" + +if [ ! -e "$ARCHIVE" ] ; then + touch "$ARCHIVE" +fi + +if [ ! -w "$ARCHIVE" ] ; then + echo "Cannot write to $ARCHIVE!" + exit 1 +fi + +TMP_ARCHIVE="/tmp/joomla-box-backup.tar" +TEMP_DIR="/tmp/backup" + +MYSQL_USER="root" +MYSQL_PASSWORD="root" + +tar -cvf $TMP_ARCHIVE --files-from /dev/null + +mkdir -p "$TEMP_DIR/" +cd $TEMP_DIR + +echo "Backing up your virtual hosts:" + +for VHOST in /etc/apache2/sites-available/1-*.conf; do + if [ ! -e "$VHOST" ] + then + echo "No virtual hosts found. Nothing to do." + break + fi + + FILENAME=$( basename "$VHOST" ) + SITENAME=${FILENAME%.*} + SITENAME=${SITENAME:2} + + echo " * $SITENAME" + + gzip < $VHOST > "$TEMP_DIR/vhost-$FILENAME.gz" + tar --append --file=$TMP_ARCHIVE "vhost-$FILENAME.gz" + rm -f "vhost-$FILENAME.gz" +done + +echo "Backing up your MySQL databases:" + +DATABASES=`mysql --user=$MYSQL_USER -p$MYSQL_PASSWORD -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|mysql)"` + +for DB in $DATABASES; do + echo " * $DB" + + mysqldump --force --opt --user=$MYSQL_USER -p$MYSQL_PASSWORD --databases $DB | gzip > "$TEMP_DIR/mysql-$DB.sql.gz" + tar --append --file=$TMP_ARCHIVE "mysql-$DB.sql.gz" + rm -f mysql-$DB.sql.gz +done + +mv $TMP_ARCHIVE $ARCHIVE +echo "Backup created in $ARCHIVE" \ No newline at end of file diff --git a/puppet/modules/triggers/files/triggers/restore.sh b/puppet/modules/triggers/files/triggers/restore.sh new file mode 100644 index 0000000..3159769 --- /dev/null +++ b/puppet/modules/triggers/files/triggers/restore.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +ARCHIVE="${1:-/vagrant/joomla-box-backup.tar}" +TEMP_DIR="/tmp/restore" + +if [ ! -f $ARCHIVE ]; then + echo "Backup archive $ARCHIVE not found, aborting." 1>&2 + exit 1 +fi + +if [ -d $TEMP_DIR ]; then + rm -f $TEMP_DIR/*.gz + rm -f $TEMP_DIR/*.conf + rm -f $TEMP_DIR/*.sql +else + mkdir -p $TEMP_DIR +fi + +tar -xf $ARCHIVE -C $TEMP_DIR + +echo "Restoring virtual hosts:" +for VHOST in $TEMP_DIR/vhost-1-*.conf.gz; do + if [ ! -e "$VHOST" ] + then + echo "No virtual hosts found. Nothing to do." + break + fi + + FILENAME=$(basename "$VHOST") + SITENAME="${FILENAME/vhost-1-/}" + SITENAME="${SITENAME/.conf.gz/}" + + echo " * $SITENAME" + + gunzip $VHOST + VHOST="${VHOST/.gz/}" + + # Make sure VirtualHosts are listening on port 8080 instead of 80 + # (we changed the port since adding Varnish support) + if grep -Fxq "" $VHOST + then + sed -i'.bak' 's///g' $VHOST + fi + + sudo mv $VHOST "/etc/apache2/sites-available/1-${SITENAME}.conf" || { echo "Failed to install $SITENAME! Aborting." 1>&2; exit 1; } + sudo a2ensite "1-$SITENAME" &> /dev/null || { echo "Failed to enable $SITENAME! Aborting." 1>&2; exit 1; } +done + +sudo service apache2 restart + +echo "Restoring databases:" + +for DB in $TEMP_DIR/mysql-*.sql.gz; do + if [ ! -e "$DB" ] + then + echo "No database dumps found. Nothing to do." + break + fi + + FILENAME=$(basename $DB) + DBNAME=${FILENAME%.*} + DBNAME="${DBNAME/.sql.gz/}" + + echo " * $DBNAME" + + gunzip $DB + DB="${DB/.gz/}" + + mysql -uroot -proot < $DB || { echo "Failed to import database $DBNAME! Aborting." 1>&2; exit 1; } +done + +rm -rf $TEMP_DIR + +echo "Succesfully restored your hosts and databases. You can safely delete the joomla-box-backup.tar file after validating your setup." \ No newline at end of file diff --git a/puppet/modules/triggers/manifests/init.pp b/puppet/modules/triggers/manifests/init.pp new file mode 100644 index 0000000..2d52551 --- /dev/null +++ b/puppet/modules/triggers/manifests/init.pp @@ -0,0 +1,15 @@ +class triggers { + + file { '/home/vagrant/triggers': + source => 'puppet:///modules/triggers/triggers', + recurse => true, + owner => vagrant, + group => vagrant, + } + + exec { 'make-triggers-executable': + command => 'chmod +x /home/vagrant/triggers/*', + subscribe => File['/home/vagrant/triggers'] + } + +} \ No newline at end of file diff --git a/puppet/modules/varnish/files/joomla.box.vcl b/puppet/modules/varnish/files/joomla.box.vcl new file mode 100644 index 0000000..e5c288e --- /dev/null +++ b/puppet/modules/varnish/files/joomla.box.vcl @@ -0,0 +1,140 @@ +vcl 4.0; + +# This Varnish configuration is a very basic template to get started with caching Joomla sites. +# In no way is this configuration complete: every site is unique and needs customisation! +# For demonstration purposes this VCL will cache all front-end pages (including pages with cookies). + +import std; + +backend default { + .host = "127.0.0.1"; + .port = "8080"; + .probe = { + .url = "/varnish-enabled"; + .interval = 1s; + .timeout = 1s; + } +} + +backend alternative { + .host = "127.0.0.1"; + .port = "8080"; +} + +sub vcl_recv { + # Forward client's IP to backend + unset req.http.X-Forwarded-For; + set req.http.X-Forwarded-For = client.ip; + + set req.http.X-Forwarded-By = server.ip; + set req.http.X-Forwarded-Port = 80; + + # Check if we've still enabled Varnish, if not, passthrough every request + if (! std.healthy(req.backend_hint)) + { + set req.backend_hint = alternative; + return (pass); + } + + # Do not cache phpmyadmin + if (req.http.host == "phpmyadmin.joomla.box") { + return (pass); + } + + # Do not cache system tools on joomla.box: + if (req.http.host == "joomla.box") + { + if (req.url ~ "^/apc" || req.url ~ "^/phpinfo" || req.url ~ "^/pimpmylog" || req.url ~ "^/dashboard") { + return (pass); + } + } + + # Do not cache POST requests + if (req.method == "POST") { + return (pass); + } + + # Proxy (pass) any request that goes to the backend admin, the banner component links, .. + if(req.url ~ "/administrator" || req.url ~ "/component/banners" || req.url ~ "/component/users" || req.url ~ "/installation") { + return (pass); + } + + # Do not cache if user is logged in + if (req.http.Authorization || req.http.Authenticate) { + return (pass); + } + + # Don't cache ajax requests + if(req.http.X-Requested-With == "XMLHttpRequest" || req.url ~ "nocache") { + return (pass); + } + + # Properly handle different encoding types + if (req.http.Accept-Encoding) { + if (req.url ~ "\.(jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf)$") { + # No point in compressing these + unset req.http.Accept-Encoding; + } elsif (req.http.Accept-Encoding ~ "gzip") { + set req.http.Accept-Encoding = "gzip"; + } elsif (req.http.Accept-Encoding ~ "deflate") { + set req.http.Accept-Encoding = "deflate"; + } else { + # unknown algorithm (aka crappy browser) + unset req.http.Accept-Encoding; + } + } + + return (hash); +} + +sub vcl_backend_response { + # Unset the "etag" header (suggested) + unset beresp.http.etag; + + # This is Joomla! specific: fix stupid "no-cache" header sent by Joomla! even + # when caching is on - make sure to replace 300 with the number of seconds that + # you want the browser to cache content + if(beresp.http.Cache-Control ~ "no-cache" || beresp.http.Cache-Control == ""){ + set beresp.http.Cache-Control = "max-age=300, public, must-revalidate"; + } + + # Check for the custom "x-Logged-In" header to identify if the visitor is a guest, + # then unset any cookie (including session cookies) provided it's not a POST request. + if(bereq.method != "POST" && beresp.http.X-Logged-In == "false") { + unset beresp.http.Set-Cookie; + } + + # This is how long Varnish will cache content + set beresp.ttl = 1w; + + return (deliver); +} + +sub vcl_hash +{ + hash_data(req.url); + + if (req.http.host) { + hash_data(req.http.host); + } else { + hash_data(server.ip); + } + + # Hash cookies for requests that have them + if (req.http.Cookie) { + hash_data(req.http.Cookie); + } +} + +sub vcl_deliver { + if (resp.http.x-varnish ~ " ") { + set resp.http.X-Varnish-Status = "HIT"; + } else { + set resp.http.X-Varnish-Status = "MISS"; + } + + # Please note that obj.hits behaviour changed in 4.0, now it counts per objecthead, not per object + # and obj.hits may not be reset in some cases where bans are in use. See bug 1492 for details. + # So take hits with a grain of salt + set resp.http.X-Varnish-Hits = obj.hits; +} \ No newline at end of file diff --git a/puppet/modules/varnish/files/varnish.conf b/puppet/modules/varnish/files/varnish.conf new file mode 100644 index 0000000..2fd9881 --- /dev/null +++ b/puppet/modules/varnish/files/varnish.conf @@ -0,0 +1,10 @@ +START=yes +NFILES=131072 +MEMLOCK=82000 + +DAEMON_OPTS="-a :80 \ + -T localhost:6082 \ + -f /etc/varnish/default.vcl \ + -S /etc/varnish/secret \ + -t 120 \ + -s malloc,128m" \ No newline at end of file diff --git a/puppet/modules/varnish/manifests/init.pp b/puppet/modules/varnish/manifests/init.pp new file mode 100644 index 0000000..555c367 --- /dev/null +++ b/puppet/modules/varnish/manifests/init.pp @@ -0,0 +1,47 @@ +class varnish { + + apt::source { 'varnish': + location => "http://repo.varnish-cache.org/ubuntu", + repos => "varnish-4.0", + key => 'C4DEFFEB', + key_source => 'http://repo.varnish-cache.org/debian/GPG-key.txt', + } + + package { 'varnish': + ensure => 'latest', + require => Apt::Source['varnish'] + } + + service {'varnish': + ensure => running, + restart => 'service varnish restart', + require => Package['varnish'] + } + + file { '/etc/default/varnish': + ensure => present, + owner => 'root', + group => 'root', + mode => '0644', + source => "puppet:///modules/varnish/varnish.conf", + require => Package['varnish'], + notify => Service['varnish'] + } + + file { '/etc/varnish/default.vcl': + ensure => present, + owner => vagrant, + group => vagrant, + mode => '0774', + source => "puppet:///modules/varnish/joomla.box.vcl", + require => Package['varnish'], + notify => Service['varnish'] + } + + file_line { 'apache-listen-port-80': + path => '/etc/apache2/ports.conf', + line => 'Listen 8080', + match => '^Listen (80){1,2}$', + require => Class['apache'] + } +} \ No newline at end of file diff --git a/puppet/modules/webgrind/files/config.php b/puppet/modules/webgrind/files/config.php new file mode 100644 index 0000000..d4cbd05 --- /dev/null +++ b/puppet/modules/webgrind/files/config.php @@ -0,0 +1,120 @@ + "puppet:///modules/webgrind/webgrind-release-1.0.zip", + package { 'graphviz': + ensure => installed } - exec { 'php-extract-webgrind': - cwd => '/usr/share', - command => "unzip /tmp/webgrind.zip", - creates => '/usr/share/webgrind', + archive { 'webgrind-1.2': + ensure => present, + url => 'https://github.com/alpha0010/webgrind/archive/1.2.tar.gz', + target => '/usr/share', + follow_redirects => true, + checksum => false } + -> + file { '/usr/share/webgrind-1.2/config.php': + ensure => file, + source => 'puppet:///modules/webgrind/config.php' + } + } \ No newline at end of file diff --git a/puppet/modules/xdebug/manifests/init.pp b/puppet/modules/xdebug/manifests/init.pp index f4a5eb6..7b27473 100644 --- a/puppet/modules/xdebug/manifests/init.pp +++ b/puppet/modules/xdebug/manifests/init.pp @@ -9,4 +9,11 @@ notify => Service[$service], } + file { '/etc/php5/mods-available/xdebug.ini': + ensure => file, + content => '; zend_extension=xdebug.so', + require => Package['xdebug'], + notify => Service[$service] + } + } diff --git a/puppet/modules/zray/manifests/apache/vhost.pp b/puppet/modules/zray/manifests/apache/vhost.pp new file mode 100644 index 0000000..ca5e133 --- /dev/null +++ b/puppet/modules/zray/manifests/apache/vhost.pp @@ -0,0 +1,20 @@ +define zray::apache::vhost ( + $ensure = present, + $path = '/opt/zray', + $enable = false +) { + + file { "/etc/apache2/sites-available/00-${title}.conf": + ensure => $ensure, + content => template('zray/apache.vhost.erb') + } + + if ($enable) { + file { "/etc/apache2/sites-enabled/00-${title}.conf": + ensure => link, + target => "/etc/apache2/sites-available/00-${title}.conf" + } + } + + +} \ No newline at end of file diff --git a/puppet/modules/zray/manifests/init.pp b/puppet/modules/zray/manifests/init.pp new file mode 100644 index 0000000..815396a --- /dev/null +++ b/puppet/modules/zray/manifests/init.pp @@ -0,0 +1,47 @@ +class zray { + + archive { 'zray-php-101832-php5.6.11-linux-debian7-amd64': + ensure => present, + url => 'http://repos.zend.com/zend-server/early-access/zray-tech-preview/zray-php-101832-php5.6.11-linux-debian7-amd64.tar.gz', + target => '/opt', + checksum => false + } + -> + exec {'zray-chown-www-data': + command => '/usr/bin/find /opt/zray-php-101832-php5.6.11-linux-debian7-amd64 ! -user www-data -exec /bin/chown www-data:www-data {} \;' + } + -> + zray::apache::vhost { 'zray-php5.6': + ensure => present, + path => '/opt/zray-php-101832-php5.6.11-linux-debian7-amd64/zray', + enable => true + } + -> + zray::php::ini { 'zray-php5.6': + ensure => present, + path => '/opt/zray-php-101832-php5.6.11-linux-debian7-amd64/zray', + enable => true + } + + archive { 'zray-php-101832-php5.5.27-linux-debian7-amd64': + ensure => present, + url => 'http://repos.zend.com/zend-server/early-access/zray-tech-preview/zray-php-101832-php5.5.27-linux-debian7-amd64.tar.gz', + target => '/opt', + checksum => false + } + -> + exec {'zray-php5.5-chown-www-data': + command => '/usr/bin/find /opt/zray-php-101832-php5.5.27-linux-debian7-amd64 ! -user www-data -exec /bin/chown www-data:www-data {} \;' + } + -> + zray::apache::vhost { 'zray-php5.5': + ensure => present, + path => '/opt/zray-php-101832-php5.5.27-linux-debian7-amd64/zray' + } + -> + zray::php::ini { 'zray-php5.5': + ensure => present, + path => '/opt/zray-php-101832-php5.5.27-linux-debian7-amd64/zray' + } + +} \ No newline at end of file diff --git a/puppet/modules/zray/manifests/php/ini.pp b/puppet/modules/zray/manifests/php/ini.pp new file mode 100644 index 0000000..714bbb5 --- /dev/null +++ b/puppet/modules/zray/manifests/php/ini.pp @@ -0,0 +1,24 @@ +define zray::php::ini ( + $ensure = present, + $path = '/opt/zray', + $enable = false +) { + + file { "/etc/php5/mods-available/${title}.ini": + ensure => $ensure, + content => template('zray/php.ini.erb') + } + + if ($enable) { + file { "/etc/php5/apache2/conf.d/20-${title}.ini": + ensure => link, + target => "/etc/php5/mods-available/${title}.ini" + } + } + else { + file { ["/etc/php5/apache2/conf.d/20-${title}.ini"]: + ensure => absent + } + } + +} \ No newline at end of file diff --git a/puppet/modules/zray/templates/apache.vhost.erb b/puppet/modules/zray/templates/apache.vhost.erb new file mode 100644 index 0000000..5bce454 --- /dev/null +++ b/puppet/modules/zray/templates/apache.vhost.erb @@ -0,0 +1,10 @@ +Alias /ZendServer <%= @path %>/gui/public + +RewriteEngine On +RewriteRule ^/$ /ZendServer/ [R] +RewriteRule ^/Login$ /ZendServer/Login [R] + +/gui/public> + Require all granted + AllowOverride All + \ No newline at end of file diff --git a/puppet/modules/zray/templates/php.ini.erb b/puppet/modules/zray/templates/php.ini.erb new file mode 100644 index 0000000..237fd20 --- /dev/null +++ b/puppet/modules/zray/templates/php.ini.erb @@ -0,0 +1,2 @@ +zend_extension=<%= @path %>/lib/zray.so +zray.install_dir=<%= @path %> \ No newline at end of file