diff --git a/modules/dependencies/concat/CHANGELOG.md b/modules/dependencies/concat/CHANGELOG.md new file mode 100644 index 000000000..f8898669b --- /dev/null +++ b/modules/dependencies/concat/CHANGELOG.md @@ -0,0 +1,204 @@ +##2014-09-10 - Supported Release 1.1.1 + +###Summary + +This is a bugfix release, and the first supported release of the 1.1.x series. + +####Bugfixes +- Make the `$order` parameter default to a string and be validated as an integer + or a string +- Use the ruby script on Solaris to not break Sol10 support +- Add quotes to the ryby script location for Windows +- Fix typos in README.md +- Make regex in concat::setup case-insensitive to make it work on Windows +- Make sure concat fragments are always replaced +- Fix validation to allow `$backup` to be a boolean +- Remove dependency on stdlib 4.x +- Fix for lack of idempotency with `ensure => 'absent'` +- Fix tests and spec_helper +- Synchronized files for more consistency across modules via modulesync + +##2014-05-14 - Release 1.1.0 + +###Summary + +This release is primarily a bugfix release since 1.1.0-rc1. + +####Features +- Improved testing, with tests moved to beaker + +####Bugfixes +- No longer attempts to set fragment owner and mode on Windows +- Fix numeric sorting +- Fix incorrect quoting +- Fix newlines + +##2014-01-03 - Release 1.1.0-rc1 + +###Summary + +This release of concat was 90% written by Joshua Hoblitt, and the module team +would like to thank him for the huge amount of work he put into this release. + +This module deprecates a bunch of old parameters and usage patterns, modernizes +much of the manifest code, simplifies a whole bunch of logic and makes +improvements to almost all parts of the module. + +The other major feature is windows support, courtesy of luisfdez, with an +alternative version of the concat bash script in ruby. We've attempted to +ensure that there are no backwards incompatible changes, all users of 1.0.0 +should be able to use 1.1.0 without any failures, but you may find deprecation +warnings and we'll be aggressively moving for a 2.0 to remove those too. + +For further information on deprecations, please read: +https://github.com/puppetlabs/puppetlabs-concat/blob/master/README.md#api-deprecations + +####Removed +- Puppet 0.24 support. +- Filebucket backup of all file resources except the target concatenated file. +- Default owner/user/group values. +- Purging of long unused /usr/local/bin/concatfragments.sh + +###Features +- Windows support via a ruby version of the concat bash script. +- Huge amount of acceptance testing work added. +- Documentation (README) completely rewritten. +- New parameters in concat: + - `ensure`: Controls if the file should be present/absent at all. + - Remove requirement to include concat::setup in manifests. + - Made `gnu` parameter deprecated. + - Added parameter validation. + +###Bugfixes + - Ensure concat::setup runs before concat::fragment in all cases. + - Pluginsync references updated for modern Puppet. + - Fix incorrect group parameter. + - Use $owner instead of $id to avoid confusion with $::id + - Compatibility fixes for Puppet 2.7/ruby 1.8.7 + - Use LC_ALL=C instead of LANG=C + - Always exec the concatfragments script as root when running as root. + - Syntax and other cleanup changes. + +##2014-06-25 - Supported Release 1.0.4 +###Summary + +This release has test fixes. + +####Features +- Added test support for OSX. + +####Bugfixes + +####Known bugs + +* Not supported on Windows. + +##2014-06-04 - Release 1.0.3 +###Summary + +This release adds compatibility for PE3.3 and fixes tests. + +####Features +- Added test support for Ubuntu Trusty. + +####Bugfixes + +####Known bugs + +*Not supported on Windows. + +##2014-03-04 - Supported Release 1.0.2 +###Summary + +This is a supported release. No functional changes were made from 1.0.1. + +####Features +- Huge amount of tests backported from 1.1. +- Documentation rewrite. + +####Bugfixes + +####Known Bugs + +* Not supported on Windows. + + +##2014-02-12 - 1.0.1 + +###Summary + +Minor bugfixes for sorting of fragments and ordering of resources. + +####Bugfixes +- LANG => C replaced with LC_ALL => C to reduce spurious recreation of +fragments. +- Corrected pluginsync documentation. +- Ensure concat::setup always runs before fragments. + + +##2013-08-09 - 1.0.0 + +###Summary + +Many new features and bugfixes in this release, and if you're a heavy concat +user you should test carefully before upgrading. The features should all be +backwards compatible but only light testing has been done from our side before +this release. + +####Features +- New parameters in concat: + - `replace`: specify if concat should replace existing files. + - `ensure_newline`: controls if fragments should contain a newline at the end. +- Improved README documentation. +- Add rspec:system tests (rake spec:system to test concat) + +####Bugfixes +- Gracefully handle \n in a fragment resource name. +- Adding more helpful message for 'pluginsync = true' +- Allow passing `source` and `content` directly to file resource, rather than +defining resource defaults. +- Added -r flag to read so that filenames with \ will be read correctly. +- sort always uses LANG=C. +- Allow WARNMSG to contain/start with '#'. +- Replace while-read pattern with for-do in order to support Solaris. + +####CHANGELOG: +- 2010/02/19 - initial release +- 2010/03/12 - add support for 0.24.8 and newer + - make the location of sort configurable + - add the ability to add shell comment based warnings to + top of files + - add the ablity to create empty files +- 2010/04/05 - fix parsing of WARN and change code style to match rest + of the code + - Better and safer boolean handling for warn and force + - Don't use hard coded paths in the shell script, set PATH + top of the script + - Use file{} to copy the result and make all fragments owned + by root. This means we can chnage the ownership/group of the + resulting file at any time. + - You can specify ensure => "/some/other/file" in concat::fragment + to include the contents of a symlink into the final file. +- 2010/04/16 - Add more cleaning of the fragment name - removing / from the $name +- 2010/05/22 - Improve documentation and show the use of ensure => +- 2010/07/14 - Add support for setting the filebucket behavior of files +- 2010/10/04 - Make the warning message configurable +- 2010/12/03 - Add flags to make concat work better on Solaris - thanks Jonathan Boyett +- 2011/02/03 - Make the shell script more portable and add a config option for root group +- 2011/06/21 - Make base dir root readable only for security +- 2011/06/23 - Set base directory using a fact instead of hardcoding it +- 2011/06/23 - Support operating as non privileged user +- 2011/06/23 - Support dash instead of bash or sh +- 2011/07/11 - Better solaris support +- 2011/12/05 - Use fully qualified variables +- 2011/12/13 - Improve Nexenta support +- 2012/04/11 - Do not use any GNU specific extensions in the shell script +- 2012/03/24 - Comply to community style guides +- 2012/05/23 - Better errors when basedir isnt set +- 2012/05/31 - Add spec tests +- 2012/07/11 - Include concat::setup in concat improving UX +- 2012/08/14 - Puppet Lint improvements +- 2012/08/30 - The target path can be different from the $name +- 2012/08/30 - More Puppet Lint cleanup +- 2012/09/04 - RELEASE 0.2.0 +- 2012/12/12 - Added (file) $replace parameter to concat diff --git a/modules/dependencies/concat/CONTRIBUTING.md b/modules/dependencies/concat/CONTRIBUTING.md new file mode 100644 index 000000000..e1288478a --- /dev/null +++ b/modules/dependencies/concat/CONTRIBUTING.md @@ -0,0 +1,234 @@ +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: + + - Sign the [Contributor License Agreement](https://cla.puppetlabs.com/) + + - Make sure you have a [GitHub account](https://github.com/join) + + - [Create a ticket](http://projects.puppetlabs.com/projects/modules/issues/new), or [watch the ticket](http://projects.puppetlabs.com/projects/modules/issues) 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. Sign the Contributor License Agreement + + Before we can accept your changes, we do need a signed Puppet + Labs Contributor License Agreement (CLA). + + You can access the CLA via the [Contributor License Agreement link](https://cla.puppetlabs.com/) + + If you have any questions about the CLA, please feel free to + contact Puppet Labs via email at cla-submissions@puppetlabs.com. + + 3. 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. + + + 4. Update the related GitHub issue. + + If there is a GitHub issue associated with the change you + submitted, then you should update the ticket to include the + location of your branch, along with any other commentary you + may wish to make. + +Testing +======= + +Getting Started +--------------- + +Our puppet modules provide [`Gemfile`](./Gemfile)s which can tell a ruby +package manager such as [bundler](http://bundler.io/) what Ruby packages, +or Gems, are required to build, develop, and test this software. + +Please make sure you have [bundler installed](http://bundler.io/#getting-started) +on your system, then use it to install all dependencies needed for this project, +by running + +```shell +% bundle install +Fetching gem metadata from https://rubygems.org/........ +Fetching gem metadata from https://rubygems.org/.. +Using rake (10.1.0) +Using builder (3.2.2) +-- 8><-- many more --><8 -- +Using rspec-system-puppet (2.2.0) +Using serverspec (0.6.3) +Using rspec-system-serverspec (1.0.0) +Using bundler (1.3.5) +Your bundle is complete! +Use `bundle show [gemname]` to see where a bundled gem is installed. +``` + +NOTE some systems may require you to run this command with sudo. + +If you already have those gems installed, make sure they are up-to-date: + +```shell +% bundle update +``` + +With all dependencies in place and up-to-date we can now run the tests: + +```shell +% rake spec +``` + +This will execute all the [rspec tests](http://rspec-puppet.com/) tests +under [spec/defines](./spec/defines), [spec/classes](./spec/classes), +and so on. rspec tests may have the same kind of dependencies as the +module they are testing. While the module defines in its [Modulefile](./Modulefile), +rspec tests define them in [.fixtures.yml](./fixtures.yml). + +Some puppet modules also come with [beaker](https://github.com/puppetlabs/beaker) +tests. These tests spin up a virtual machine under +[VirtualBox](https://www.virtualbox.org/)) with, controlling it with +[Vagrant](http://www.vagrantup.com/) to actually simulate scripted test +scenarios. In order to run these, you will need both of those tools +installed on your system. + +You can run them by issuing the following command + +```shell +% rake spec_clean +% rspec spec/acceptance +``` + +This will now download a pre-fabricated image configured in the [default node-set](./spec/acceptance/nodesets/default.yml), +install puppet, copy this module and install its dependencies per [spec/spec_helper_acceptance.rb](./spec/spec_helper_acceptance.rb) +and then run all the tests under [spec/acceptance](./spec/acceptance). + +Writing Tests +------------- + +XXX getting started writing tests. + +If you have commit access to the repository +=========================================== + +Even if you have commit access to the repository, you will still need to +go through the process above, and have someone else review and merge +in your changes. The rule is that all changes must be reviewed by a +developer on the project (that did not write the code) to ensure that +all changes go through a code review process. + +Having someone other than the author of the topic branch recorded as +performing the merge is the record that they performed the code +review. + + +Additional Resources +==================== + +* [Getting additional help](http://projects.puppetlabs.com/projects/puppet/wiki/Getting_Help) + +* [Writing tests](http://projects.puppetlabs.com/projects/puppet/wiki/Development_Writing_Tests) + +* [Patchwork](https://patchwork.puppetlabs.com) + +* [Contributor License Agreement](https://projects.puppetlabs.com/contributor_licenses/sign) + +* [General GitHub documentation](http://help.github.com/) + +* [GitHub pull request documentation](http://help.github.com/send-pull-requests/) + diff --git a/modules/dependencies/concat/Gemfile b/modules/dependencies/concat/Gemfile new file mode 100644 index 000000000..081b1a291 --- /dev/null +++ b/modules/dependencies/concat/Gemfile @@ -0,0 +1,27 @@ +source ENV['GEM_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 'puppet-lint', '0.3.2', :require => false + gem 'beaker', :require => false + gem 'beaker-rspec', :require => false + gem 'pry', :require => false + gem 'simplecov', :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/modules/dependencies/concat/LICENSE b/modules/dependencies/concat/LICENSE new file mode 100644 index 000000000..6a9e9a194 --- /dev/null +++ b/modules/dependencies/concat/LICENSE @@ -0,0 +1,14 @@ + Copyright 2012 R.I.Pienaar + + 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/modules/dependencies/concat/README.md b/modules/dependencies/concat/README.md new file mode 100644 index 000000000..2ed9024eb --- /dev/null +++ b/modules/dependencies/concat/README.md @@ -0,0 +1,437 @@ +#Concat + +[](https://travis-ci.org/puppetlabs/puppetlabs-concat) + +####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 concat](#setup) + * [What concat affects](#what-concat-affects) + * [Setup requirements](#setup-requirements) + * [Beginning with concat](#beginning-with-concat) +4. [Usage - Configuration options and additional functionality](#usage) + * [API _deprecations_](#api-deprecations) +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 + +This module constructs files from multiple fragments in an ordered way. + +##Module Description + +This module lets you use many concat::fragment{} resources throughout +your modules to construct a single file at the end. It does this through +a shell (or ruby) script and a temporary holding space for the fragments. + +##Setup + +###What concat affects + +* Installs concatfragments.[sh|rb] based on platform. +* Adds a concat/ directory into Puppets `vardir`. + +###Beginning with concat + +To start using concat you need to create: + +* A concat{} resource for the final file. +* One or more concat::fragment{}'s. + +A minimal example might be: + +```puppet +concat { '/tmp/file': + ensure => present, +} + +concat::fragment { 'tmpfile': + target => '/tmp/file', + content => 'test contents', + order => '01' +} +``` + +##Usage + +Please be aware that there have been a number of [API +_deprecations_](#api-deprecations). + +If you wanted a /etc/motd file that listed all the major modules +on the machine. And that would be maintained automatically even +if you just remove the include lines for other modules you could +use code like below, a sample /etc/motd would be: + +
+Puppet modules on this server: + + -- Apache + -- MySQL ++ +Local sysadmins can also append to the file by just editing /etc/motd.local +their changes will be incorporated into the puppet managed motd. + +```puppet +class motd { + $motd = '/etc/motd' + + concat { $motd: + owner => 'root', + group => 'root', + mode => '0644' + } + + concat::fragment{ 'motd_header': + target => $motd, + content => "\nPuppet modules on this server:\n\n", + order => '01' + } + + # local users on the machine can append to motd by just creating + # /etc/motd.local + concat::fragment{ 'motd_local': + target => $motd, + source => '/etc/motd.local', + order => '15' + } +} + +# used by other modules to register themselves in the motd +define motd::register($content="", $order='10') { + if $content == "" { + $body = $name + } else { + $body = $content + } + + concat::fragment{ "motd_fragment_$name": + target => '/etc/motd', + order => $order, + content => " -- $body\n" + } +} +``` + +To use this you'd then do something like: + +```puppet +class apache { + include apache::install, apache::config, apache::service + + motd::register{ 'Apache': } +} +``` + +##Reference + +###Classes + +####Public classes + +####Private classes +* `concat::setup`: Sets up the concat script/directories. + +###Parameters + +###Defines + +####concat + +#####`ensure` +Controls if the combined file is present or absent. + +######Example +- ensure => present +- ensure => absent + +#####`path` +Controls the destination of the file to create. + +######Example +- path => '/tmp/filename' + +#####`owner` +Set the owner of the combined file. + +######Example +- owner => 'root' + +#####`group` +Set the group of the combined file. + +######Example +- group => 'root' + +#####`mode` +Set the mode of the combined file. + +######Example +- mode => '0644' + +#####`warn` +Determine if a warning message should be added at the top of the file to let +users know it was autogenerated by Puppet. It should be a boolean or a string +containing the contents of the warning message. + +######Example +- warn => true +- warn => false +- warn => '# This file is autogenerated!' + +#####`force` +Determine if empty files are allowed when no fragments were added. + +######Example +- force => true +- force => false + +#####`backup` +Controls the filebucket behavior used for the file. + +######Example +- backup => 'puppet' + +#####`replace` +Controls if Puppet should replace the destination file if it already exists. + +######Example +- replace => true +- replace => false + +#####`order` +Controls the way in which the shell script chooses to sort the files. It's +rare you'll need to adjust this. + +######Allowed Values +- order => 'alpha' +- order => 'numeric' + +#####`ensure_newline` +Ensure there's a newline at the end of the fragments. + +######Example +- ensure_newline => true +- ensure_newline => false + +####concat::fragment + +#####`target` +Choose the destination file of the fragment. + +######Example +- target => '/tmp/testfile' + +#####`content` +Create the content of the fragment. + +######Example +- content => 'test file contents' + +#####`source` +Find the sources within Puppet of the fragment. + +######Example +- source => 'puppet:///modules/test/testfile' +- source => ['puppet:///modules/test/1', 'puppet:///modules/test/2'] + +#####`order` +Order the fragments. + +######Example +- order => '01' + +Best practice is to pass a string to this parameter but integer values are accepted. + +#####`ensure` +Control the file of fragment created. + +######Example +- ensure => 'present' +- ensure => 'absent' + +#####`mode` +Set the mode of the fragment. + +######Example +- mode => '0644' + +#####`owner` +Set the owner of the fragment. + +######Example +- owner => 'root' + +#####`group` +Set the group of the fragment. + +######Example +- group => 'root' + +#####`backup` +Control the filebucket behavior for the fragment. + +######Example +- backup => 'puppet' + +### API _deprecations_ + +#### Since version `1.0.0` + +##### `concat{}` `warn` parameter + +```puppet +concat { '/tmp/file': + ensure => present, + warn => 'true', # generates stringified boolean value warning +} +``` + +Using stringified Boolean values as the `warn` parameter to `concat` is +deprecated, generates a catalog compile time warning, and will be silently +treated as the concatenated file header/warning message in a future release. + +The following strings are considered a stringified Boolean value: + + * `'true'` + * `'yes'` + * `'on'` + * `'false'` + * `'no'` + * `'off'` + +Please migrate to using the Puppet DSL's native [Boolean data +type](http://docs.puppetlabs.com/puppet/3/reference/lang_datatypes.html#booleans). + +##### `concat{}` `gnu` parameter + +```puppet +concat { '/tmp/file': + ensure => present, + gnu => $foo, # generates deprecation warning +} +``` + +The `gnu` parameter to `concat` is deprecated, generates a catalog compile time +warning, and has no effect. This parameter will be removed in a future +release. + +Note that this parameter was silently ignored in the `1.0.0` release. + +##### `concat::fragment{}` `ensure` parameter + +```puppet +concat::fragment { 'cpuinfo': + ensure => '/proc/cpuinfo', # generates deprecation warning + target => '/tmp/file', +} +``` + +Passing a value other than `'present'` or `'absent'` as the `ensure` parameter +to `concat::fragment` is deprecated and generates a catalog compile time +warning. The warning will become a catalog compilation failure in a future +release. + +This type emulates the Puppet core `file` type's disfavored [`ensure` +semantics](http://docs.puppetlabs.com/references/latest/type.html#file-attribute-ensure) +of treating a file path as a directive to create a symlink. This feature is +problematic in several ways. It copies an API semantic of another type that is +both frowned upon and not generally well known. It's behavior may be +surprising in that the target concatenated file will not be a symlink nor is +there any common file system that has a concept of a section of a plain file +being symbolically linked to another file. Additionally, the behavior is +generally inconsistent with most Puppet types in that a missing source file +will be silently ignored. + +If you want to use the content of a file as a fragment please use the `source` +parameter. + +##### `concat::fragment{}` `mode/owner/group` parameters + +```puppet +concat::fragment { 'foo': + target => '/tmp/file', + content => 'foo', + mode => $mode, # generates deprecation warning + owner => $owner, # generates deprecation warning + group => $group, # generates deprecation warning +} +``` + +The `mode` parameter to `concat::fragment` is deprecated, generates a catalog compile time warning, and has no effect. + +The `owner` parameter to `concat::fragment` is deprecated, generates a catalog +compile time warning, and has no effect. + +The `group` parameter to `concat::fragment` is deprecated, generates a catalog +compile time warning, and has no effect. + +These parameters had no user visible effect in version `1.0.0` and will be +removed in a future release. + +##### `concat::fragment{}` `backup` parameter + +```puppet +concat::fragment { 'foo': + target => '/tmp/file', + content => 'foo', + backup => 'bar', # generates deprecation warning +} +``` + +The `backup` parameter to `concat::fragment` is deprecated, generates a catalog +compile time warning, and has no effect. It will be removed in a future +release. + +In the `1.0.0` release this parameter controlled file bucketing of the file +fragment. Bucketting the fragment(s) is redundant with bucketting the final +concatenated file and this feature has been removed. + +##### `class { 'concat::setup': }` + +```puppet +include concat::setup # generates deprecation warning + +class { 'concat::setup': } # generates deprecation warning +``` + +The `concat::setup` class is deprecated as a public API of this module and +should no longer be directly included in the manifest. This class may be +removed in a future release. + +##### Parameter validation + +While not an API depreciation, users should be aware that all public parameters +in this module are now validated for at least variable type. This may cause +validation errors in a manifest that was previously silently misbehaving. + +##Limitations + +This module has been tested on: + +* RedHat Enterprise Linux (and Centos) 5/6 +* Debian 6/7 +* Ubuntu 12.04 + +Testing on other platforms has been light and cannot be guaranteed. + +#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. + +You can read the complete module contribution guide [on the Puppet Labs wiki.](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing) + +###Contributors + +The list of contributors can be found at: + +https://github.com/puppetlabs/puppetlabs-concat/graphs/contributors diff --git a/modules/dependencies/concat/Rakefile b/modules/dependencies/concat/Rakefile new file mode 100644 index 000000000..5868545f2 --- /dev/null +++ b/modules/dependencies/concat/Rakefile @@ -0,0 +1,10 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' + +PuppetLint.configuration.fail_on_warnings +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.send('disable_class_inherits_from_params_class') +PuppetLint.configuration.send('disable_class_parameter_defaults') +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/modules/dependencies/concat/checksums.json b/modules/dependencies/concat/checksums.json new file mode 100644 index 000000000..ccdb8e9b4 --- /dev/null +++ b/modules/dependencies/concat/checksums.json @@ -0,0 +1,53 @@ +{ + "CHANGELOG.md": "e72e5900c060795a23a286c09898cefb", + "CONTRIBUTING.md": "d911815dd7d0d90b90bb35382a6e3298", + "Gemfile": "7e54561091d91e1ce90e429ae4bcea19", + "LICENSE": "f5a76685d453424cd63dde1535811cf0", + "README.md": "1a3d6bbaad03232055fdf7c7cf5a4e7f", + "Rakefile": "de8eeacfe1fbbc6a6f4d89adfc98bcaf", + "files/concatfragments.rb": "f88397daaf63a9c75bcf285b23b727ed", + "files/concatfragments.sh": "7bbe7c5fce25a5ddd20415d909ba44fc", + "lib/facter/concat_basedir.rb": "ff080677e7f192b9b96911698b0b9b3d", + "lib/puppet/parser/functions/concat_getparam.rb": "7654b44a87a05b2f2e9de2eaadf1ff8f", + "lib/puppet/parser/functions/concat_is_bool.rb": "a5dc6980d7f27d1b858e791964682756", + "manifests/fragment.pp": "85921c0e68ba60fc2e711c9324f03ff6", + "manifests/init.pp": "aa491fe7e5cba80dea09ead4c77bb02a", + "manifests/setup.pp": "dea1e9492771dabf32a1b2ac2161beb2", + "metadata.json": "821277dec4a59e16711b5f46fc6a2371", + "spec/acceptance/backup_spec.rb": "6cd0023de71c7f297b919ad44875211c", + "spec/acceptance/concat_spec.rb": "9c43771d9b9b0dd2c3e9fe257059347b", + "spec/acceptance/deprecation_warnings_spec.rb": "1e8afe1828999bca24bd9e0fd64d4e2e", + "spec/acceptance/empty_spec.rb": "8fbe5077e9d85c1ead153164fbf45cac", + "spec/acceptance/fragment_source_spec.rb": "d067b5a75a475df32b391031780c81fb", + "spec/acceptance/fragments_are_always_replaced_spec.rb": "1705de285eb045f26e92e85eadee7fe4", + "spec/acceptance/newline_spec.rb": "8e0b87458e5f6cc3ec242d22520e9fde", + "spec/acceptance/nodesets/aix-71-vcloud.yml": "de6cc5bf18be2be8d50e62503652cb32", + "spec/acceptance/nodesets/centos-59-x64.yml": "57eb3e471b9042a8ea40978c467f8151", + "spec/acceptance/nodesets/centos-64-x64-pe.yml": "ec075d95760df3d4702abea1ce0a829b", + "spec/acceptance/nodesets/centos-64-x64.yml": "9cde7b5d2ab6a42366d2344c264d6bdc", + "spec/acceptance/nodesets/centos-65-x64.yml": "3e5c36e6aa5a690229e720f4048bb8af", + "spec/acceptance/nodesets/debian-607-x64.yml": "d566bf76f534e2af7c9a4605316d232c", + "spec/acceptance/nodesets/debian-70rc1-x64.yml": "31ccca73af7b74e1cc2fb0035c230b2c", + "spec/acceptance/nodesets/debian-73-x64.yml": "bd3ea8245ce691c2b234529d62d043eb", + "spec/acceptance/nodesets/default.yml": "9cde7b5d2ab6a42366d2344c264d6bdc", + "spec/acceptance/nodesets/fedora-18-x64.yml": "acc126fa764c39a3b1df36e9224a21d9", + "spec/acceptance/nodesets/sles-11-x64.yml": "44e4c6c15c018333bfa9840a5e702f66", + "spec/acceptance/nodesets/sles-11sp1-x64.yml": "fa0046bd89c1ab4ba9521ad79db234cd", + "spec/acceptance/nodesets/ubuntu-server-10044-x64.yml": "dc0da2d2449f66c8fdae16593811504f", + "spec/acceptance/nodesets/ubuntu-server-12042-x64.yml": "78a3ee42652e26119d90aa62586565b2", + "spec/acceptance/nodesets/ubuntu-server-1404-x64.yml": "5f0aed10098ac5b78e4217bb27c7aaf0", + "spec/acceptance/order_spec.rb": "bc2c9fc317bf3553e8eb817b00af6f00", + "spec/acceptance/quoted_paths_spec.rb": "b0996f7c377c0a16a64a62c3a8559c93", + "spec/acceptance/replace_spec.rb": "bc06b6f00b1ff1cca19f45468676bcbd", + "spec/acceptance/symbolic_name_spec.rb": "94978d9d4742d18263c420c26e9d7a67", + "spec/acceptance/warn_spec.rb": "130c2c41cab442386ee8be4a1e1a6304", + "spec/spec.opts": "a600ded995d948e393fbe2320ba8e51c", + "spec/spec_helper.rb": "0db89c9a486df193c0e40095422e19dc", + "spec/spec_helper_acceptance.rb": "30b594565f800443d6802436a53afc37", + "spec/unit/classes/concat_setup_spec.rb": "f76beeb0f90766dc91c91f3c0b6b5f4a", + "spec/unit/defines/concat_fragment_spec.rb": "b273ed6b1052a587829ce073e3ded7a4", + "spec/unit/defines/concat_spec.rb": "9cafbbc5afd9c3cd8d8cdc8d951fdcb7", + "spec/unit/facts/concat_basedir_spec.rb": "cf00f5a07948436fa0a84d00fc098539", + "tests/fragment.pp": "9adc3d9ba61676066072e1b949a37dbb", + "tests/init.pp": "bd3ce7d2ee146744b5dbbaae8a927043" +} \ No newline at end of file diff --git a/modules/dependencies/concat/files/concatfragments.rb b/modules/dependencies/concat/files/concatfragments.rb new file mode 100644 index 000000000..904f82460 --- /dev/null +++ b/modules/dependencies/concat/files/concatfragments.rb @@ -0,0 +1,150 @@ +#!/usr/bin/env ruby +# Script to concat files to a config file. +# +# Given a directory like this: +# /path/to/conf.d +# |-- fragments +# | |-- 00_named.conf +# | |-- 10_domain.net +# | `-- zz_footer +# +# The script supports a test option that will build the concat file to a temp location and +# use /usr/bin/cmp to verify if it should be run or not. This would result in the concat happening +# twice on each run but gives you the option to have an unless option in your execs to inhibit rebuilds. +# +# Without the test option and the unless combo your services that depend on the final file would end up +# restarting on each run, or in other manifest models some changes might get missed. +# +# OPTIONS: +# -o The file to create from the sources +# -d The directory where the fragments are kept +# -t Test to find out if a build is needed, basically concats the files to a temp +# location and compare with what's in the final location, return codes are designed +# for use with unless on an exec resource +# -w Add a shell style comment at the top of the created file to warn users that it +# is generated by puppet +# -f Enables the creation of empty output files when no fragments are found +# -n Sort the output numerically rather than the default alpha sort +# +# the command: +# +# concatfragments.rb -o /path/to/conffile.cfg -d /path/to/conf.d +# +# creates /path/to/conf.d/fragments.concat and copies the resulting +# file to /path/to/conffile.cfg. The files will be sorted alphabetically +# pass the -n switch to sort numerically. +# +# The script does error checking on the various dirs and files to make +# sure things don't fail. +require 'optparse' +require 'fileutils' + +settings = { + :outfile => "", + :workdir => "", + :test => false, + :force => false, + :warn => "", + :sortarg => "", + :newline => false +} + +OptionParser.new do |opts| + opts.banner = "Usage: #{$0} [options]" + opts.separator "Specific options:" + + opts.on("-o", "--outfile OUTFILE", String, "The file to create from the sources") do |o| + settings[:outfile] = o + end + + opts.on("-d", "--workdir WORKDIR", String, "The directory where the fragments are kept") do |d| + settings[:workdir] = d + end + + opts.on("-t", "--test", "Test to find out if a build is needed") do + settings[:test] = true + end + + opts.separator "Other options:" + opts.on("-w", "--warn WARNMSG", String, + "Add a shell style comment at the top of the created file to warn users that it is generated by puppet") do |w| + settings[:warn] = w + end + + opts.on("-f", "--force", "Enables the creation of empty output files when no fragments are found") do + settings[:force] = true + end + + opts.on("-n", "--sort", "Sort the output numerically rather than the default alpha sort") do + settings[:sortarg] = "-n" + end + + opts.on("-l", "--line", "Append a newline") do + settings[:newline] = true + end +end.parse! + +# do we have -o? +raise 'Please specify an output file with -o' unless !settings[:outfile].empty? + +# do we have -d? +raise 'Please specify fragments directory with -d' unless !settings[:workdir].empty? + +# can we write to -o? +if File.file?(settings[:outfile]) + if !File.writable?(settings[:outfile]) + raise "Cannot write to #{settings[:outfile]}" + end +else + if !File.writable?(File.dirname(settings[:outfile])) + raise "Cannot write to dirname #{File.dirname(settings[:outfile])} to create #{settings[:outfile]}" + end +end + +# do we have a fragments subdir inside the work dir? +if !File.directory?(File.join(settings[:workdir], "fragments")) && !File.executable?(File.join(settings[:workdir], "fragments")) + raise "Cannot access the fragments directory" +end + +# are there actually any fragments? +if (Dir.entries(File.join(settings[:workdir], "fragments")) - %w{ . .. }).empty? + if !settings[:force] + raise "The fragments directory is empty, cowardly refusing to make empty config files" + end +end + +Dir.chdir(settings[:workdir]) + +if settings[:warn].empty? + File.open("fragments.concat", 'w') {|f| f.write("") } +else + File.open("fragments.concat", 'w') {|f| f.write("#{settings[:warn]}\n") } +end + +# find all the files in the fragments directory, sort them numerically and concat to fragments.concat in the working dir +open('fragments.concat', 'a') do |f| + Dir.entries("fragments").sort.each{ |entry| + + if File.file?(File.join("fragments", entry)) + f << File.read(File.join("fragments", entry)) + + # append a newline if we were asked to (invoked with -l) + if settings[:newline] + f << "\n" + end + + end + } +end + +if !settings[:test] + # This is a real run, copy the file to outfile + FileUtils.cp 'fragments.concat', settings[:outfile] +else + # Just compare the result to outfile to help the exec decide + if FileUtils.cmp 'fragments.concat', settings[:outfile] + exit 0 + else + exit 1 + end +end diff --git a/modules/dependencies/concat/files/concatfragments.sh b/modules/dependencies/concat/files/concatfragments.sh new file mode 100755 index 000000000..7e6b0f5c5 --- /dev/null +++ b/modules/dependencies/concat/files/concatfragments.sh @@ -0,0 +1,140 @@ +#!/bin/sh + +# Script to concat files to a config file. +# +# Given a directory like this: +# /path/to/conf.d +# |-- fragments +# | |-- 00_named.conf +# | |-- 10_domain.net +# | `-- zz_footer +# +# The script supports a test option that will build the concat file to a temp location and +# use /usr/bin/cmp to verify if it should be run or not. This would result in the concat happening +# twice on each run but gives you the option to have an unless option in your execs to inhibit rebuilds. +# +# Without the test option and the unless combo your services that depend on the final file would end up +# restarting on each run, or in other manifest models some changes might get missed. +# +# OPTIONS: +# -o The file to create from the sources +# -d The directory where the fragments are kept +# -t Test to find out if a build is needed, basically concats the files to a temp +# location and compare with what's in the final location, return codes are designed +# for use with unless on an exec resource +# -w Add a shell style comment at the top of the created file to warn users that it +# is generated by puppet +# -f Enables the creation of empty output files when no fragments are found +# -n Sort the output numerically rather than the default alpha sort +# +# the command: +# +# concatfragments.sh -o /path/to/conffile.cfg -d /path/to/conf.d +# +# creates /path/to/conf.d/fragments.concat and copies the resulting +# file to /path/to/conffile.cfg. The files will be sorted alphabetically +# pass the -n switch to sort numerically. +# +# The script does error checking on the various dirs and files to make +# sure things don't fail. + +OUTFILE="" +WORKDIR="" +TEST="" +FORCE="" +WARN="" +SORTARG="" +ENSURE_NEWLINE="" + +PATH=/sbin:/usr/sbin:/bin:/usr/bin + +## Well, if there's ever a bad way to do things, Nexenta has it. +## http://nexenta.org/projects/site/wiki/Personalities +unset SUN_PERSONALITY + +while getopts "o:s:d:tnw:fl" options; do + case $options in + o ) OUTFILE=$OPTARG;; + d ) WORKDIR=$OPTARG;; + n ) SORTARG="-n";; + w ) WARNMSG="$OPTARG";; + f ) FORCE="true";; + t ) TEST="true";; + l ) ENSURE_NEWLINE="true";; + * ) echo "Specify output file with -o and fragments directory with -d" + exit 1;; + esac +done + +# do we have -o? +if [ "x${OUTFILE}" = "x" ]; then + echo "Please specify an output file with -o" + exit 1 +fi + +# do we have -d? +if [ "x${WORKDIR}" = "x" ]; then + echo "Please fragments directory with -d" + exit 1 +fi + +# can we write to -o? +if [ -f "${OUTFILE}" ]; then + if [ ! -w "${OUTFILE}" ]; then + echo "Cannot write to ${OUTFILE}" + exit 1 + fi +else + if [ ! -w `dirname "${OUTFILE}"` ]; then + echo "Cannot write to `dirname \"${OUTFILE}\"` to create ${OUTFILE}" + exit 1 + fi +fi + +# do we have a fragments subdir inside the work dir? +if [ ! -d "${WORKDIR}/fragments" ] && [ ! -x "${WORKDIR}/fragments" ]; then + echo "Cannot access the fragments directory" + exit 1 +fi + +# are there actually any fragments? +if [ ! "$(ls -A """${WORKDIR}/fragments""")" ]; then + if [ "x${FORCE}" = "x" ]; then + echo "The fragments directory is empty, cowardly refusing to make empty config files" + exit 1 + fi +fi + +cd "${WORKDIR}" + +if [ "x${WARNMSG}" = "x" ]; then + : > "fragments.concat" +else + printf '%s\n' "$WARNMSG" > "fragments.concat" +fi + +# find all the files in the fragments directory, sort them numerically and concat to fragments.concat in the working dir +IFS_BACKUP=$IFS +IFS=' +' +for fragfile in `find fragments/ -type f -follow -print0 | xargs -0 -n1 basename | LC_ALL=C sort ${SORTARG}` +do + cat "fragments/$fragfile" >> "fragments.concat" + # Handle newlines. + if [ "x${ENSURE_NEWLINE}" != "x" ]; then + echo >> "fragments.concat" + fi +done +IFS=$IFS_BACKUP + +if [ "x${TEST}" = "x" ]; then + # This is a real run, copy the file to outfile + cp fragments.concat "${OUTFILE}" + RETVAL=$? +else + # Just compare the result to outfile to help the exec decide + cmp "${OUTFILE}" fragments.concat + RETVAL=$? +fi + +exit $RETVAL diff --git a/modules/dependencies/concat/lib/facter/concat_basedir.rb b/modules/dependencies/concat/lib/facter/concat_basedir.rb new file mode 100644 index 000000000..bfac07102 --- /dev/null +++ b/modules/dependencies/concat/lib/facter/concat_basedir.rb @@ -0,0 +1,11 @@ +# == Fact: concat_basedir +# +# A custom fact that sets the default location for fragments +# +# "${::vardir}/concat/" +# +Facter.add("concat_basedir") do + setcode do + File.join(Puppet[:vardir],"concat") + end +end diff --git a/modules/dependencies/concat/lib/puppet/parser/functions/concat_getparam.rb b/modules/dependencies/concat/lib/puppet/parser/functions/concat_getparam.rb new file mode 100644 index 000000000..1757bdc54 --- /dev/null +++ b/modules/dependencies/concat/lib/puppet/parser/functions/concat_getparam.rb @@ -0,0 +1,35 @@ +# Test whether a given class or definition is defined +require 'puppet/parser/functions' + +Puppet::Parser::Functions.newfunction(:concat_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" + } + + concat_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/modules/dependencies/concat/lib/puppet/parser/functions/concat_is_bool.rb b/modules/dependencies/concat/lib/puppet/parser/functions/concat_is_bool.rb new file mode 100644 index 000000000..c2c2a9f2e --- /dev/null +++ b/modules/dependencies/concat/lib/puppet/parser/functions/concat_is_bool.rb @@ -0,0 +1,22 @@ +# +# concat_is_bool.rb +# + +module Puppet::Parser::Functions + newfunction(:concat_is_bool, :type => :rvalue, :doc => <<-EOS +Returns true if the variable passed to this function is a boolean. + EOS + ) do |arguments| + + raise(Puppet::ParseError, "concat_is_bool(): Wrong number of arguments " + + "given (#{arguments.size} for 1)") if arguments.size != 1 + + type = arguments[0] + + result = type.is_a?(TrueClass) || type.is_a?(FalseClass) + + return result + end +end + +# vim: set ts=2 sw=2 et : diff --git a/modules/dependencies/concat/manifests/fragment.pp b/modules/dependencies/concat/manifests/fragment.pp new file mode 100644 index 000000000..34ec4c248 --- /dev/null +++ b/modules/dependencies/concat/manifests/fragment.pp @@ -0,0 +1,124 @@ +# == Define: concat::fragment +# +# Puts a file fragment into a directory previous setup using concat +# +# === Options: +# +# [*target*] +# The file that these fragments belong to +# [*content*] +# If present puts the content into the file +# [*source*] +# If content was not specified, use the source +# [*order*] +# By default all files gets a 10_ prefix in the directory you can set it to +# anything else using this to influence the order of the content in the file +# [*ensure*] +# Present/Absent or destination to a file to include another file +# [*mode*] +# Deprecated +# [*owner*] +# Deprecated +# [*group*] +# Deprecated +# [*backup*] +# Deprecated +# +define concat::fragment( + $target, + $content = undef, + $source = undef, + $order = '10', + $ensure = undef, + $mode = undef, + $owner = undef, + $group = undef, + $backup = undef +) { + validate_string($target) + validate_string($content) + if !(is_string($source) or is_array($source)) { + fail('$source is not a string or an Array.') + } + if !(is_string($order) or is_integer($order)) { + fail('$order is not a string or integer.') + } + if $mode { + warning('The $mode parameter to concat::fragment is deprecated and has no effect') + } + if $owner { + warning('The $owner parameter to concat::fragment is deprecated and has no effect') + } + if $group { + warning('The $group parameter to concat::fragment is deprecated and has no effect') + } + if $backup { + warning('The $backup parameter to concat::fragment is deprecated and has no effect') + } + if $ensure == undef { + $my_ensure = concat_getparam(Concat[$target], 'ensure') + } else { + if ! ($ensure in [ 'present', 'absent' ]) { + warning('Passing a value other than \'present\' or \'absent\' as the $ensure parameter to concat::fragment is deprecated. If you want to use the content of a file as a fragment please use the $source parameter.') + } + $my_ensure = $ensure + } + + include concat::setup + + $safe_name = regsubst($name, '[/:\n]', '_', 'GM') + $safe_target_name = regsubst($target, '[/:\n]', '_', 'GM') + $concatdir = $concat::setup::concatdir + $fragdir = "${concatdir}/${safe_target_name}" + $fragowner = $concat::setup::fragment_owner + $fragmode = $concat::setup::fragment_mode + + # The file type's semantics are problematic in that ensure => present will + # not over write a pre-existing symlink. We are attempting to provide + # backwards compatiblity with previous concat::fragment versions that + # supported the file type's ensure => /target syntax + + # be paranoid and only allow the fragment's file resource's ensure param to + # be file, absent, or a file target + $safe_ensure = $my_ensure ? { + '' => 'file', + undef => 'file', + 'file' => 'file', + 'present' => 'file', + 'absent' => 'absent', + default => $my_ensure, + } + + # if it looks line ensure => /target syntax was used, fish that out + if ! ($my_ensure in ['', 'present', 'absent', 'file' ]) { + $ensure_target = $my_ensure + } else { + $ensure_target = undef + } + + # the file type's semantics only allows one of: ensure => /target, content, + # or source + if ($ensure_target and $source) or + ($ensure_target and $content) or + ($source and $content) { + fail('You cannot specify more than one of $content, $source, $ensure => /target') + } + + if ! ($content or $source or $ensure_target) { + crit('No content, source or symlink specified') + } + + # punt on group ownership until some point in the distant future when $::gid + # can be relied on to be present + file { "${fragdir}/fragments/${order}_${safe_name}": + ensure => $safe_ensure, + owner => $fragowner, + mode => $fragmode, + source => $source, + content => $content, + backup => false, + replace => true, + alias => "concat_fragment_${name}", + notify => Exec["concat_${target}"] + } +} diff --git a/modules/dependencies/concat/manifests/init.pp b/modules/dependencies/concat/manifests/init.pp new file mode 100644 index 000000000..77f9d5fd2 --- /dev/null +++ b/modules/dependencies/concat/manifests/init.pp @@ -0,0 +1,236 @@ +# == Define: concat +# +# Sets up so that you can use fragments to build a final config file, +# +# === Options: +# +# [*ensure*] +# Present/Absent +# [*path*] +# The path to the final file. Use this in case you want to differentiate +# between the name of a resource and the file path. Note: Use the name you +# provided in the target of your fragments. +# [*owner*] +# Who will own the file +# [*group*] +# Who will own the file +# [*mode*] +# The mode of the final file +# [*force*] +# Enables creating empty files if no fragments are present +# [*warn*] +# Adds a normal shell style comment top of the file indicating that it is +# built by puppet +# [*force*] +# [*backup*] +# Controls the filebucketing behavior of the final file and see File type +# reference for its use. Defaults to 'puppet' +# [*replace*] +# Whether to replace a file that already exists on the local system +# [*order*] +# [*ensure_newline*] +# [*gnu*] +# Deprecated +# +# === Actions: +# * Creates fragment directories if it didn't exist already +# * Executes the concatfragments.sh script to build the final file, this +# script will create directory/fragments.concat. Execution happens only +# when: +# * The directory changes +# * fragments.concat != final destination, this means rebuilds will happen +# whenever someone changes or deletes the final file. Checking is done +# using /usr/bin/cmp. +# * The Exec gets notified by something else - like the concat::fragment +# define +# * Copies the file over to the final destination using a file resource +# +# === Aliases: +# +# * The exec can notified using Exec["concat_/path/to/file"] or +# Exec["concat_/path/to/directory"] +# * The final file can be referenced as File["/path/to/file"] or +# File["concat_/path/to/file"] +# +define concat( + $ensure = 'present', + $path = $name, + $owner = undef, + $group = undef, + $mode = '0644', + $warn = false, + $force = false, + $backup = 'puppet', + $replace = true, + $order = 'alpha', + $ensure_newline = false, + $gnu = undef +) { + validate_re($ensure, '^present$|^absent$') + validate_absolute_path($path) + validate_string($owner) + validate_string($group) + validate_string($mode) + if ! (is_string($warn) or $warn == true or $warn == false) { + fail('$warn is not a string or boolean') + } + validate_bool($force) + if ! concat_is_bool($backup) and ! is_string($backup) { + fail('$backup must be string or bool!') + } + validate_bool($replace) + validate_re($order, '^alpha$|^numeric$') + validate_bool($ensure_newline) + if $gnu { + warning('The $gnu parameter to concat is deprecated and has no effect') + } + + include concat::setup + + $safe_name = regsubst($name, '[/:]', '_', 'G') + $concatdir = $concat::setup::concatdir + $fragdir = "${concatdir}/${safe_name}" + $concat_name = 'fragments.concat.out' + $script_command = $concat::setup::script_command + $default_warn_message = '# This file is managed by Puppet. DO NOT EDIT.' + $bool_warn_message = 'Using stringified boolean values (\'true\', \'yes\', \'on\', \'false\', \'no\', \'off\') to represent boolean true/false as the $warn parameter to concat is deprecated and will be treated as the warning message in a future release' + + case $warn { + true: { + $warn_message = $default_warn_message + } + 'true', 'yes', 'on': { + warning($bool_warn_message) + $warn_message = $default_warn_message + } + false: { + $warn_message = '' + } + 'false', 'no', 'off': { + warning($bool_warn_message) + $warn_message = '' + } + default: { + $warn_message = $warn + } + } + + $warnmsg_escaped = regsubst($warn_message, '\'', '\'\\\'\'', 'G') + $warnflag = $warnmsg_escaped ? { + '' => '', + default => "-w '${warnmsg_escaped}'" + } + + $forceflag = $force ? { + true => '-f', + false => '', + } + + $orderflag = $order ? { + 'numeric' => '-n', + 'alpha' => '', + } + + $newlineflag = $ensure_newline ? { + true => '-l', + false => '', + } + + File { + backup => false, + } + + if $ensure == 'present' { + file { $fragdir: + ensure => directory, + mode => '0750', + } + + file { "${fragdir}/fragments": + ensure => directory, + mode => '0750', + force => true, + ignore => ['.svn', '.git', '.gitignore'], + notify => Exec["concat_${name}"], + purge => true, + recurse => true, + } + + file { "${fragdir}/fragments.concat": + ensure => present, + mode => '0640', + } + + file { "${fragdir}/${concat_name}": + ensure => present, + mode => '0640', + } + + file { $name: + ensure => present, + owner => $owner, + group => $group, + mode => $mode, + replace => $replace, + path => $path, + alias => "concat_${name}", + source => "${fragdir}/${concat_name}", + backup => $backup, + } + + # remove extra whitespace from string interpolation to make testing easier + $command = strip(regsubst("${script_command} -o \"${fragdir}/${concat_name}\" -d \"${fragdir}\" ${warnflag} ${forceflag} ${orderflag} ${newlineflag}", '\s+', ' ', 'G')) + + # if puppet is running as root, this exec should also run as root to allow + # the concatfragments.sh script to potentially be installed in path that + # may not be accessible by a target non-root owner. + exec { "concat_${name}": + alias => "concat_${fragdir}", + command => $command, + notify => File[$name], + subscribe => File[$fragdir], + unless => "${command} -t", + path => $::path, + require => [ + File[$fragdir], + File["${fragdir}/fragments"], + File["${fragdir}/fragments.concat"], + ], + } + } else { + file { [ + $fragdir, + "${fragdir}/fragments", + "${fragdir}/fragments.concat", + "${fragdir}/${concat_name}" + ]: + ensure => absent, + force => true, + } + + file { $path: + ensure => absent, + backup => $backup, + } + + $absent_exec_command = $::kernel ? { + 'windows' => 'cmd.exe /c exit 0', + default => 'true', + } + + $absent_exec_path = $::kernel ? { + 'windows' => $::path, + default => '/bin:/usr/bin', + } + + # Need to have an unless here for idempotency. + exec { "concat_${name}": + alias => "concat_${fragdir}", + command => $absent_exec_command, + unless => $absent_exec_command, + path => $absent_exec_path, + } + } +} + +# vim:sw=2:ts=2:expandtab:textwidth=79 diff --git a/modules/dependencies/concat/manifests/setup.pp b/modules/dependencies/concat/manifests/setup.pp new file mode 100644 index 000000000..1a6af6487 --- /dev/null +++ b/modules/dependencies/concat/manifests/setup.pp @@ -0,0 +1,64 @@ +# === Class: concat::setup +# +# Sets up the concat system. This is a private class. +# +# [$concatdir] +# is where the fragments live and is set on the fact concat_basedir. +# Since puppet should always manage files in $concatdir and they should +# not be deleted ever, /tmp is not an option. +# +# It also copies out the concatfragments.{sh,rb} file to ${concatdir}/bin +# +class concat::setup { + if $caller_module_name != $module_name { + warning("${name} is deprecated as a public API of the ${module_name} module and should no longer be directly included in the manifest.") + } + + if $::concat_basedir { + $concatdir = $::concat_basedir + } else { + fail ('$concat_basedir not defined. Try running again with pluginsync=true on the [master] and/or [main] section of your node\'s \'/etc/puppet/puppet.conf\'.') + } + + # owner and mode of fragment files (on windows owner and access rights should + # be inherited from concatdir and not explicitly set to avoid problems) + $fragment_owner = $::osfamily ? { 'windows' => undef, default => $::id } + $fragment_mode = $::osfamily ? { 'windows' => undef, default => '0640' } + + # PR #174 introduced changes to the concatfragments.sh script that are + # incompatible with Solaris 10 but reportedly OK on Solaris 11. As a work + # around we are enable the .rb concat script on all Solaris versions. If + # this goes smoothly, we should move towards completely eliminating the .sh + # version. + $script_name = $::osfamily? { + /(?i:(Windows|Solaris))/ => 'concatfragments.rb', + default => 'concatfragments.sh' + } + + $script_path = "${concatdir}/bin/${script_name}" + + $script_owner = $::osfamily ? { 'windows' => undef, default => $::id } + + $script_mode = $::osfamily ? { 'windows' => undef, default => '0755' } + + $script_command = $::osfamily? { + 'windows' => "ruby.exe '${script_path}'", + default => $script_path + } + + File { + backup => false, + } + + file { $script_path: + ensure => file, + owner => $script_owner, + mode => $script_mode, + source => "puppet:///modules/concat/${script_name}", + } + + file { [ $concatdir, "${concatdir}/bin" ]: + ensure => directory, + mode => '0755', + } +} diff --git a/modules/dependencies/concat/metadata.json b/modules/dependencies/concat/metadata.json new file mode 100644 index 000000000..93bb4b9f6 --- /dev/null +++ b/modules/dependencies/concat/metadata.json @@ -0,0 +1,108 @@ +{ + "name": "puppetlabs-concat", + "version": "1.1.1", + "author": "Puppet Labs", + "summary": "Concat module", + "license": "Apache-2.0", + "source": "https://github.com/puppetlabs/puppetlabs-concat", + "project_page": "https://github.com/puppetlabs/puppetlabs-concat", + "issues_url": "https://github.com/puppetlabs/puppetlabs-concat/issues", + "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": [ + "11 SP1" + ] + }, + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "6", + "7" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "10.04", + "12.04", + "14.04" + ] + }, + { + "operatingsystem": "Solaris", + "operatingsystemrelease": [ + "10", + "11" + ] + }, + { + "operatingsystem": "Windows", + "operatingsystemrelease": [ + "Server 2003 R2", + "Server 2008 R2", + "Server 2012", + "Server 2012 R2" + ] + }, + { + "operatingsystem": "AIX", + "operatingsystemrelease": [ + "5.3", + "6.1", + "7.1" + ] + }, + { + "operatingsystem": "OSX", + "operatingsystemrelease": [ + "10.9" + ] + } + ], + "requirements": [ + { + "name": "pe", + "version_requirement": "3.x" + }, + { + "name": "puppet", + "version_requirement": "3.x" + } + ], + "dependencies": [ + {"name":"puppetlabs/stdlib","version_requirement":">= 3.2.0 < 5.0.0"} + ] +} diff --git a/modules/dependencies/concat/spec/acceptance/backup_spec.rb b/modules/dependencies/concat/spec/acceptance/backup_spec.rb new file mode 100644 index 000000000..1989f4458 --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/backup_spec.rb @@ -0,0 +1,115 @@ +require 'spec_helper_acceptance' + +describe 'concat backup parameter' do + basedir = default.tmpdir('concat') + context '=> puppet' do + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + file { '#{basedir}/file': + content => "old contents\n", + } + EOS + apply_manifest(pp) + end + pp = <<-EOS + concat { '#{basedir}/file': + backup => 'puppet', + } + concat::fragment { 'new file': + target => '#{basedir}/file', + content => 'new contents', + } + EOS + + it 'applies the manifest twice with "Filebucketed" stdout and no stderr' do + apply_manifest(pp, :catch_failures => true) do |r| + expect(r.stdout).to match(/Filebucketed #{basedir}\/file to puppet with sum 0140c31db86293a1a1e080ce9b91305f/) # sum is for file contents of 'old contents' + end + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it { should contain 'new contents' } + end + end + + context '=> .backup' do + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + file { '#{basedir}/file': + content => "old contents\n", + } + EOS + apply_manifest(pp) + end + pp = <<-EOS + concat { '#{basedir}/file': + backup => '.backup', + } + concat::fragment { 'new file': + target => '#{basedir}/file', + content => 'new contents', + } + EOS + + # XXX Puppet doesn't mention anything about filebucketing with a given + # extension like .backup + it 'applies the manifest twice no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it { should contain 'new contents' } + end + describe file("#{basedir}/file.backup") do + it { should be_file } + it { should contain 'old contents' } + end + end + + # XXX The backup parameter uses validate_string() and thus can't be the + # boolean false value, but the string 'false' has the same effect in Puppet 3 + context "=> 'false'" do + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + file { '#{basedir}/file': + content => "old contents\n", + } + EOS + apply_manifest(pp) + end + pp = <<-EOS + concat { '#{basedir}/file': + backup => '.backup', + } + concat::fragment { 'new file': + target => '#{basedir}/file', + content => 'new contents', + } + EOS + + it 'applies the manifest twice with no "Filebucketed" stdout and no stderr' do + apply_manifest(pp, :catch_failures => true) do |r| + expect(r.stdout).to_not match(/Filebucketed/) + end + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it { should contain 'new contents' } + end + end +end diff --git a/modules/dependencies/concat/spec/acceptance/concat_spec.rb b/modules/dependencies/concat/spec/acceptance/concat_spec.rb new file mode 100644 index 000000000..10f72d91c --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/concat_spec.rb @@ -0,0 +1,215 @@ +require 'spec_helper_acceptance' + +case fact('osfamily') +when 'AIX' + username = 'root' + groupname = 'system' + scriptname = 'concatfragments.sh' + vardir = default['puppetvardir'] +when 'Darwin' + username = 'root' + groupname = 'wheel' + scriptname = 'concatfragments.sh' + vardir = default['puppetvardir'] +when 'windows' + username = 'Administrator' + groupname = 'Administrators' + scriptname = 'concatfragments.rb' + result = on default, "echo #{default['puppetvardir']}" + vardir = result.raw_output.chomp +when 'Solaris' + username = 'root' + groupname = 'root' + scriptname = 'concatfragments.rb' + vardir = default['puppetvardir'] +else + username = 'root' + groupname = 'root' + scriptname = 'concatfragments.sh' + vardir = default['puppetvardir'] +end + +describe 'basic concat test' do + basedir = default.tmpdir('concat') + safe_basedir = basedir.gsub(/[\/:]/,'_') + + shared_examples 'successfully_applied' do |pp| + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{vardir}/concat") do + it { should be_directory } + it { should be_owned_by username } + it("should be mode", :unless => (fact('osfamily') == 'AIX')) { + should be_mode 755 + } + end + describe file("#{vardir}/concat/bin") do + it { should be_directory } + it { should be_owned_by username } + it("should be mode", :unless => (fact('osfamily') == 'AIX')) { + should be_mode 755 + } + end + describe file("#{vardir}/concat/bin/#{scriptname}") do + it { should be_file } + it { should be_owned_by username } + it("should be mode", :unless => (fact('osfamily') == 'AIX')) { + should be_mode 755 + } + end + describe file("#{vardir}/concat/#{safe_basedir}_file") do + it { should be_directory } + it { should be_owned_by username } + it("should be mode", :unless => (fact('osfamily') == 'AIX')) { + should be_mode 750 + } + end + describe file("#{vardir}/concat/#{safe_basedir}_file/fragments") do + it { should be_directory } + it { should be_owned_by username } + it("should be mode", :unless => (fact('osfamily') == 'AIX')) { + should be_mode 750 + } + end + describe file("#{vardir}/concat/#{safe_basedir}_file/fragments.concat") do + it { should be_file } + it { should be_owned_by username } + it("should be mode", :unless => (fact('osfamily') == 'AIX')) { + should be_mode 640 + } + end + describe file("#{vardir}/concat/#{safe_basedir}_file/fragments.concat.out") do + it { should be_file } + it { should be_owned_by username } + it("should be mode", :unless => (fact('osfamily') == 'AIX')) { + should be_mode 640 + } + end + end + + context 'owner/group root' do + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + EOS + apply_manifest(pp) + end + pp = <<-EOS + concat { '#{basedir}/file': + owner => '#{username}', + group => '#{groupname}', + mode => '0644', + } + + concat::fragment { '1': + target => '#{basedir}/file', + content => '1', + order => '01', + } + + concat::fragment { '2': + target => '#{basedir}/file', + content => '2', + order => '02', + } + EOS + + it_behaves_like 'successfully_applied', pp + + describe file("#{basedir}/file") do + it { should be_file } + it { should be_owned_by username } + it { should be_grouped_into groupname } + it("should be mode", :unless => (fact('osfamily') == 'AIX')) { + should be_mode 644 + } + it { should contain '1' } + it { should contain '2' } + end + describe file("#{vardir}/concat/#{safe_basedir}_file/fragments/01_1") do + it { should be_file } + it { should be_owned_by username } + it("should be mode", :unless => (fact('osfamily') == 'AIX')) { + should be_mode 640 + } + end + describe file("#{vardir}/concat/#{safe_basedir}_file/fragments/02_2") do + it { should be_file } + it { should be_owned_by username } + it("should be mode", :unless => (fact('osfamily') == 'AIX')) { + should be_mode 640 + } + end + end + + context 'ensure' do + context 'works when set to present with path set' do + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + EOS + apply_manifest(pp) + end + pp=" + concat { 'file': + ensure => present, + path => '#{basedir}/file', + mode => '0644', + } + concat::fragment { '1': + target => 'file', + content => '1', + order => '01', + } + " + + it_behaves_like 'successfully_applied', pp + + describe file("#{basedir}/file") do + it { should be_file } + it("should be mode", :unless => (fact('osfamily') == 'AIX')) { + should be_mode 644 + } + it { should contain '1' } + end + end + context 'works when set to absent with path set' do + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + EOS + apply_manifest(pp) + end + pp=" + concat { 'file': + ensure => absent, + path => '#{basedir}/file', + mode => '0644', + } + concat::fragment { '1': + target => 'file', + content => '1', + order => '01', + } + " + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should_not be_file } + end + end + end +end diff --git a/modules/dependencies/concat/spec/acceptance/deprecation_warnings_spec.rb b/modules/dependencies/concat/spec/acceptance/deprecation_warnings_spec.rb new file mode 100644 index 000000000..7b0f5c50c --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/deprecation_warnings_spec.rb @@ -0,0 +1,233 @@ +require 'spec_helper_acceptance' + +describe 'deprecation warnings' do + basedir = default.tmpdir('concat') + + shared_examples 'has_warning'do |pp, w| + it 'applies the manifest twice with a stderr regex' do + expect(apply_manifest(pp, :catch_failures => true).stderr).to match(/#{Regexp.escape(w)}/m) + expect(apply_manifest(pp, :catch_changes => true).stderr).to match(/#{Regexp.escape(w)}/m) + end + end + + context 'concat gnu parameter' do + pp = <<-EOS + concat { '#{basedir}/file': + gnu => 'foo', + } + concat::fragment { 'foo': + target => '#{basedir}/file', + content => 'bar', + } + EOS + w = 'The $gnu parameter to concat is deprecated and has no effect' + + it_behaves_like 'has_warning', pp, w + end + + context 'concat warn parameter =>' do + ['true', 'yes', 'on'].each do |warn| + context warn do + pp = <<-EOS + concat { '#{basedir}/file': + warn => '#{warn}', + } + concat::fragment { 'foo': + target => '#{basedir}/file', + content => 'bar', + } + EOS + w = 'Using stringified boolean values (\'true\', \'yes\', \'on\', \'false\', \'no\', \'off\') to represent boolean true/false as the $warn parameter to concat is deprecated and will be treated as the warning message in a future release' + + it_behaves_like 'has_warning', pp, w + + describe file("#{basedir}/file") do + it { should be_file } + it { should contain '# This file is managed by Puppet. DO NOT EDIT.' } + it { should contain 'bar' } + end + end + end + + ['false', 'no', 'off'].each do |warn| + context warn do + pp = <<-EOS + concat { '#{basedir}/file': + warn => '#{warn}', + } + concat::fragment { 'foo': + target => '#{basedir}/file', + content => 'bar', + } + EOS + w = 'Using stringified boolean values (\'true\', \'yes\', \'on\', \'false\', \'no\', \'off\') to represent boolean true/false as the $warn parameter to concat is deprecated and will be treated as the warning message in a future release' + + it_behaves_like 'has_warning', pp, w + + describe file("#{basedir}/file") do + it { should be_file } + it { should_not contain '# This file is managed by Puppet. DO NOT EDIT.' } + it { should contain 'bar' } + end + end + end + end + + context 'concat::fragment ensure parameter' do + context 'target file exists' do + before(:all) do + shell("/bin/echo 'file1 contents' > #{basedir}/file1") + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + file { '#{basedir}/file1': + content => "file1 contents\n", + } + EOS + apply_manifest(pp) + end + + pp = <<-EOS + concat { '#{basedir}/file': } + concat::fragment { 'foo': + target => '#{basedir}/file', + ensure => '#{basedir}/file1', + } + EOS + w = 'Passing a value other than \'present\' or \'absent\' as the $ensure parameter to concat::fragment is deprecated. If you want to use the content of a file as a fragment please use the $source parameter.' + + it_behaves_like 'has_warning', pp, w + + describe file("#{basedir}/file") do + it { should be_file } + it { should contain 'file1 contents' } + end + + describe 'the fragment can be changed from a symlink to a plain file', :unless => (fact("osfamily") == "windows") do + pp = <<-EOS + concat { '#{basedir}/file': } + concat::fragment { 'foo': + target => '#{basedir}/file', + content => 'new content', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it { should contain 'new content' } + it { should_not contain 'file1 contents' } + end + end + end # target file exists + + context 'target does not exist' do + pp = <<-EOS + concat { '#{basedir}/file': } + concat::fragment { 'foo': + target => '#{basedir}/file', + ensure => '#{basedir}/file1', + } + EOS + w = 'Passing a value other than \'present\' or \'absent\' as the $ensure parameter to concat::fragment is deprecated. If you want to use the content of a file as a fragment please use the $source parameter.' + + it_behaves_like 'has_warning', pp, w + + describe file("#{basedir}/file") do + it { should be_file } + end + + describe 'the fragment can be changed from a symlink to a plain file', :unless => (fact('osfamily') == 'windows') do + pp = <<-EOS + concat { '#{basedir}/file': } + concat::fragment { 'foo': + target => '#{basedir}/file', + content => 'new content', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it { should contain 'new content' } + end + end + end # target file exists + + end # concat::fragment ensure parameter + + context 'concat::fragment mode parameter' do + pp = <<-EOS + concat { '#{basedir}/file': } + concat::fragment { 'foo': + target => '#{basedir}/file', + content => 'bar', + mode => 'bar', + } + EOS + w = 'The $mode parameter to concat::fragment is deprecated and has no effect' + + it_behaves_like 'has_warning', pp, w + end + + context 'concat::fragment owner parameter' do + pp = <<-EOS + concat { '#{basedir}/file': } + concat::fragment { 'foo': + target => '#{basedir}/file', + content => 'bar', + owner => 'bar', + } + EOS + w = 'The $owner parameter to concat::fragment is deprecated and has no effect' + + it_behaves_like 'has_warning', pp, w + end + + context 'concat::fragment group parameter' do + pp = <<-EOS + concat { '#{basedir}/file': } + concat::fragment { 'foo': + target => '#{basedir}/file', + content => 'bar', + group => 'bar', + } + EOS + w = 'The $group parameter to concat::fragment is deprecated and has no effect' + + it_behaves_like 'has_warning', pp, w + end + + context 'concat::fragment backup parameter' do + pp = <<-EOS + concat { '#{basedir}/file': } + concat::fragment { 'foo': + target => '#{basedir}/file', + content => 'bar', + backup => 'bar', + } + EOS + w = 'The $backup parameter to concat::fragment is deprecated and has no effect' + + it_behaves_like 'has_warning', pp, w + end + + context 'include concat::setup' do + pp = <<-EOS + include concat::setup + EOS + w = 'concat::setup is deprecated as a public API of the concat module and should no longer be directly included in the manifest.' + + it_behaves_like 'has_warning', pp, w + end + +end diff --git a/modules/dependencies/concat/spec/acceptance/empty_spec.rb b/modules/dependencies/concat/spec/acceptance/empty_spec.rb new file mode 100644 index 000000000..dc57cb791 --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/empty_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper_acceptance' + +describe 'concat force empty parameter' do + basedir = default.tmpdir('concat') + context 'should run successfully' do + pp = <<-EOS + concat { '#{basedir}/file': + mode => '0644', + force => true, + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it { should_not contain '1\n2' } + end + end +end diff --git a/modules/dependencies/concat/spec/acceptance/fragment_source_spec.rb b/modules/dependencies/concat/spec/acceptance/fragment_source_spec.rb new file mode 100644 index 000000000..f3bbfccdf --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/fragment_source_spec.rb @@ -0,0 +1,149 @@ +require 'spec_helper_acceptance' + +case fact('osfamily') +when 'AIX' + username = 'root' + groupname = 'system' +when 'Darwin' + username = 'root' + groupname = 'wheel' +when 'windows' + username = 'Administrator' + groupname = 'Administrators' +else + username = 'root' + groupname = 'root' +end + +describe 'concat::fragment source' do + basedir = default.tmpdir('concat') + context 'should read file fragments from local system' do + pp = <<-EOS + file { '#{basedir}/file1': + content => "file1 contents\n" + } + file { '#{basedir}/file2': + content => "file2 contents\n" + } + concat { '#{basedir}/foo': } + + concat::fragment { '1': + target => '#{basedir}/foo', + source => '#{basedir}/file1', + require => File['#{basedir}/file1'], + } + concat::fragment { '2': + target => '#{basedir}/foo', + content => 'string1 contents', + } + concat::fragment { '3': + target => '#{basedir}/foo', + source => '#{basedir}/file2', + require => File['#{basedir}/file2'], + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/foo") do + it { should be_file } + it { should contain 'file1 contents' } + it { should contain 'string1 contents' } + it { should contain 'file2 contents' } + end + end # should read file fragments from local system + + context 'should create files containing first match only.' do + pp = <<-EOS + file { '#{basedir}/file1': + content => "file1 contents\n" + } + file { '#{basedir}/file2': + content => "file2 contents\n" + } + concat { '#{basedir}/result_file1': + owner => '#{username}', + group => '#{groupname}', + mode => '0644', + } + concat { '#{basedir}/result_file2': + owner => '#{username}', + group => '#{groupname}', + mode => '0644', + } + concat { '#{basedir}/result_file3': + owner => '#{username}', + group => '#{groupname}', + mode => '0644', + } + + concat::fragment { '1': + target => '#{basedir}/result_file1', + source => [ '#{basedir}/file1', '#{basedir}/file2' ], + require => [ File['#{basedir}/file1'], File['#{basedir}/file2'] ], + order => '01', + } + concat::fragment { '2': + target => '#{basedir}/result_file2', + source => [ '#{basedir}/file2', '#{basedir}/file1' ], + require => [ File['#{basedir}/file1'], File['#{basedir}/file2'] ], + order => '01', + } + concat::fragment { '3': + target => '#{basedir}/result_file3', + source => [ '#{basedir}/file1', '#{basedir}/file2' ], + require => [ File['#{basedir}/file1'], File['#{basedir}/file2'] ], + order => '01', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + describe file("#{basedir}/result_file1") do + it { should be_file } + it { should contain 'file1 contents' } + it { should_not contain 'file2 contents' } + end + describe file("#{basedir}/result_file2") do + it { should be_file } + it { should contain 'file2 contents' } + it { should_not contain 'file1 contents' } + end + describe file("#{basedir}/result_file3") do + it { should be_file } + it { should contain 'file1 contents' } + it { should_not contain 'file2 contents' } + end + end + + context 'should fail if no match on source.' do + pp = <<-EOS + concat { '#{basedir}/fail_no_source': + owner => '#{username}', + group => '#{groupname}', + mode => '0644', + } + + concat::fragment { '1': + target => '#{basedir}/fail_no_source', + source => [ '#{basedir}/nofilehere', '#{basedir}/nothereeither' ], + order => '01', + } + EOS + + it 'applies the manifest with resource failures' do + apply_manifest(pp, :expect_failures => true) + end + describe file("#{basedir}/fail_no_source") do + #FIXME: Serverspec::Type::File doesn't support exists? for some reason. so... hack. + it { should_not be_file } + it { should_not be_directory } + end + end +end + diff --git a/modules/dependencies/concat/spec/acceptance/fragments_are_always_replaced_spec.rb b/modules/dependencies/concat/spec/acceptance/fragments_are_always_replaced_spec.rb new file mode 100644 index 000000000..ac714a964 --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/fragments_are_always_replaced_spec.rb @@ -0,0 +1,133 @@ +require 'spec_helper_acceptance' + +describe 'concat::fragment replace' do + basedir = default.tmpdir('concat') + + context 'should create fragment files' do + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + EOS + apply_manifest(pp) + end + + pp1 = <<-EOS + concat { '#{basedir}/foo': } + + concat::fragment { '1': + target => '#{basedir}/foo', + content => 'caller has replace unset run 1', + } + EOS + pp2 = <<-EOS + concat { '#{basedir}/foo': } + + concat::fragment { '1': + target => '#{basedir}/foo', + content => 'caller has replace unset run 2', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp1, :catch_failures => true) + apply_manifest(pp1, :catch_changes => true) + apply_manifest(pp2, :catch_failures => true) + apply_manifest(pp2, :catch_changes => true) + end + + describe file("#{basedir}/foo") do + it { should be_file } + it { should_not contain 'caller has replace unset run 1' } + it { should contain 'caller has replace unset run 2' } + end + end # should create fragment files + + context 'should replace its own fragment files when caller has File { replace=>true } set' do + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + EOS + apply_manifest(pp) + end + + pp1 = <<-EOS + File { replace=>true } + concat { '#{basedir}/foo': } + + concat::fragment { '1': + target => '#{basedir}/foo', + content => 'caller has replace true set run 1', + } + EOS + pp2 = <<-EOS + File { replace=>true } + concat { '#{basedir}/foo': } + + concat::fragment { '1': + target => '#{basedir}/foo', + content => 'caller has replace true set run 2', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp1, :catch_failures => true) + apply_manifest(pp1, :catch_changes => true) + apply_manifest(pp2, :catch_failures => true) + apply_manifest(pp2, :catch_changes => true) + end + + describe file("#{basedir}/foo") do + it { should be_file } + it { should_not contain 'caller has replace true set run 1' } + it { should contain 'caller has replace true set run 2' } + end + end # should replace its own fragment files when caller has File(replace=>true) set + + context 'should replace its own fragment files even when caller has File { replace=>false } set' do + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + EOS + apply_manifest(pp) + end + + pp1 = <<-EOS + File { replace=>false } + concat { '#{basedir}/foo': } + + concat::fragment { '1': + target => '#{basedir}/foo', + content => 'caller has replace false set run 1', + } + EOS + pp2 = <<-EOS + File { replace=>false } + concat { '#{basedir}/foo': } + + concat::fragment { '1': + target => '#{basedir}/foo', + content => 'caller has replace false set run 2', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp1, :catch_failures => true) + apply_manifest(pp1, :catch_changes => true) + apply_manifest(pp2, :catch_failures => true) + apply_manifest(pp2, :catch_changes => true) + end + + describe file("#{basedir}/foo") do + it { should be_file } + it { should_not contain 'caller has replace false set run 1' } + it { should contain 'caller has replace false set run 2' } + end + end # should replace its own fragment files even when caller has File(replace=>false) set + +end diff --git a/modules/dependencies/concat/spec/acceptance/newline_spec.rb b/modules/dependencies/concat/spec/acceptance/newline_spec.rb new file mode 100644 index 000000000..d182f2adc --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/newline_spec.rb @@ -0,0 +1,67 @@ +require 'spec_helper_acceptance' + +describe 'concat ensure_newline parameter' do + basedir = default.tmpdir('concat') + context '=> false' do + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory + } + EOS + + apply_manifest(pp) + end + pp = <<-EOS + concat { '#{basedir}/file': + ensure_newline => false, + } + concat::fragment { '1': + target => '#{basedir}/file', + content => '1', + } + concat::fragment { '2': + target => '#{basedir}/file', + content => '2', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it { should contain '12' } + end + end + + context '=> true' do + pp = <<-EOS + concat { '#{basedir}/file': + ensure_newline => true, + } + concat::fragment { '1': + target => '#{basedir}/file', + content => '1', + } + concat::fragment { '2': + target => '#{basedir}/file', + content => '2', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it("should contain 1\n2\n", :unless => (fact('osfamily') == 'Solaris')) { + should contain "1\n2\n" + } + end + end +end diff --git a/modules/dependencies/concat/spec/acceptance/nodesets/aix-71-vcloud.yml b/modules/dependencies/concat/spec/acceptance/nodesets/aix-71-vcloud.yml new file mode 100644 index 000000000..f0ae87a5c --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/nodesets/aix-71-vcloud.yml @@ -0,0 +1,19 @@ +HOSTS: + pe-aix-71-acceptance: + roles: + - master + - dashboard + - database + - agent + - default + platform: aix-7.1-power + hypervisor: aix + ip: pe-aix-71-acceptance.delivery.puppetlabs.net +CONFIG: + type: pe + 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/ diff --git a/modules/dependencies/concat/spec/acceptance/nodesets/centos-59-x64.yml b/modules/dependencies/concat/spec/acceptance/nodesets/centos-59-x64.yml new file mode 100644 index 000000000..2ad90b86a --- /dev/null +++ b/modules/dependencies/concat/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/modules/dependencies/concat/spec/acceptance/nodesets/centos-64-x64-pe.yml b/modules/dependencies/concat/spec/acceptance/nodesets/centos-64-x64-pe.yml new file mode 100644 index 000000000..7d9242f1b --- /dev/null +++ b/modules/dependencies/concat/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/modules/dependencies/concat/spec/acceptance/nodesets/centos-64-x64.yml b/modules/dependencies/concat/spec/acceptance/nodesets/centos-64-x64.yml new file mode 100644 index 000000000..063983549 --- /dev/null +++ b/modules/dependencies/concat/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/modules/dependencies/concat/spec/acceptance/nodesets/centos-65-x64.yml b/modules/dependencies/concat/spec/acceptance/nodesets/centos-65-x64.yml new file mode 100644 index 000000000..4e2cb809e --- /dev/null +++ b/modules/dependencies/concat/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/modules/dependencies/concat/spec/acceptance/nodesets/debian-607-x64.yml b/modules/dependencies/concat/spec/acceptance/nodesets/debian-607-x64.yml new file mode 100644 index 000000000..4c8be42d0 --- /dev/null +++ b/modules/dependencies/concat/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/modules/dependencies/concat/spec/acceptance/nodesets/debian-70rc1-x64.yml b/modules/dependencies/concat/spec/acceptance/nodesets/debian-70rc1-x64.yml new file mode 100644 index 000000000..19181c123 --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/nodesets/debian-70rc1-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + debian-70rc1-x64: + roles: + - master + platform: debian-7-amd64 + box : debian-70rc1-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-70rc1-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: git diff --git a/modules/dependencies/concat/spec/acceptance/nodesets/debian-73-x64.yml b/modules/dependencies/concat/spec/acceptance/nodesets/debian-73-x64.yml new file mode 100644 index 000000000..3e6a3a9dd --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/nodesets/debian-73-x64.yml @@ -0,0 +1,11 @@ +HOSTS: + debian-73-x64.localhost: + 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: + log_level: debug + type: foss diff --git a/modules/dependencies/concat/spec/acceptance/nodesets/default.yml b/modules/dependencies/concat/spec/acceptance/nodesets/default.yml new file mode 100644 index 000000000..063983549 --- /dev/null +++ b/modules/dependencies/concat/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/modules/dependencies/concat/spec/acceptance/nodesets/fedora-18-x64.yml b/modules/dependencies/concat/spec/acceptance/nodesets/fedora-18-x64.yml new file mode 100644 index 000000000..624b53716 --- /dev/null +++ b/modules/dependencies/concat/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/modules/dependencies/concat/spec/acceptance/nodesets/sles-11-x64.yml b/modules/dependencies/concat/spec/acceptance/nodesets/sles-11-x64.yml new file mode 100644 index 000000000..41abe2135 --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/nodesets/sles-11-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + sles-11-x64.local: + roles: + - master + platform: sles-11-x64 + box : sles-11sp1-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: foss diff --git a/modules/dependencies/concat/spec/acceptance/nodesets/sles-11sp1-x64.yml b/modules/dependencies/concat/spec/acceptance/nodesets/sles-11sp1-x64.yml new file mode 100644 index 000000000..554c37a50 --- /dev/null +++ b/modules/dependencies/concat/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/modules/dependencies/concat/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml b/modules/dependencies/concat/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml new file mode 100644 index 000000000..5047017e6 --- /dev/null +++ b/modules/dependencies/concat/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: git diff --git a/modules/dependencies/concat/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml b/modules/dependencies/concat/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml new file mode 100644 index 000000000..1c7a34ccb --- /dev/null +++ b/modules/dependencies/concat/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: git diff --git a/modules/dependencies/concat/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml b/modules/dependencies/concat/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml new file mode 100644 index 000000000..cba1cd04c --- /dev/null +++ b/modules/dependencies/concat/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/modules/dependencies/concat/spec/acceptance/order_spec.rb b/modules/dependencies/concat/spec/acceptance/order_spec.rb new file mode 100644 index 000000000..fd7b05b4f --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/order_spec.rb @@ -0,0 +1,143 @@ +require 'spec_helper_acceptance' + +describe 'concat order' do + basedir = default.tmpdir('concat') + + context '=> alpha' do + pp = <<-EOS + concat { '#{basedir}/foo': + order => 'alpha' + } + concat::fragment { '1': + target => '#{basedir}/foo', + content => 'string1', + } + concat::fragment { '2': + target => '#{basedir}/foo', + content => 'string2', + } + concat::fragment { '10': + target => '#{basedir}/foo', + content => 'string10', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/foo") do + it { should be_file } + #XXX Solaris 10 doesn't support multi-line grep + it("should contain string10\nstring1\nsring2", :unless => (fact('osfamily') == 'Solaris')) { + should contain "string10\nstring1\nsring2" + } + end + end + + context '=> numeric' do + pp = <<-EOS + concat { '#{basedir}/foo': + order => 'numeric' + } + concat::fragment { '1': + target => '#{basedir}/foo', + content => 'string1', + } + concat::fragment { '2': + target => '#{basedir}/foo', + content => 'string2', + } + concat::fragment { '10': + target => '#{basedir}/foo', + content => 'string10', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/foo") do + it { should be_file } + #XXX Solaris 10 doesn't support multi-line grep + it("should contain string1\nstring2\nsring10", :unless => (fact('osfamily') == 'Solaris')) { + should contain "string1\nstring2\nsring10" + } + end + end +end # concat order + +describe 'concat::fragment order' do + basedir = default.tmpdir('concat') + + context '=> reverse order' do + pp = <<-EOS + concat { '#{basedir}/foo': } + concat::fragment { '1': + target => '#{basedir}/foo', + content => 'string1', + order => '15', + } + concat::fragment { '2': + target => '#{basedir}/foo', + content => 'string2', + # default order 10 + } + concat::fragment { '3': + target => '#{basedir}/foo', + content => 'string3', + order => '1', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/foo") do + it { should be_file } + #XXX Solaris 10 doesn't support multi-line grep + it("should contain string3\nstring2\nsring1", :unless => (fact('osfamily') == 'Solaris')) { + should contain "string3\nstring2\nsring1" + } + end + end + + context '=> normal order' do + pp = <<-EOS + concat { '#{basedir}/foo': } + concat::fragment { '1': + target => '#{basedir}/foo', + content => 'string1', + order => '01', + } + concat::fragment { '2': + target => '#{basedir}/foo', + content => 'string2', + order => '02' + } + concat::fragment { '3': + target => '#{basedir}/foo', + content => 'string3', + order => '03', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/foo") do + it { should be_file } + #XXX Solaris 10 doesn't support multi-line grep + it("should contain string1\nstring2\nsring3", :unless => (fact('osfamily') == 'Solaris')) { + should contain "string1\nstring2\nsring3" + } + end + end +end # concat::fragment order diff --git a/modules/dependencies/concat/spec/acceptance/quoted_paths_spec.rb b/modules/dependencies/concat/spec/acceptance/quoted_paths_spec.rb new file mode 100644 index 000000000..1c0248516 --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/quoted_paths_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper_acceptance' + +describe 'quoted paths' do + basedir = default.tmpdir('concat') + + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + file { '#{basedir}/concat test': + ensure => directory, + } + EOS + apply_manifest(pp) + end + + context 'path with blanks' do + pp = <<-EOS + concat { '#{basedir}/concat test/foo': + } + concat::fragment { '1': + target => '#{basedir}/concat test/foo', + content => 'string1', + } + concat::fragment { '2': + target => '#{basedir}/concat test/foo', + content => 'string2', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/concat test/foo") do + it { should be_file } + it("should contain string1\nstring2", :unless => (fact('osfamily') == 'Solaris')) { + should contain "string1\nstring2" + } + end + end +end diff --git a/modules/dependencies/concat/spec/acceptance/replace_spec.rb b/modules/dependencies/concat/spec/acceptance/replace_spec.rb new file mode 100644 index 000000000..cc30d1250 --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/replace_spec.rb @@ -0,0 +1,256 @@ +require 'spec_helper_acceptance' + +describe 'replacement of' do + basedir = default.tmpdir('concat') + context 'file' do + context 'should not succeed' do + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + file { '#{basedir}/file': + content => "file exists\n" + } + EOS + apply_manifest(pp) + end + pp = <<-EOS + concat { '#{basedir}/file': + replace => false, + } + + concat::fragment { '1': + target => '#{basedir}/file', + content => '1', + } + + concat::fragment { '2': + target => '#{basedir}/file', + content => '2', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it { should contain 'file exists' } + it { should_not contain '1' } + it { should_not contain '2' } + end + end + + context 'should succeed' do + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + file { '#{basedir}/file': + content => "file exists\n" + } + EOS + apply_manifest(pp) + end + pp = <<-EOS + concat { '#{basedir}/file': + replace => true, + } + + concat::fragment { '1': + target => '#{basedir}/file', + content => '1', + } + + concat::fragment { '2': + target => '#{basedir}/file', + content => '2', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it { should_not contain 'file exists' } + it { should contain '1' } + it { should contain '2' } + end + end + end # file + + context 'symlink', :unless => (fact("osfamily") == "windows") do + context 'should not succeed' do + # XXX the core puppet file type will replace a symlink with a plain file + # when using ensure => present and source => ... but it will not when using + # ensure => present and content => ...; this is somewhat confusing behavior + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + file { '#{basedir}/file': + ensure => link, + target => '#{basedir}/dangling', + } + EOS + apply_manifest(pp) + end + + pp = <<-EOS + concat { '#{basedir}/file': + replace => false, + } + + concat::fragment { '1': + target => '#{basedir}/file', + content => '1', + } + + concat::fragment { '2': + target => '#{basedir}/file', + content => '2', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + # XXX specinfra doesn't support be_linked_to on AIX + describe file("#{basedir}/file"), :unless => (fact("osfamily") == "AIX") do + it { should be_linked_to "#{basedir}/dangling" } + end + + describe file("#{basedir}/dangling") do + # XXX serverspec does not have a matcher for 'exists' + it { should_not be_file } + it { should_not be_directory } + end + end + + context 'should succeed' do + # XXX the core puppet file type will replace a symlink with a plain file + # when using ensure => present and source => ... but it will not when using + # ensure => present and content => ...; this is somewhat confusing behavior + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + file { '#{basedir}/file': + ensure => link, + target => '#{basedir}/dangling', + } + EOS + apply_manifest(pp) + end + + pp = <<-EOS + concat { '#{basedir}/file': + replace => true, + } + + concat::fragment { '1': + target => '#{basedir}/file', + content => '1', + } + + concat::fragment { '2': + target => '#{basedir}/file', + content => '2', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it { should contain '1' } + it { should contain '2' } + end + end + end # symlink + + context 'directory' do + context 'should not succeed' do + before(:all) do + pp = <<-EOS + file { '#{basedir}': + ensure => directory, + } + file { '#{basedir}/file': + ensure => directory, + } + EOS + apply_manifest(pp) + end + pp = <<-EOS + concat { '#{basedir}/file': } + + concat::fragment { '1': + target => '#{basedir}/file', + content => '1', + } + + concat::fragment { '2': + target => '#{basedir}/file', + content => '2', + } + EOS + + it 'applies the manifest twice with stderr for changing to file' do + expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/change from directory to file failed/) + expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/change from directory to file failed/) + end + + describe file("#{basedir}/file") do + it { should be_directory } + end + end + + # XXX concat's force param currently enables the creation of empty files + # when there are no fragments, and the replace param will only replace + # files and symlinks, not directories. The semantics either need to be + # changed, extended, or a new param introduced to control directory + # replacement. + context 'should succeed', :pending => 'not yet implemented' do + pp = <<-EOS + concat { '#{basedir}/file': + force => true, + } + + concat::fragment { '1': + target => '#{basedir}/file', + content => '1', + } + + concat::fragment { '2': + target => '#{basedir}/file', + content => '2', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it { should contain '1' } + end + end + end # directory +end diff --git a/modules/dependencies/concat/spec/acceptance/symbolic_name_spec.rb b/modules/dependencies/concat/spec/acceptance/symbolic_name_spec.rb new file mode 100644 index 000000000..b0dceac8c --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/symbolic_name_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper_acceptance' + +describe 'symbolic name' do + basedir = default.tmpdir('concat') + pp = <<-EOS + concat { 'not_abs_path': + path => '#{basedir}/file', + } + + concat::fragment { '1': + target => 'not_abs_path', + content => '1', + order => '01', + } + + concat::fragment { '2': + target => 'not_abs_path', + content => '2', + order => '02', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it { should contain '1' } + it { should contain '2' } + end +end diff --git a/modules/dependencies/concat/spec/acceptance/warn_spec.rb b/modules/dependencies/concat/spec/acceptance/warn_spec.rb new file mode 100644 index 000000000..2fa529da2 --- /dev/null +++ b/modules/dependencies/concat/spec/acceptance/warn_spec.rb @@ -0,0 +1,98 @@ +require 'spec_helper_acceptance' + +describe 'concat warn =>' do + basedir = default.tmpdir('concat') + context 'true should enable default warning message' do + pp = <<-EOS + concat { '#{basedir}/file': + warn => true, + } + + concat::fragment { '1': + target => '#{basedir}/file', + content => '1', + order => '01', + } + + concat::fragment { '2': + target => '#{basedir}/file', + content => '2', + order => '02', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it { should contain '# This file is managed by Puppet. DO NOT EDIT.' } + it { should contain '1' } + it { should contain '2' } + end + end + context 'false should not enable default warning message' do + pp = <<-EOS + concat { '#{basedir}/file': + warn => false, + } + + concat::fragment { '1': + target => '#{basedir}/file', + content => '1', + order => '01', + } + + concat::fragment { '2': + target => '#{basedir}/file', + content => '2', + order => '02', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it { should_not contain '# This file is managed by Puppet. DO NOT EDIT.' } + it { should contain '1' } + it { should contain '2' } + end + end + context '# foo should overide default warning message' do + pp = <<-EOS + concat { '#{basedir}/file': + warn => '# foo', + } + + concat::fragment { '1': + target => '#{basedir}/file', + content => '1', + order => '01', + } + + concat::fragment { '2': + target => '#{basedir}/file', + content => '2', + order => '02', + } + EOS + + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe file("#{basedir}/file") do + it { should be_file } + it { should contain '# foo' } + it { should contain '1' } + it { should contain '2' } + end + end +end diff --git a/modules/dependencies/concat/spec/spec.opts b/modules/dependencies/concat/spec/spec.opts new file mode 100644 index 000000000..91cd6427e --- /dev/null +++ b/modules/dependencies/concat/spec/spec.opts @@ -0,0 +1,6 @@ +--format +s +--colour +--loadby +mtime +--backtrace diff --git a/modules/dependencies/concat/spec/spec_helper.rb b/modules/dependencies/concat/spec/spec_helper.rb new file mode 100644 index 000000000..2c6f56649 --- /dev/null +++ b/modules/dependencies/concat/spec/spec_helper.rb @@ -0,0 +1 @@ +require 'puppetlabs_spec_helper/module_spec_helper' diff --git a/modules/dependencies/concat/spec/spec_helper_acceptance.rb b/modules/dependencies/concat/spec/spec_helper_acceptance.rb new file mode 100644 index 000000000..b34a188d6 --- /dev/null +++ b/modules/dependencies/concat/spec/spec_helper_acceptance.rb @@ -0,0 +1,47 @@ +require 'beaker-rspec/spec_helper' +require 'beaker-rspec/helpers/serverspec' + +unless ENV['RS_PROVISION'] == 'no' or ENV['BEAKER_provision'] == 'no' + # This will install the latest available package on el and deb based + # systems fail on windows and osx, and install via gem on other *nixes + foss_opts = { :default_action => 'gem_install' } + + if default.is_pe?; then install_pe; else install_puppet( foss_opts ); end + + hosts.each do |host| + on hosts, "mkdir -p #{host['distmoduledir']}" + end +end + +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| + on host, "mkdir -p #{host['distmoduledir']}/concat" + result = on host, "echo #{host['distmoduledir']}/concat" + target = result.raw_output.chomp + + %w(files lib manifests metadata.json).each do |file| + scp_to host, "#{proj_root}/#{file}", target + end + #copy_module_to(host, :source => proj_root, :module_name => 'concat') + on host, puppet('module','install','puppetlabs-stdlib'), { :acceptable_exit_codes => [0,1] } + end + end + + c.before(:all) do + shell('mkdir -p /tmp/concat') + end + c.after(:all) do + shell('rm -rf /tmp/concat /var/lib/puppet/concat') + end + + c.treat_symbols_as_metadata_keys_with_true_values = true +end diff --git a/modules/dependencies/concat/spec/unit/classes/concat_setup_spec.rb b/modules/dependencies/concat/spec/unit/classes/concat_setup_spec.rb new file mode 100644 index 000000000..3096e7368 --- /dev/null +++ b/modules/dependencies/concat/spec/unit/classes/concat_setup_spec.rb @@ -0,0 +1,84 @@ +require 'spec_helper' + +describe 'concat::setup', :type => :class do + + shared_examples 'setup' do |concatdir| + concatdir = '/foo' if concatdir.nil? + + let(:facts) {{ :concat_basedir => concatdir }} + + it do + should contain_file("#{concatdir}/bin/concatfragments.sh").with({ + :mode => '0755', + :source => 'puppet:///modules/concat/concatfragments.sh', + :backup => false, + }) + end + + [concatdir, "#{concatdir}/bin"].each do |file| + it do + should contain_file(file).with({ + :ensure => 'directory', + :mode => '0755', + :backup => false, + }) + end + end + end + + context 'facts' do + context 'concat_basedir =>' do + context '/foo' do + it_behaves_like 'setup', '/foo' + end + end + end # facts + + context 'deprecated as a public class' do + it 'should create a warning' do + pending('rspec-puppet support for testing warning()') + end + end + + context "on osfamily Solaris" do + concatdir = '/foo' + let(:facts) do + { + :concat_basedir => concatdir, + :osfamily => 'Solaris', + :id => 'root', + } + end + + it do + should contain_file("#{concatdir}/bin/concatfragments.rb").with({ + :ensure => 'file', + :owner => 'root', + :mode => '0755', + :source => 'puppet:///modules/concat/concatfragments.rb', + :backup => false, + }) + end + end # on osfamily Solaris + + context "on osfamily windows" do + concatdir = '/foo' + let(:facts) do + { + :concat_basedir => concatdir, + :osfamily => 'windows', + :id => 'batman', + } + end + + it do + should contain_file("#{concatdir}/bin/concatfragments.rb").with({ + :ensure => 'file', + :owner => nil, + :mode => nil, + :source => 'puppet:///modules/concat/concatfragments.rb', + :backup => false, + }) + end + end # on osfamily windows +end diff --git a/modules/dependencies/concat/spec/unit/defines/concat_fragment_spec.rb b/modules/dependencies/concat/spec/unit/defines/concat_fragment_spec.rb new file mode 100644 index 000000000..3c61aabf7 --- /dev/null +++ b/modules/dependencies/concat/spec/unit/defines/concat_fragment_spec.rb @@ -0,0 +1,267 @@ +require 'spec_helper' + +describe 'concat::fragment', :type => :define do + + shared_examples 'fragment' do |title, params| + params = {} if params.nil? + + p = { + :content => nil, + :source => nil, + :order => 10, + :ensure => 'present', + }.merge(params) + + safe_name = title.gsub(/[\/\n]/, '_') + safe_target_name = p[:target].gsub(/[\/\n]/, '_') + concatdir = '/var/lib/puppet/concat' + fragdir = "#{concatdir}/#{safe_target_name}" + id = 'root' + if p[:ensure] == 'absent' + safe_ensure = p[:ensure] + else + safe_ensure = 'file' + end + + let(:title) { title } + let(:facts) {{ :concat_basedir => concatdir, :id => id }} + let(:params) { params } + let(:pre_condition) do + "concat{ '#{p[:target]}': }" + end + + it do + should contain_class('concat::setup') + should contain_concat(p[:target]) + should contain_file("#{fragdir}/fragments/#{p[:order]}_#{safe_name}").with({ + :ensure => safe_ensure, + :owner => id, + :mode => '0640', + :source => p[:source], + :content => p[:content], + :alias => "concat_fragment_#{title}", + :backup => false, + }) + end + end + + context 'title' do + ['0', '1', 'a', 'z'].each do |title| + it_behaves_like 'fragment', title, { + :target => '/etc/motd', + } + end + end # title + + context 'target =>' do + ['./etc/motd', 'etc/motd', 'motd_header'].each do |target| + context target do + it_behaves_like 'fragment', target, { + :target => '/etc/motd', + } + end + end + + context 'false' do + let(:title) { 'motd_header' } + let(:facts) {{ :concat_basedir => '/tmp' }} + let(:params) {{ :target => false }} + + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /is not a string/) + end + end + end # target => + + context 'ensure =>' do + ['present', 'absent'].each do |ens| + context ens do + it_behaves_like 'fragment', 'motd_header', { + :ensure => ens, + :target => '/etc/motd', + } + end + end + + context 'any value other than \'present\' or \'absent\'' do + let(:title) { 'motd_header' } + let(:facts) {{ :concat_basedir => '/tmp' }} + let(:params) {{ :ensure => 'invalid', :target => '/etc/motd' }} + + it 'should create a warning' do + pending('rspec-puppet support for testing warning()') + end + end + end # ensure => + + context 'content =>' do + ['', 'ashp is our hero'].each do |content| + context content do + it_behaves_like 'fragment', 'motd_header', { + :content => content, + :target => '/etc/motd', + } + end + end + + context 'false' do + let(:title) { 'motd_header' } + let(:facts) {{ :concat_basedir => '/tmp' }} + let(:params) {{ :content => false, :target => '/etc/motd' }} + + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /is not a string/) + end + end + end # content => + + context 'source =>' do + ['', '/foo/bar', ['/foo/bar', '/foo/baz']].each do |source| + context source do + it_behaves_like 'fragment', 'motd_header', { + :source => source, + :target => '/etc/motd', + } + end + end + + context 'false' do + let(:title) { 'motd_header' } + let(:facts) {{ :concat_basedir => '/tmp' }} + let(:params) {{ :source => false, :target => '/etc/motd' }} + + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /is not a string or an Array/) + end + end + end # source => + + context 'order =>' do + ['', '42', 'a', 'z'].each do |order| + context '\'\'' do + it_behaves_like 'fragment', 'motd_header', { + :order => order, + :target => '/etc/motd', + } + end + end + + context 'false' do + let(:title) { 'motd_header' } + let(:facts) {{ :concat_basedir => '/tmp' }} + let(:params) {{ :order => false, :target => '/etc/motd' }} + + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /is not a string or integer/) + end + end + end # order => + + context 'more than one content source' do + error_msg = 'You cannot specify more than one of $content, $source, $ensure => /target' + + context 'ensure => target and source' do + let(:title) { 'motd_header' } + let(:facts) {{ :concat_basedir => '/tmp' }} + let(:params) do + { + :target => '/etc/motd', + :ensure => '/foo', + :source => '/bar', + } + end + + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /#{Regexp.escape(error_msg)}/m) + end + end + + context 'ensure => target and content' do + let(:title) { 'motd_header' } + let(:facts) {{ :concat_basedir => '/tmp' }} + let(:params) do + { + :target => '/etc/motd', + :ensure => '/foo', + :content => 'bar', + } + end + + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /#{Regexp.escape(error_msg)}/m) + end + end + + context 'source and content' do + let(:title) { 'motd_header' } + let(:facts) {{ :concat_basedir => '/tmp' }} + let(:params) do + { + :target => '/etc/motd', + :source => '/foo', + :content => 'bar', + } + end + + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /#{Regexp.escape(error_msg)}/m) + end + end + + end # more than one content source + + describe 'deprecated parameter' do + context 'mode =>' do + context '1755' do + it_behaves_like 'fragment', 'motd_header', { + :mode => '1755', + :target => '/etc/motd', + } + + it 'should create a warning' do + pending('rspec-puppet support for testing warning()') + end + end + end # mode => + + context 'owner =>' do + context 'apenny' do + it_behaves_like 'fragment', 'motd_header', { + :owner => 'apenny', + :target => '/etc/motd', + } + + it 'should create a warning' do + pending('rspec-puppet support for testing warning()') + end + end + end # owner => + + context 'group =>' do + context 'apenny' do + it_behaves_like 'fragment', 'motd_header', { + :group => 'apenny', + :target => '/etc/motd', + } + + it 'should create a warning' do + pending('rspec-puppet support for testing warning()') + end + end + end # group => + + context 'backup =>' do + context 'foo' do + it_behaves_like 'fragment', 'motd_header', { + :backup => 'foo', + :target => '/etc/motd', + } + + it 'should create a warning' do + pending('rspec-puppet support for testing warning()') + end + end + end # backup => + end # deprecated params + +end diff --git a/modules/dependencies/concat/spec/unit/defines/concat_spec.rb b/modules/dependencies/concat/spec/unit/defines/concat_spec.rb new file mode 100644 index 000000000..e7be4d570 --- /dev/null +++ b/modules/dependencies/concat/spec/unit/defines/concat_spec.rb @@ -0,0 +1,389 @@ +require 'spec_helper' + +describe 'concat', :type => :define do + + shared_examples 'concat' do |title, params, id| + params = {} if params.nil? + id = 'root' if id.nil? + + # default param values + p = { + :ensure => 'present', + :path => title, + :owner => nil, + :group => nil, + :mode => '0644', + :warn => false, + :force => false, + :backup => 'puppet', + :replace => true, + :order => 'alpha', + :ensure_newline => false, + }.merge(params) + + safe_name = title.gsub('/', '_') + concatdir = '/var/lib/puppet/concat' + fragdir = "#{concatdir}/#{safe_name}" + concat_name = 'fragments.concat.out' + default_warn_message = '# This file is managed by Puppet. DO NOT EDIT.' + + file_defaults = { + :backup => false, + } + + let(:title) { title } + let(:params) { params } + let(:facts) {{ :concat_basedir => concatdir, :id => id }} + + if p[:ensure] == 'present' + it do + should contain_file(fragdir).with(file_defaults.merge({ + :ensure => 'directory', + :mode => '0750', + })) + end + + it do + should contain_file("#{fragdir}/fragments").with(file_defaults.merge({ + :ensure => 'directory', + :mode => '0750', + :force => true, + :ignore => ['.svn', '.git', '.gitignore'], + :purge => true, + :recurse => true, + })) + end + + [ + "#{fragdir}/fragments.concat", + "#{fragdir}/#{concat_name}", + ].each do |file| + it do + should contain_file(file).with(file_defaults.merge({ + :ensure => 'present', + :mode => '0640', + })) + end + end + + it do + should contain_file(title).with(file_defaults.merge({ + :ensure => 'present', + :owner => p[:owner], + :group => p[:group], + :mode => p[:mode], + :replace => p[:replace], + :path => p[:path], + :alias => "concat_#{title}", + :source => "#{fragdir}/#{concat_name}", + :backup => p[:backup], + })) + end + + cmd = "#{concatdir}/bin/concatfragments.sh " + + "-o \"#{concatdir}/#{safe_name}/fragments.concat.out\" " + + "-d \"#{concatdir}/#{safe_name}\"" + + # flag order: fragdir, warnflag, forceflag, orderflag, newlineflag + if p.has_key?(:warn) + case p[:warn] + when TrueClass + message = default_warn_message + when 'true', 'yes', 'on' + # should generate a stringified boolean warning + message = default_warn_message + when FalseClass + message = nil + when 'false', 'no', 'off' + # should generate a stringified boolean warning + message = nil + else + message = p[:warn] + end + + unless message.nil? + cmd += " -w \'#{message}\'" + end + end + + cmd += " -f" if p[:force] + cmd += " -n" if p[:order] == 'numeric' + cmd += " -l" if p[:ensure_newline] == true + + it do + should contain_exec("concat_#{title}").with({ + :alias => "concat_#{fragdir}", + :command => cmd, + :unless => "#{cmd} -t", + }) + end + else + [ + fragdir, + "#{fragdir}/fragments", + "#{fragdir}/fragments.concat", + "#{fragdir}/#{concat_name}", + ].each do |file| + it do + should contain_file(file).with(file_defaults.merge({ + :ensure => 'absent', + :backup => false, + :force => true, + })) + end + end + + it do + should contain_file(title).with(file_defaults.merge({ + :ensure => 'absent', + :backup => p[:backup], + })) + end + + it do + should contain_exec("concat_#{title}").with({ + :alias => "concat_#{fragdir}", + :command => 'true', + :unless => 'true', + :path => '/bin:/usr/bin', + }) + end + end + end + + context 'title' do + context 'without path param' do + # title/name is the default value for the path param. therefore, the + # title must be an absolute path unless path is specified + ['/foo', '/foo/bar', '/foo/bar/baz'].each do |title| + context title do + it_behaves_like 'concat', '/etc/foo.bar' + end + end + + ['./foo', 'foo', 'foo/bar'].each do |title| + context title do + let(:title) { title } + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /is not an absolute path/) + end + end + end + end + + context 'with path param' do + ['./foo', 'foo', 'foo/bar'].each do |title| + context title do + it_behaves_like 'concat', title, { :path => '/etc/foo.bar' } + end + end + end + end # title => + + context 'as non-root user' do + it_behaves_like 'concat', '/etc/foo.bar', {}, 'bob' + end + + context 'ensure =>' do + ['present', 'absent'].each do |ens| + context ens do + it_behaves_like 'concat', '/etc/foo.bar', { :ensure => ens } + end + end + + context 'invalid' do + let(:title) { '/etc/foo.bar' } + let(:params) {{ :ensure => 'invalid' }} + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /#{Regexp.escape('does not match "^present$|^absent$"')}/) + end + end + end # ensure => + + context 'path =>' do + context '/foo' do + it_behaves_like 'concat', '/etc/foo.bar', { :path => '/foo' } + end + + ['./foo', 'foo', 'foo/bar', false].each do |path| + context path do + let(:title) { '/etc/foo.bar' } + let(:params) {{ :path => path }} + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /is not an absolute path/) + end + end + end + end # path => + + context 'owner =>' do + context 'apenney' do + it_behaves_like 'concat', '/etc/foo.bar', { :owner => 'apenny' } + end + + context 'false' do + let(:title) { '/etc/foo.bar' } + let(:params) {{ :owner => false }} + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /is not a string/) + end + end + end # owner => + + context 'group =>' do + context 'apenney' do + it_behaves_like 'concat', '/etc/foo.bar', { :group => 'apenny' } + end + + context 'false' do + let(:title) { '/etc/foo.bar' } + let(:params) {{ :group => false }} + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /is not a string/) + end + end + end # group => + + context 'mode =>' do + context '1755' do + it_behaves_like 'concat', '/etc/foo.bar', { :mode => '1755' } + end + + context 'false' do + let(:title) { '/etc/foo.bar' } + let(:params) {{ :mode => false }} + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /is not a string/) + end + end + end # mode => + + context 'warn =>' do + [true, false, '# foo'].each do |warn| + context warn do + it_behaves_like 'concat', '/etc/foo.bar', { :warn => warn } + end + end + + context '(stringified boolean)' do + ['true', 'yes', 'on', 'false', 'no', 'off'].each do |warn| + context warn do + it_behaves_like 'concat', '/etc/foo.bar', { :warn => warn } + + it 'should create a warning' do + pending('rspec-puppet support for testing warning()') + end + end + end + end + + context '123' do + let(:title) { '/etc/foo.bar' } + let(:params) {{ :warn => 123 }} + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /is not a string or boolean/) + end + end + end # warn => + + context 'force =>' do + [true, false].each do |force| + context force do + it_behaves_like 'concat', '/etc/foo.bar', { :force => force } + end + end + + context '123' do + let(:title) { '/etc/foo.bar' } + let(:params) {{ :force => 123 }} + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /is not a boolean/) + end + end + end # force => + + context 'backup =>' do + context 'reverse' do + it_behaves_like 'concat', '/etc/foo.bar', { :backup => 'reverse' } + end + + context 'false' do + it_behaves_like 'concat', '/etc/foo.bar', { :backup => false } + end + + context 'true' do + it_behaves_like 'concat', '/etc/foo.bar', { :backup => true } + end + + context 'true' do + let(:title) { '/etc/foo.bar' } + let(:params) {{ :backup => [] }} + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /backup must be string or bool/) + end + end + end # backup => + + context 'replace =>' do + [true, false].each do |replace| + context replace do + it_behaves_like 'concat', '/etc/foo.bar', { :replace => replace } + end + end + + context '123' do + let(:title) { '/etc/foo.bar' } + let(:params) {{ :replace => 123 }} + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /is not a boolean/) + end + end + end # replace => + + context 'order =>' do + ['alpha', 'numeric'].each do |order| + context order do + it_behaves_like 'concat', '/etc/foo.bar', { :order => order } + end + end + + context 'invalid' do + let(:title) { '/etc/foo.bar' } + let(:params) {{ :order => 'invalid' }} + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /#{Regexp.escape('does not match "^alpha$|^numeric$"')}/) + end + end + end # order => + + context 'ensure_newline =>' do + [true, false].each do |ensure_newline| + context 'true' do + it_behaves_like 'concat', '/etc/foo.bar', { :ensure_newline => ensure_newline} + end + end + + context '123' do + let(:title) { '/etc/foo.bar' } + let(:params) {{ :ensure_newline => 123 }} + it 'should fail' do + expect { should }.to raise_error(Puppet::Error, /is not a boolean/) + end + end + end # ensure_newline => + + describe 'deprecated parameter' do + context 'gnu =>' do + context 'foo' do + it_behaves_like 'concat', '/etc/foo.bar', { :gnu => 'foo'} + + it 'should create a warning' do + pending('rspec-puppet support for testing warning()') + end + end + end + end + +end + +# vim:sw=2:ts=2:expandtab:textwidth=79 diff --git a/modules/dependencies/concat/spec/unit/facts/concat_basedir_spec.rb b/modules/dependencies/concat/spec/unit/facts/concat_basedir_spec.rb new file mode 100644 index 000000000..41bc90f15 --- /dev/null +++ b/modules/dependencies/concat/spec/unit/facts/concat_basedir_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +describe 'concat_basedir', :type => :fact do + before(:each) { Facter.clear } + + context 'Puppet[:vardir] ==' do + it '/var/lib/puppet' do + Puppet.stubs(:[]).with(:vardir).returns('/var/lib/puppet') + Facter.fact(:concat_basedir).value.should == '/var/lib/puppet/concat' + end + + it '/home/apenny/.puppet/var' do + Puppet.stubs(:[]).with(:vardir).returns('/home/apenny/.puppet/var') + Facter.fact(:concat_basedir).value.should == '/home/apenny/.puppet/var/concat' + end + end + +end diff --git a/modules/dependencies/concat/tests/fragment.pp b/modules/dependencies/concat/tests/fragment.pp new file mode 100644 index 000000000..a2dfaca29 --- /dev/null +++ b/modules/dependencies/concat/tests/fragment.pp @@ -0,0 +1,19 @@ +concat { 'testconcat': + ensure => present, + path => '/tmp/concat', + owner => 'root', + group => 'root', + mode => '0664', +} + +concat::fragment { '1': + target => 'testconcat', + content => '1', + order => '01', +} + +concat::fragment { '2': + target => 'testconcat', + content => '2', + order => '02', +} diff --git a/modules/dependencies/concat/tests/init.pp b/modules/dependencies/concat/tests/init.pp new file mode 100644 index 000000000..fd2142718 --- /dev/null +++ b/modules/dependencies/concat/tests/init.pp @@ -0,0 +1,7 @@ +concat { '/tmp/concat': + ensure => present, + force => true, + owner => 'root', + group => 'root', + mode => '0644', +}