Added modules

This commit is contained in:
Ciaby 2014-07-11 13:30:23 -05:00
parent c53c931217
commit 59ec520742
646 changed files with 35182 additions and 0 deletions

248
modules/apt/CHANGELOG.md Normal file
View file

@ -0,0 +1,248 @@
##2014-06-04 - Release 1.5.0
###Summary
This release adds support for Ubuntu 14.04. It also includes many new features
and important bugfixes. One huge change is that apt::key was replaced with
apt_key, which allows you to use puppet resource apt_key to inventory keys on
your system.
Special thanks to daenney, our intrepid unofficial apt maintainer!
####Features
- Add support for Ubuntu Trusty!
- Add apt::hold define
- Generate valid *.pref files in apt::pin
- Made pin_priority configurable for apt::backports
- Add apt_key type and provider
- Rename "${apt_conf_d}/proxy" to "${apt_conf_d}/01proxy"
- apt::key rewritten to use apt_key type
- Add support for update_tries to apt::update
####Bugfixes
- Typo fixes
- Fix unattended upgrades
- Removed bogus line when using purge_preferences
- Fix apt::force to upgrade allow packages to be upgraded to the pacakge from the specified release
##2014-03-04 - Supported Release 1.4.2
###Summary
This is a supported release. This release tidies up 1.4.1 and re-enables
support for Ubuntu 10.04
####Features
####Bugfixes
- Fix apt:ppa to include the -y Ubuntu 10.04 requires.
- Documentation changes.
- Test fixups.
####Known Bugs
* No known issues.
##2014-02-13 1.4.1
###Summary
This is a bugfix release.
####Bugfixes
- Fix apt::force unable to upgrade packages from releases other than its original
- Removed a few refeneces to aptitude instead of apt-get for portability
- Removed call to getparam() due to stdlib dependency
- Correct apt::source template when architecture is provided
- Retry package installs if apt is locked
- Use root to exec in apt::ppa
- Updated tests and converted acceptance tests to beaker
##2013-10-08 - Release 1.4.0
###Summary
Minor bugfix and allow the timeout to be adjusted.
####Features
- Add an `updates_timeout` to apt::params
####Bugfixes
- Ensure apt::ppa can read a ppa removed by hand.
##2013-10-08 - Release 1.3.0
###Summary
This major feature in this release is the new apt::unattended_upgrades class,
allowing you to handle Ubuntu's unattended feature. This allows you to select
specific packages to automatically upgrade without any further user
involvement.
In addition we extend our Wheezy support, add proxy support to apt:ppa and do
various cleanups and tweaks.
####Features
- Add apt::unattended_upgrades support for Ubuntu.
- Add wheezy backports support.
- Use the geoDNS http.debian.net instead of the main debian ftp server.
- Add `options` parameter to apt::ppa in order to pass options to apt-add-repository command.
- Add proxy support for apt::ppa (uses proxy_host and proxy_port from apt).
####Bugfixes
- Fix regsubst() calls to quote single letters (for future parser).
- Fix lint warnings and other misc cleanup.
##2013-07-03 - Release 1.2.0
####Features
- Add geppetto `.project` natures
- Add GH auto-release
- Add `apt::key::key_options` parameter
- Add complex pin support using distribution properties for `apt::pin` via new properties:
- `apt::pin::codename`
- `apt::pin::release_version`
- `apt::pin::component`
- `apt::pin::originator`
- `apt::pin::label`
- Add source architecture support to `apt::source::architecture`
####Bugfixes
- Use apt-get instead of aptitude in apt::force
- Update default backports location
- Add dependency for required packages before apt-get update
##2013-06-02 - Release 1.1.1
###Summary
This is a bug fix release that resolves a number of issues:
* By changing template variable usage, we remove the deprecation warnings
for Puppet 3.2.x
* Fixed proxy file removal, when proxy absent
Some documentation, style and whitespaces changes were also merged. This
release also introduced proper rspec-puppet unit testing on Travis-CI to help
reduce regression.
Thanks to all the community contributors below that made this patch possible.
#### Detail Changes
* fix minor comment type (Chris Rutter)
* whitespace fixes (Michael Moll)
* Update travis config file (William Van Hevelingen)
* Build all branches on travis (William Van Hevelingen)
* Standardize travis.yml on pattern introduced in stdlib (William Van Hevelingen)
* Updated content to conform to README best practices template (Lauren Rother)
* Fix apt::release example in readme (Brian Galey)
* add @ to variables in template (Peter Hoeg)
* Remove deprecation warnings for pin.pref.erb as well (Ken Barber)
* Update travis.yml to latest versions of puppet (Ken Barber)
* Fix proxy file removal (Scott Barber)
* Add spec test for removing proxy configuration (Dean Reilly)
* Fix apt::key listing longer than 8 chars (Benjamin Knofe)
## Release 1.1.0
###Summary
This release includes Ubuntu 12.10 (Quantal) support for PPAs.
---
##2012-05-25 - Puppet Labs <info@puppetlabs.com> - Release 0.0.4
###Summary
* Fix ppa list filename when there is a period in the PPA name
* Add .pref extension to apt preferences files
* Allow preferences to be purged
* Extend pin support
##2012-05-04 - Puppet Labs <info@puppetlabs.com> - Release 0.0.3
###Summary
* only invoke apt-get update once
* only install python-software-properties if a ppa is added
* support 'ensure => absent' for all defined types
* add apt::conf
* add apt::backports
* fixed Modulefile for module tool dependency resolution
* configure proxy before doing apt-get update
* use apt-get update instead of aptitude for apt::ppa
* add support to pin release
##2012-03-26 - Puppet Labs <info@puppetlabs.com> - Release 0.0.2
###Summary
* 41cedbb (#13261) Add real examples to smoke tests.
* d159a78 (#13261) Add key.pp smoke test
* 7116c7a (#13261) Replace foo source with puppetlabs source
* 1ead0bf Ignore pkg directory.
* 9c13872 (#13289) Fix some more style violations
* 0ea4ffa (#13289) Change test scaffolding to use a module & manifest dir fixture path
* a758247 (#13289) Clean up style violations and fix corresponding tests
* 99c3fd3 (#13289) Add puppet lint tests to Rakefile
* 5148cbf (#13125) Apt keys should be case insensitive
* b9607a4 Convert apt::key to use anchors
##2012-03-07 - Puppet Labs <info@puppetlabs.com> - Release 0.0.1
###Summary
* d4fec56 Modify apt::source release parameter test
* 1132a07 (#12917) Add contributors to README
* 8cdaf85 (#12823) Add apt::key defined type and modify apt::source to use it
* 7c0d10b (#12809) $release should use $lsbdistcodename and fall back to manual input
* be2cc3e (#12522) Adjust spec test for splitting purge
* 7dc60ae (#12522) Split purge option to spare sources.list
* 9059c4e Fix source specs to test all key permutations
* 8acb202 Add test for python-software-properties package
* a4af11f Check if python-software-properties is defined before attempting to define it.
* 1dcbf3d Add tests for required_packages change
* f3735d2 Allow duplicate $required_packages
* 74c8371 (#12430) Add tests for changes to apt module
* 97ebb2d Test two sources with the same key
* 1160bcd (#12526) Add ability to reverse apt { disable_keys => true }
* 2842d73 Add Modulefile to puppet-apt
* c657742 Allow the use of the same key in multiple sources
* 8c27963 (#12522) Adding purge option to apt class
* 997c9fd (#12529) Add unit test for apt proxy settings
* 50f3cca (#12529) Add parameter to support setting a proxy for apt
* d522877 (#12094) Replace chained .with_* with a hash
* 8cf1bd0 (#12094) Remove deprecated spec.opts file
* 2d688f4 (#12094) Add rspec-puppet tests for apt
* 0fb5f78 (#12094) Replace name with path in file resources
* f759bc0 (#11953) Apt::force passes $version to aptitude
* f71db53 (#11413) Add spec test for apt::force to verify changes to unless
* 2f5d317 (#11413) Update dpkg query used by apt::force
* cf6caa1 (#10451) Add test coverage to apt::ppa
* 0dd697d include_src parameter in example; Whitespace cleanup
* b662eb8 fix typos in "repositories"
* 1be7457 Fix (#10451) - apt::ppa fails to "apt-get update" when new PPA source is added
* 864302a Set the pin priority before adding the source (Fix #10449)
* 1de4e0a Refactored as per mlitteken
* 1af9a13 Added some crazy bash madness to check if the ppa is installed already. Otherwise the manifest tries to add it on every run!
* 52ca73e (#8720) Replace Apt::Ppa with Apt::Builddep
* 5c05fa0 added builddep command.
* a11af50 added the ability to specify the content of a key
* c42db0f Fixes ppa test.
* 77d2b0d reformatted whitespace to match recommended style of 2 space indentation.
* 27ebdfc ignore swap files.
* 377d58a added smoke tests for module.
* 18f614b reformatted apt::ppa according to recommended style.
* d8a1e4e Created a params class to hold global data.
* 636ae85 Added two params for apt class
* 148fc73 Update LICENSE.
* ed2d19e Support ability to add more than one PPA
* 420d537 Add call to apt-update after add-apt-repository in apt::ppa
* 945be77 Add package definition for python-software-properties
* 71fc425 Abs paths for all commands
* 9d51cd1 Adding LICENSE
* 71796e3 Heading fix in README
* 87777d8 Typo in README
* f848bac First commit

18
modules/apt/Gemfile Normal file
View file

@ -0,0 +1,18 @@
source ENV['GEM_SOURCE'] || 'https://rubygems.org'
group :development, :test do
gem 'rake', '10.1.1', :require => false
gem 'pry', :require => false
gem 'rspec-puppet', :require => false
gem 'puppet-lint', :require => false
gem 'puppetlabs_spec_helper', :require => false
gem 'serverspec', :require => false
gem 'beaker', :require => false
gem 'beaker-rspec', :require => false
end
if puppetversion = ENV['PUPPET_GEM_VERSION']
gem 'puppet', puppetversion, :require => false
else
gem 'puppet', :require => false
end

152
modules/apt/Gemfile.lock Normal file
View file

@ -0,0 +1,152 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (2.2.7)
addressable (2.3.6)
autoparse (0.3.3)
addressable (>= 2.3.1)
extlib (>= 0.9.15)
multi_json (>= 1.0.0)
aws-sdk (1.39.0)
json (~> 1.4)
nokogiri (>= 1.4.4)
beaker (1.10.0)
aws-sdk (~> 1.38)
blimpy (~> 0.6)
fission (~> 0.4)
google-api-client (~> 0.6.4)
inifile (~> 2.0)
json (~> 1.8)
mime-types (~> 1.25)
net-scp (~> 1.1)
net-ssh (~> 2.6)
nokogiri (= 1.5.10)
rbvmomi (= 1.8.1)
unf (~> 0.1)
beaker-rspec (2.2.3)
beaker (~> 1.10.0)
rspec (~> 2.14)
serverspec (~> 1.0.0)
specinfra (~> 1.0.0)
blimpy (0.6.7)
fog
minitar
thor
builder (3.2.2)
coderay (1.1.0)
diff-lcs (1.2.5)
excon (0.31.0)
extlib (0.9.16)
facter (2.0.1)
CFPropertyList (~> 2.2.6)
faraday (0.8.9)
multipart-post (~> 1.2.0)
fission (0.5.0)
CFPropertyList (~> 2.2)
fog (1.19.0)
builder
excon (~> 0.31.0)
formatador (~> 0.2.0)
mime-types
multi_json (~> 1.0)
net-scp (~> 1.1)
net-ssh (>= 2.1.3)
nokogiri (~> 1.5)
ruby-hmac
formatador (0.2.4)
google-api-client (0.6.4)
addressable (>= 2.3.2)
autoparse (>= 0.3.3)
extlib (>= 0.9.15)
faraday (~> 0.8.4)
jwt (>= 0.1.5)
launchy (>= 2.1.1)
multi_json (>= 1.0.0)
signet (~> 0.4.5)
uuidtools (>= 2.1.0)
hiera (1.3.2)
json_pure
highline (1.6.21)
inifile (2.0.2)
json (1.8.1)
json_pure (1.8.1)
jwt (0.1.11)
multi_json (>= 1.5)
launchy (2.4.2)
addressable (~> 2.3)
metaclass (0.0.4)
method_source (0.8.2)
mime-types (1.25.1)
minitar (0.5.4)
mocha (1.0.0)
metaclass (~> 0.0.1)
multi_json (1.9.3)
multipart-post (1.2.0)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
net-ssh (2.9.0)
nokogiri (1.5.10)
pry (0.9.12.6)
coderay (~> 1.0)
method_source (~> 0.8)
slop (~> 3.4)
puppet (3.5.1)
facter (> 1.6, < 3)
hiera (~> 1.0)
json_pure
rgen (~> 0.6.5)
puppet-lint (0.3.2)
puppetlabs_spec_helper (0.4.1)
mocha (>= 0.10.5)
rake
rspec (>= 2.9.0)
rspec-puppet (>= 0.1.1)
rake (10.1.1)
rbvmomi (1.8.1)
builder
nokogiri (>= 1.4.1)
trollop
rgen (0.6.6)
rspec (2.14.1)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
rspec-core (2.14.8)
rspec-expectations (2.14.5)
diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.14.6)
rspec-puppet (1.0.1)
rspec
ruby-hmac (0.4.0)
serverspec (1.0.0)
highline
net-ssh
rspec (~> 2.13)
specinfra (>= 1.0.0)
signet (0.4.5)
addressable (>= 2.2.3)
faraday (~> 0.8.1)
jwt (>= 0.1.5)
multi_json (>= 1.0.0)
slop (3.5.0)
specinfra (1.0.5)
thor (0.19.1)
trollop (2.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.6)
uuidtools (2.1.4)
PLATFORMS
ruby
DEPENDENCIES
beaker
beaker-rspec
pry
puppet
puppet-lint
puppetlabs_spec_helper
rake (= 10.1.1)
rspec-puppet
serverspec

34
modules/apt/LICENSE Normal file
View file

@ -0,0 +1,34 @@
Copyright (c) 2011 Evolving Web Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Copyright 2014 Puppet Labs
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.

14
modules/apt/Modulefile Normal file
View file

@ -0,0 +1,14 @@
name 'puppetlabs-apt'
version '1.5.0'
source 'https://github.com/puppetlabs/puppetlabs-apt'
author 'Evolving Web / Puppet Labs'
license 'Apache License 2.0'
summary 'Puppet Labs Apt Module'
description 'APT Module for Puppet'
project_page 'https://github.com/puppetlabs/puppetlabs-apt'
## Add dependencies, if any:
#dependency 'puppetlabs/stdlib', '2.x'
# The dependency should be written as above but librarian-puppet
# does not support the expression as the PMT does.
dependency 'puppetlabs/stdlib', '>= 2.2.1'

323
modules/apt/README.md Normal file
View file

@ -0,0 +1,323 @@
apt
===
[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-apt.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-apt)
Overview
--------
The APT module provides a simple interface for managing APT source, key, and definitions with Puppet.
Module Description
------------------
APT automates obtaining and installing software packages on \*nix systems.
***Note:** While this module allows the use of short keys, we STRONGLY RECOMMEND that you DO NOT USE short keys, as they pose a serious security issue in that they open you up to collision attacks.*
Setup
-----
**What APT affects:**
* package/service/configuration files for APT
* NOTE: Setting the `purge_preferences` or `purge_preferences_d` parameters to 'true' will destroy any existing configuration that was not declared with puppet. The default for these parameters is 'false'.
* your system's `sources.list` file and `sources.list.d` directory
* NOTE: Setting the `purge_sources_list` and `purge_sources_list_d` parameters to 'true' will destroy any existing content that was not declared with Puppet. The default for these parameters is 'false'.
* system repositories
* authentication keys
### Beginning with APT
To begin using the APT module with default parameters, declare the class
include apt
Puppet code that uses anything from the APT module requires that the core apt class be declared/\s\+$//e
Usage
-----
Using the APT module consists predominantly in declaring classes that provide desired functionality and features.
### apt
`apt` provides a number of common resources and options that are shared by the various defined types in this module, so you MUST always include this class in your manifests.
The parameters for `apt` are not required in general and are predominantly for development environment use-cases.
class { 'apt':
always_apt_update => false,
disable_keys => undef,
proxy_host => false,
proxy_port => '8080',
purge_sources_list => false,
purge_sources_list_d => false,
purge_preferences_d => false,
update_timeout => undef
}
Puppet will manage your system's `sources.list` file and `sources.list.d` directory but will do its best to respect existing content.
If you declare your apt class with `purge_sources_list`, `purge_sources_list_d`, `purge_preferences` and `purge_preferences_d` set to 'true', Puppet will unapologetically purge any existing content it finds that wasn't declared with Puppet.
### apt::builddep
Installs the build depends of a specified package.
apt::builddep { 'glusterfs-server': }
### apt::force
Forces a package to be installed from a specific release. This class is particularly useful when using repositories, like Debian, that are unstable in Ubuntu.
apt::force { 'glusterfs-server':
release => 'unstable',
version => '3.0.3',
require => Apt::Source['debian_unstable'],
}
### apt_key
A native Puppet type and provider for managing GPG keys for APT is provided by
this module.
apt_key { 'puppetlabs':
ensure => 'present',
id => '4BD6EC30',
}
You can additionally set the following attributes:
* `source`: HTTP, HTTPS or FTP location of a GPG key or path to a file on the
target host;
* `content`: Instead of pointing to a file, pass the key in as a string;
* `server`: The GPG key server to use. It defaults to *keyserver.ubuntu.com*;
* `keyserver_options`: Additional options to pass to `--keyserver`.
Because it is a native type it can be used in and queried for with MCollective.
### apt::key
Adds a key to the list of keys used by APT to authenticate packages. This type
uses the aforementioned `apt_key` native type. As such it no longer requires
the wget command that the old implementation depended on.
apt::key { 'puppetlabs':
key => '4BD6EC30',
key_server => 'pgp.mit.edu',
}
apt::key { 'jenkins':
key => 'D50582E6',
key_source => 'http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key',
}
### apt::pin
Adds an apt pin for a certain release.
apt::pin { 'karmic': priority => 700 }
apt::pin { 'karmic-updates': priority => 700 }
apt::pin { 'karmic-security': priority => 700 }
Note you can also specifying more complex pins using distribution properties.
apt::pin { 'stable':
priority => -10,
originator => 'Debian',
release_version => '3.0',
component => 'main',
label => 'Debian'
}
If you wish to pin a number of packages you may specify the packages as a space
delimited string using the `packages` attribute or pass in an array of package
names.
### apt::hold
When you wish to hold a package in Puppet is should be done by passing in
'held' as the ensure attribute to the package resource. However, a lot of
public modules do not take this into account and generally do not work well
with an ensure of 'held'.
There is an additional issue that when Puppet is told to hold a package, it
will hold it at the current version installed, there is no way to tell it in
one go to install a specific version and then hold that version without using
an exec resource that wraps `dpkg --set-selections` or `apt-mark`.
At first glance this could also be solved by just passing the version required
to the ensure attribute but that only means that Puppet will install that
version once it processes that package. It does not inform apt that we want
this package to be held. In other words; if another package somehow wants to
upgrade this one (because of a version requirement in a dependency), apt
should not allow it.
In order to solve this you can use apt::hold. It's implemented by creating
a preferences file with a priority of 1001, meaning that under normal
circumstances this preference will always win. Because the priority is > 1000
apt will interpret this as 'this should be the version installed and I am
allowed to downgrade the current package if needed'.
With this you can now set a package's ensure attribute to 'latest' but still
get the version specified by apt::hold. You can do it like this:
apt::hold { 'vim':
version => '2:7.3.547-7',
}
Since you might just want to hold Vim at version 7.3 and not care about the
rest you can also pass in a version with a glob:
apt::hold { 'vim':
version => '2:7.3.*',
}
### apt::ppa
Adds a ppa repository using `add-apt-repository`.
apt::ppa { 'ppa:drizzle-developers/ppa': }
### apt::release
Sets the default apt release. This class is particularly useful when using repositories, like Debian, that are unstable in Ubuntu.
class { 'apt::release':
release_id => 'precise',
}
### apt::source
Adds an apt source to `/etc/apt/sources.list.d/`.
apt::source { 'debian_unstable':
location => 'http://debian.mirror.iweb.ca/debian/',
release => 'unstable',
repos => 'main contrib non-free',
required_packages => 'debian-keyring debian-archive-keyring',
key => '46925553',
key_server => 'subkeys.pgp.net',
pin => '-10',
include_src => true
}
If you would like to configure your system so the source is the Puppet Labs APT repository
apt::source { 'puppetlabs':
location => 'http://apt.puppetlabs.com',
repos => 'main',
key => '4BD6EC30',
key_server => 'pgp.mit.edu',
}
#### Hiera example
<pre>
apt::sources:
'debian_unstable':
location: 'http://debian.mirror.iweb.ca/debian/'
release: 'unstable'
repos: 'main contrib non-free'
required_packages: 'debian-keyring debian-archive-keyring'
key: '55BE302B'
key_server: 'subkeys.pgp.net'
pin: '-10'
include_src: 'true'
'puppetlabs':
location: 'http://apt.puppetlabs.com'
repos: 'main'
key: '4BD6EC30'
key_server: 'pgp.mit.edu'
</pre>
### Testing
The APT module is mostly a collection of defined resource types, which provide reusable logic that can be leveraged to manage APT. It does provide smoke tests for testing functionality on a target system, as well as spec tests for checking a compiled catalog against an expected set of resources.
#### Example Test
This test will set up a Puppet Labs apt repository. Start by creating a new smoke test in the apt module's test folder. Call it puppetlabs-apt.pp. Inside, declare a single resource representing the Puppet Labs APT source and gpg key
apt::source { 'puppetlabs':
location => 'http://apt.puppetlabs.com',
repos => 'main',
key => '4BD6EC30',
key_server => 'pgp.mit.edu',
}
This resource creates an apt source named puppetlabs and gives Puppet information about the repository's location and key used to sign its packages. Puppet leverages Facter to determine the appropriate release, but you can set it directly by adding the release type.
Check your smoke test for syntax errors
$ puppet parser validate tests/puppetlabs-apt.pp
If you receive no output from that command, it means nothing is wrong. Then apply the code
$ puppet apply --verbose tests/puppetlabs-apt.pp
notice: /Stage[main]//Apt::Source[puppetlabs]/File[puppetlabs.list]/ensure: defined content as '{md5}3be1da4923fb910f1102a233b77e982e'
info: /Stage[main]//Apt::Source[puppetlabs]/File[puppetlabs.list]: Scheduling refresh of Exec[puppetlabs apt update]
notice: /Stage[main]//Apt::Source[puppetlabs]/Exec[puppetlabs apt update]: Triggered 'refresh' from 1 events>
The above example used a smoke test to easily lay out a resource declaration and apply it on your system. In production, you may want to declare your APT sources inside the classes where theyre needed.
Implementation
--------------
### apt::backports
Adds the necessary components to get backports for Ubuntu and Debian. The release name defaults to `$lsbdistcodename`. Setting this manually can cause undefined behavior (read: universe exploding).
By default this class drops a Pin-file for Backports pinning it to a priority of 200, lower than the normal Debian archive which gets a priority of 500 to ensure your packages with `ensure => latest` don't get magically upgraded from Backports without your explicit say-so.
If you raise the priority through the `pin_priority` parameter to *500*, identical to the rest of the Debian mirrors, normal policy goes into effect and the newest version wins/becomes the candidate apt will want to install or upgrade to. This means that if a package is available from Backports it and its dependencies will be pulled in from Backports unless you explicitly set the `ensure` attribute of the `package` resource to `installed`/`present` or a specific version.
Limitations
-----------
This module should work across all versions of Debian/Ubuntu and support all major APT repository management features.
Development
------------
Puppet Labs modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We cant 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)
License
-------
The original code for this module comes from Evolving Web and was licensed under the MIT license. Code added since the fork of this module is licensed under the Apache 2.0 License like the rest of the Puppet Labs products.
The LICENSE contains both licenses.
Contributors
------------
A lot of great people have contributed to this module. A somewhat current list follows:
* Ben Godfrey <ben.godfrey@wonga.com>
* Branan Purvine-Riley <branan@puppetlabs.com>
* Christian G. Warden <cwarden@xerus.org>
* Dan Bode <bodepd@gmail.com> <dan@puppetlabs.com>
* Daniel Tremblay <github@danieltremblay.ca>
* Garrett Honeycutt <github@garretthoneycutt.com>
* Jeff Wallace <jeff@evolvingweb.ca> <jeff@tjwallace.ca>
* Ken Barber <ken@bob.sh>
* Matthaus Litteken <matthaus@puppetlabs.com> <mlitteken@gmail.com>
* Matthias Pigulla <mp@webfactory.de>
* Monty Taylor <mordred@inaugust.com>
* Peter Drake <pdrake@allplayers.com>
* Reid Vandewiele <marut@cat.pdx.edu>
* Robert Navarro <rnavarro@phiivo.com>
* Ryan Coleman <ryan@puppetlabs.com>
* Scott McLeod <scott.mcleod@theice.com>
* Spencer Krum <spencer@puppetlabs.com>
* William Van Hevelingen <blkperl@cat.pdx.edu> <wvan13@gmail.com>
* Zach Leslie <zach@puppetlabs.com>
* Daniele Sluijters <github@daenney.net>
* Daniel Paulus <daniel@inuits.eu>

10
modules/apt/Rakefile Normal file
View file

@ -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"]

View file

@ -0,0 +1,84 @@
{
"CHANGELOG.md": "2edd771d2aa653812ac9f58ddb8a8dd6",
"Gemfile": "0d209c30c4451b1cdce50967b396a8cb",
"Gemfile.lock": "3cc280f2c4a11d8e1a3c010a5e503b24",
"LICENSE": "c236a08bf88c5c8e480957038c869ed1",
"Modulefile": "e2ddc834592f3bd9dc229c3b7edda549",
"README.md": "0047d76fa8c10a673d556f5c099a1113",
"Rakefile": "de8eeacfe1fbbc6a6f4d89adfc98bcaf",
"lib/puppet/provider/apt_key/apt_key.rb": "7c1517b4ec04c5574f078b1651ed3c5c",
"lib/puppet/type/apt_key.rb": "e638201e7e299a5061c39e1045396887",
"lib/puppet_x/apt_key/patch_openuri.rb": "951bad007a3b5db035be069c1d1c9c09",
"manifests/backports.pp": "75523c9a3573830d5c364dba918a0511",
"manifests/builddep.pp": "4f313b5140c84aa7d5793b5a073c30dd",
"manifests/conf.pp": "5ddf258195d414d93284dfd281a8d6e3",
"manifests/debian/testing.pp": "1d7b2a7dfafa08eb47982cbf03cac5b9",
"manifests/debian/unstable.pp": "cf5a4e7ecadb34856bb6fed17e58c822",
"manifests/force.pp": "2e75773abb485ee64c6ebb8b284cce6d",
"manifests/hold.pp": "817999daec857e6305b22b4894da81aa",
"manifests/init.pp": "7a676234a6d693f88a91fac986490b6b",
"manifests/key.pp": "e1427a4d902b64a296dd16fbaa2063ef",
"manifests/params.pp": "4ed486272bafc452e506b98abe0f1149",
"manifests/pin.pp": "4bb5f0e75987fb69d1e617130412a6a3",
"manifests/ppa.pp": "1252cdd4d5fad97e0d94e9556f038db1",
"manifests/release.pp": "427f3ee70a6a1e55fa291e58655bd5d9",
"manifests/source.pp": "9f36b03fde5b1148d01c89677eee6b0e",
"manifests/unattended_upgrades.pp": "aaf5e4c350800d2d77faac0430c4c598",
"manifests/update.pp": "2950af6e8e4a4b30ecdf2921d7f01fee",
"metadata.json": "9e77b5b32cd0c0379601b3c6f15c4f7c",
"spec/acceptance/apt_builddep_spec.rb": "fb7ede528790507df42032d77eb74211",
"spec/acceptance/apt_key_provider_spec.rb": "bfc96c53af3e7ea1e1f3694466a40e86",
"spec/acceptance/apt_key_spec.rb": "5a5a6586db3010a0876dfa4ee29e3155",
"spec/acceptance/apt_ppa_spec.rb": "65efac5d8fa1baaed823ecd9548565c3",
"spec/acceptance/apt_source_spec.rb": "dc47437fa48d7cc82900ceba4d6d1f26",
"spec/acceptance/apt_spec.rb": "242e16421f4aaeddb57666fa6c685eaf",
"spec/acceptance/backports_spec.rb": "e2e4ba8091f1e3e168b6be376d22b961",
"spec/acceptance/class_spec.rb": "7efb1890650fea7a303ed74f3fa6fff1",
"spec/acceptance/conf_spec.rb": "ce961c5ace4de40df1b131a7e600e704",
"spec/acceptance/force_spec.rb": "e504f250caf7614099d9c1bb71125d63",
"spec/acceptance/nodesets/debian-70rc1-x64.yml": "715f798e696d3582c66d13f0e8e5f009",
"spec/acceptance/nodesets/debian-73-x64.yml": "b44b7146a828c37482c06879862fb5d9",
"spec/acceptance/nodesets/default.yml": "e27bb4d7526ad3c7a1c4aeb87decec15",
"spec/acceptance/nodesets/ubuntu-server-10044-x64.yml": "edd30a624fabfcae11b876ec3167383d",
"spec/acceptance/nodesets/ubuntu-server-12042-x64.yml": "344002a1813eb994a0d854981692ea5b",
"spec/acceptance/nodesets/ubuntu-server-1404-x64.yml": "5f0aed10098ac5b78e4217bb27c7aaf0",
"spec/acceptance/pin_spec.rb": "b91328114476900d1707f60953e86807",
"spec/acceptance/release_spec.rb": "171c6a92d12c47fffc255cbd41e53f88",
"spec/acceptance/unattended_upgrade_spec.rb": "2f24ec935bc070964f8eb231d2e7885d",
"spec/acceptance/unsupported_spec.rb": "a791d7f6fdeb4cc6dc8e32cfad88f4c1",
"spec/classes/apt_spec.rb": "93443e5cbe858e0a77cb94fe54bf7e78",
"spec/classes/backports_spec.rb": "fe8d8f03cacaed1134cd8b612f7ee139",
"spec/classes/debian_testing_spec.rb": "939bc900d8d9bc82e6c378b21b56035a",
"spec/classes/debian_unstable_spec.rb": "ac7e6a5bd599fd54ddc91a20c9777a90",
"spec/classes/init_spec.rb": "c08cdc9c025b1b343911d87ce4838bd2",
"spec/classes/params_spec.rb": "d5e4ef728174328113c75fbf6de85692",
"spec/classes/release_spec.rb": "bc3cce54aca2fef36a60fdfa0ae24488",
"spec/classes/unattended_upgrades_spec.rb": "686780f08979420bfe34495227fe284b",
"spec/defines/builddep_spec.rb": "99370325f64faa5034b79d113b2ef962",
"spec/defines/conf_spec.rb": "9c8fce10a10bb4b607d926ebfd6a6dcc",
"spec/defines/force_spec.rb": "12dce7d0903d1af82bba97a5d0bfa0b5",
"spec/defines/hold_spec.rb": "dd0863c74fff804900c8b390e820bdab",
"spec/defines/key_spec.rb": "6ba8391d8fac22fb6d265cea56c7d823",
"spec/defines/pin_spec.rb": "74e280e91fdfa7099d8e834dcc1ef14f",
"spec/defines/ppa_spec.rb": "aaa2c1e762fe14d2b78d63133e04501c",
"spec/defines/source_spec.rb": "054028467c44ec1002e3a4de9cf563d6",
"spec/spec_helper.rb": "0db89c9a486df193c0e40095422e19dc",
"spec/spec_helper_acceptance.rb": "fc4a89c45d1812b03459bd70139ce2c7",
"spec/unit/puppet/type/apt_key_spec.rb": "61ac4b1a237a7666acd517598bbc8667",
"templates/10periodic.erb": "2aeea866a39f19a62254abbb4f1bc59d",
"templates/50unattended-upgrades.erb": "78ff1ebf80099450fc989de20ea7153f",
"templates/pin.pref.erb": "50ad71970336e20e2f0fb017034af453",
"templates/source.list.erb": "7df942e41d3cefff84ef9410e6fdd626",
"tests/builddep.pp": "4773f57072111e58f2ed833fa4489a88",
"tests/debian/testing.pp": "1cbee56baddd6a91d981db8fddec70fb",
"tests/debian/unstable.pp": "4b2a090afeb315752262386f4dbcd8ca",
"tests/force.pp": "896f0e2da2c3eebda56fbf5461b90991",
"tests/init.pp": "551138eb704e71ab3687932dda429a81",
"tests/key.pp": "371a695e1332d51a38e283a87be52798",
"tests/params.pp": "900db40f3fc84b0be173278df2ebff35",
"tests/pin.pp": "4b4c3612d75a19dba8eb7227070fa4ab",
"tests/ppa.pp": "b902cce8159128b5e8b21bed540743ff",
"tests/release.pp": "53ce5debe6fa5bee42821767599cc768",
"tests/source.pp": "123b6208bc80c80f887cac6d563c04f1",
"tests/unattended_upgrades.pp": "ae03b24ced8748887178d2357b4bdb53"
}

View file

@ -0,0 +1,179 @@
require 'date'
require 'open-uri'
require 'net/ftp'
require 'tempfile'
if RUBY_VERSION == '1.8.7'
# Mothers cry, puppies die and Ruby 1.8.7's open-uri needs to be
# monkeypatched to support passing in :ftp_passive_mode.
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..',
'puppet_x', 'apt_key', 'patch_openuri.rb'))
OpenURI::Options.merge!({:ftp_active_mode => false,})
end
Puppet::Type.type(:apt_key).provide(:apt_key) do
KEY_LINE = {
:date => '[0-9]{4}-[0-9]{2}-[0-9]{2}',
:key_type => '(R|D)',
:key_size => '\d{4}',
:key_id => '[0-9a-fA-F]+',
:expires => 'expire(d|s)',
}
confine :osfamily => :debian
defaultfor :osfamily => :debian
commands :apt_key => 'apt-key'
def self.instances
key_array = apt_key('list').split("\n").collect do |line|
line_hash = key_line_hash(line)
next unless line_hash
expired = false
if line_hash[:key_expiry]
expired = Date.today > Date.parse(line_hash[:key_expiry])
end
new(
:name => line_hash[:key_id],
:id => line_hash[:key_id],
:ensure => :present,
:expired => expired,
:expiry => line_hash[:key_expiry],
:size => line_hash[:key_size],
:type => line_hash[:key_type] == 'R' ? :rsa : :dsa,
:created => line_hash[:key_created]
)
end
key_array.compact!
end
def self.prefetch(resources)
apt_keys = instances
resources.keys.each do |name|
if provider = apt_keys.find{ |key| key.name == name }
resources[name].provider = provider
end
end
end
def self.key_line_hash(line)
line_array = line.match(key_line_regexp).to_a
return nil if line_array.length < 5
return_hash = {
:key_id => line_array[3],
:key_size => line_array[1],
:key_type => line_array[2],
:key_created => line_array[4],
:key_expiry => nil,
}
return_hash[:key_expiry] = line_array[7] if line_array.length == 8
return return_hash
end
def self.key_line_regexp
# This regexp is trying to match the following output
# pub 4096R/4BD6EC30 2010-07-10 [expires: 2016-07-08]
# pub 1024D/CD2EFD2A 2009-12-15
regexp = /\A
pub # match only the public key, not signatures
\s+ # bunch of spaces after that
(#{KEY_LINE[:key_size]}) # size of the key, usually a multiple of 1024
#{KEY_LINE[:key_type]} # type of the key, usually R or D
\/ # separator between key_type and key_id
(#{KEY_LINE[:key_id]}) # hex id of the key
\s+ # bunch of spaces after that
(#{KEY_LINE[:date]}) # date the key was added to the keyring
# following an optional block which indicates if the key has an expiration
# date and if it has expired yet
(
\s+ # again with thes paces
\[ # we open with a square bracket
#{KEY_LINE[:expires]} # expires or expired
\: # a colon
\s+ # more spaces
(#{KEY_LINE[:date]}) # date indicating key expiry
\] # we close with a square bracket
)? # end of the optional block
\Z/x
regexp
end
def source_to_file(value)
if URI::parse(value).scheme.nil?
fail("The file #{value} does not exist") unless File.exists?(value)
value
else
begin
key = open(value, :ftp_active_mode => false).read
rescue OpenURI::HTTPError, Net::FTPPermError => e
fail("#{e.message} for #{resource[:source]}")
rescue SocketError
fail("could not resolve #{resource[:source]}")
else
tempfile(key)
end
end
end
def tempfile(content)
file = Tempfile.new('apt_key')
file.write content
file.close
file.path
end
def exists?
@property_hash[:ensure] == :present
end
def create
command = []
if resource[:source].nil? and resource[:content].nil?
# Breaking up the command like this is needed because it blows up
# if --recv-keys isn't the last argument.
command.push('adv', '--keyserver', resource[:server])
unless resource[:keyserver_options].nil?
command.push('--keyserver-options', resource[:keyserver_options])
end
command.push('--recv-keys', resource[:id])
elsif resource[:content]
command.push('add', tempfile(resource[:content]))
elsif resource[:source]
command.push('add', source_to_file(resource[:source]))
# In case we really screwed up, better safe than sorry.
else
fail("an unexpected condition occurred while trying to add the key: #{resource[:id]}")
end
apt_key(command)
@property_hash[:ensure] = :present
end
def destroy
apt_key('del', resource[:id])
@property_hash.clear
end
def read_only(value)
fail('This is a read-only property.')
end
mk_resource_methods
# Needed until PUP-1470 is fixed and we can drop support for Puppet versions
# before that.
def expired
@property_hash[:expired]
end
# Alias the setters of read-only properties
# to the read_only function.
alias :created= :read_only
alias :expired= :read_only
alias :expiry= :read_only
alias :size= :read_only
alias :type= :read_only
end

View file

@ -0,0 +1,112 @@
require 'pathname'
Puppet::Type.newtype(:apt_key) do
@doc = <<-EOS
This type provides Puppet with the capabilities to manage GPG keys needed
by apt to perform package validation. Apt has it's own GPG keyring that can
be manipulated through the `apt-key` command.
apt_key { '4BD6EC30':
source => 'http://apt.puppetlabs.com/pubkey.gpg'
}
**Autorequires**:
If Puppet is given the location of a key file which looks like an absolute
path this type will autorequire that file.
EOS
ensurable
validate do
if self[:content] and self[:source]
fail('The properties content and source are mutually exclusive.')
end
end
newparam(:id, :namevar => true) do
desc 'The ID of the key you want to manage.'
# GPG key ID's should be either 32-bit (short) or 64-bit (long) key ID's
# and may start with the optional 0x
newvalues(/\A(0x)?[0-9a-fA-F]{8}\Z/, /\A(0x)?[0-9a-fA-F]{16}\Z/)
munge do |value|
if value.start_with?('0x')
id = value.partition('0x').last.upcase
else
id = value.upcase
end
if id.length == 16
id[8..-1]
else
id
end
end
end
newparam(:content) do
desc 'The content of, or string representing, a GPG key.'
end
newparam(:source) do
desc 'Location of a GPG key file, /path/to/file, ftp://, http:// or https://'
newvalues(/\Ahttps?:\/\//, /\Aftp:\/\//, /\A\/\w+/)
end
autorequire(:file) do
if self[:source] and Pathname.new(self[:source]).absolute?
self[:source]
end
end
newparam(:server) do
desc 'The key server to fetch the key from based on the ID.'
defaultto :'keyserver.ubuntu.com'
# Need to validate this, preferably through stdlib is_fqdn
# but still working on getting to that.
end
newparam(:keyserver_options) do
desc 'Additional options to pass to apt-key\'s --keyserver-options.'
end
newproperty(:expired) do
desc <<-EOS
Indicates if the key has expired.
This property is read-only.
EOS
end
newproperty(:expiry) do
desc <<-EOS
The date the key will expire, or nil if it has no expiry date.
This property is read-only.
EOS
end
newproperty(:size) do
desc <<-EOS
The key size, usually a multiple of 1024.
This property is read-only.
EOS
end
newproperty(:type) do
desc <<-EOS
The key type, either RSA or DSA.
This property is read-only.
EOS
end
newproperty(:created) do
desc <<-EOS
Date the key was created.
This property is read-only.
EOS
end
end

View file

@ -0,0 +1,63 @@
require 'uri'
require 'stringio'
require 'time'
module URI
class FTP
def buffer_open(buf, proxy, options) # :nodoc:
if proxy
OpenURI.open_http(buf, self, proxy, options)
return
end
require 'net/ftp'
directories = self.path.split(%r{/}, -1)
directories.shift if directories[0] == '' # strip a field before leading slash
directories.each {|d|
d.gsub!(/%([0-9A-Fa-f][0-9A-Fa-f])/) { [$1].pack("H2") }
}
unless filename = directories.pop
raise ArgumentError, "no filename: #{self.inspect}"
end
directories.each {|d|
if /[\r\n]/ =~ d
raise ArgumentError, "invalid directory: #{d.inspect}"
end
}
if /[\r\n]/ =~ filename
raise ArgumentError, "invalid filename: #{filename.inspect}"
end
typecode = self.typecode
if typecode && /\A[aid]\z/ !~ typecode
raise ArgumentError, "invalid typecode: #{typecode.inspect}"
end
# The access sequence is defined by RFC 1738
ftp = Net::FTP.open(self.host)
ftp.passive = true if !options[:ftp_active_mode]
# todo: extract user/passwd from .netrc.
user = 'anonymous'
passwd = nil
user, passwd = self.userinfo.split(/:/) if self.userinfo
ftp.login(user, passwd)
directories.each {|cwd|
ftp.voidcmd("CWD #{cwd}")
}
if typecode
# xxx: typecode D is not handled.
ftp.voidcmd("TYPE #{typecode.upcase}")
end
if options[:content_length_proc]
options[:content_length_proc].call(ftp.size(filename))
end
ftp.retrbinary("RETR #{filename}", 4096) { |str|
buf << str
options[:progress_proc].call(buf.size) if options[:progress_proc]
}
ftp.close
buf.io.rewind
end
include OpenURI::OpenRead
end
end

View file

@ -0,0 +1,59 @@
# This adds the necessary components to get backports for ubuntu and debian
#
# == Parameters
#
# [*release*]
# The ubuntu/debian release name. Defaults to $lsbdistcodename. Setting this
# manually can cause undefined behavior. (Read: universe exploding)
#
# [*pin_priority*]
# _default_: 200
#
# The priority that should be awarded by default to all packages coming from
# the Debian Backports project.
#
# == Examples
#
# include apt::backports
#
# class { 'apt::backports':
# release => 'natty',
# }
#
# == Authors
#
# Ben Hughes, I think. At least blame him if this goes wrong.
# I just added puppet doc.
#
# == Copyright
#
# Copyright 2011 Puppet Labs Inc, unless otherwise noted.
class apt::backports(
$release = $::lsbdistcodename,
$location = $::apt::params::backports_location,
$pin_priority = 200,
) inherits apt::params {
if ! is_integer($pin_priority) {
fail('$pin_priority must be an integer')
}
$release_real = downcase($release)
$key = $::lsbdistid ? {
'debian' => '46925553',
'ubuntu' => '437D05B5',
}
$repos = $::lsbdistid ? {
'debian' => 'main contrib non-free',
'ubuntu' => 'main universe multiverse restricted',
}
apt::source { 'backports':
location => $location,
release => "${release_real}-backports",
repos => $repos,
key => $key,
key_server => 'pgp.mit.edu',
pin => $pin_priority,
}
}

View file

@ -0,0 +1,16 @@
# builddep.pp
define apt::builddep() {
include apt::update
exec { "apt-builddep-${name}":
command => "/usr/bin/apt-get -y --force-yes build-dep ${name}",
logoutput => 'on_failure',
notify => Exec['apt_update'],
}
# Need anchor to provide containment for dependencies.
anchor { "apt::builddep::${name}":
require => Class['apt::update'],
}
}

View file

@ -0,0 +1,18 @@
define apt::conf (
$content,
$ensure = present,
$priority = '50'
) {
include apt::params
$apt_conf_d = $apt::params::apt_conf_d
file { "${apt_conf_d}/${priority}${name}":
ensure => $ensure,
content => $content,
owner => root,
group => root,
mode => '0644',
}
}

View file

@ -0,0 +1,21 @@
# testing.pp
class apt::debian::testing {
include apt
# deb http://debian.mirror.iweb.ca/debian/ testing main contrib non-free
# deb-src http://debian.mirror.iweb.ca/debian/ testing main contrib non-free
# Key: 46925553 Server: subkeys.pgp.net
# debian-keyring
# debian-archive-keyring
apt::source { 'debian_testing':
location => 'http://debian.mirror.iweb.ca/debian/',
release => 'testing',
repos => 'main contrib non-free',
required_packages => 'debian-keyring debian-archive-keyring',
key => '46925553',
key_server => 'subkeys.pgp.net',
pin => '-10',
}
}

View file

@ -0,0 +1,21 @@
# unstable.pp
class apt::debian::unstable {
include apt
# deb http://debian.mirror.iweb.ca/debian/ unstable main contrib non-free
# deb-src http://debian.mirror.iweb.ca/debian/ unstable main contrib non-free
# Key: 46925553 Server: subkeys.pgp.net
# debian-keyring
# debian-archive-keyring
apt::source { 'debian_unstable':
location => 'http://debian.mirror.iweb.ca/debian/',
release => 'unstable',
repos => 'main contrib non-free',
required_packages => 'debian-keyring debian-archive-keyring',
key => '46925553',
key_server => 'subkeys.pgp.net',
pin => '-10',
}
}

View file

@ -0,0 +1,42 @@
# force.pp
# force a package from a specific release
define apt::force(
$release = false,
$version = false,
$timeout = 300
) {
$provider = $apt::params::provider
$version_string = $version ? {
false => undef,
default => "=${version}",
}
$release_string = $release ? {
false => undef,
default => "-t ${release}",
}
if $version == false {
if $release == false {
$install_check = "/usr/bin/dpkg -s ${name} | grep -q 'Status: install'"
} else {
# If installed version and candidate version differ, this check returns 1 (false).
$install_check = "/usr/bin/test \$(/usr/bin/apt-cache policy -t ${release} ${name} | /bin/grep -E 'Installed|Candidate' | /usr/bin/uniq -s 14 | /usr/bin/wc -l) -eq 1"
}
} else {
if $release == false {
$install_check = "/usr/bin/dpkg -s ${name} | grep -q 'Version: ${version}'"
} else {
$install_check = "/usr/bin/apt-cache policy -t ${release} ${name} | /bin/grep -q 'Installed: ${version}'"
}
}
exec { "${provider} -y ${release_string} install ${name}${version_string}":
unless => $install_check,
logoutput => 'on_failure',
timeout => $timeout,
}
}

View file

@ -0,0 +1,54 @@
# == Define apt::hold
#
# This defined type allows you to hold a package based on the version you
# require. It's implemented by dropping an apt preferences file pinning the
# package to the version you require.
#
# === Parameters
#
# [*version*]
# The version at which you wish to pin a package.
#
# This can either be the full version, such as 4:2.11.8.1-5, or
# a partial version, such as 4:2.11.*
#
# [*package*]
# _default_: +$title+, the title/name of the resource.
#
# Name of the package that apt is to hold.
#
# [*priority*]
# _default_: +1001+
#
# The default priority of 1001 causes this preference to always win. By
# setting the priority to a number greater than 1000 apt will always install
# this version even if it means downgrading the currently installed version.
define apt::hold(
$version,
$ensure = 'present',
$package = $title,
$priority = 1001,
){
validate_string($title)
validate_re($ensure, ['^present|absent',])
validate_string($package)
validate_string($version)
if ! is_integer($priority) {
fail('$priority must be an integer')
}
if $ensure == 'present' {
::apt::pin { "hold ${package} at ${version}":
packages => $package,
version => $version,
priority => $priority,
}
} else {
::apt::pin { "hold ${package} at ${version}":
ensure => 'absent',
}
}
}

View file

@ -0,0 +1,154 @@
# Class: apt
#
# This module manages the initial configuration of apt.
#
# Parameters:
# The parameters listed here are not required in general and were
# added for use cases related to development environments.
# disable_keys - disables the requirement for all packages to be signed
# always_apt_update - rather apt should be updated on every run (intended
# for development environments where package updates are frequent)
# purge_sources_list - Accepts true or false. Defaults to false If set to
# true, Puppet will purge all unmanaged entries from sources.list
# purge_sources_list_d - Accepts true or false. Defaults to false. If set
# to true, Puppet will purge all unmanaged entries from sources.list.d
# update_timeout - Overrides the exec timeout in seconds for apt-get update.
# If not set defaults to Exec's default (300)
# update_tries - Number of times that `apt-get update` will be tried. Use this
# to work around transient DNS and HTTP errors. By default, the command
# will only be run once.
#
# Actions:
#
# Requires:
# puppetlabs/stdlib
# Sample Usage:
# class { 'apt': }
class apt(
$always_apt_update = false,
$disable_keys = undef,
$proxy_host = undef,
$proxy_port = '8080',
$purge_sources_list = false,
$purge_sources_list_d = false,
$purge_preferences = false,
$purge_preferences_d = false,
$update_timeout = undef,
$update_tries = undef,
$sources = undef
) {
if $::osfamily != 'Debian' {
fail('This module only works on Debian or derivatives like Ubuntu')
}
include apt::params
include apt::update
validate_bool($purge_sources_list, $purge_sources_list_d,
$purge_preferences, $purge_preferences_d)
$sources_list_content = $purge_sources_list ? {
false => undef,
true => "# Repos managed by puppet.\n",
}
if $always_apt_update == true {
Exec <| title=='apt_update' |> {
refreshonly => false,
}
}
$root = $apt::params::root
$apt_conf_d = $apt::params::apt_conf_d
$sources_list_d = $apt::params::sources_list_d
$preferences_d = $apt::params::preferences_d
$provider = $apt::params::provider
file { 'sources.list':
ensure => present,
path => "${root}/sources.list",
owner => root,
group => root,
mode => '0644',
content => $sources_list_content,
notify => Exec['apt_update'],
}
file { 'sources.list.d':
ensure => directory,
path => $sources_list_d,
owner => root,
group => root,
purge => $purge_sources_list_d,
recurse => $purge_sources_list_d,
notify => Exec['apt_update'],
}
if $purge_preferences {
file { 'apt-preferences':
ensure => absent,
path => "${root}/preferences",
}
}
file { 'preferences.d':
ensure => directory,
path => $preferences_d,
owner => root,
group => root,
purge => $purge_preferences_d,
recurse => $purge_preferences_d,
}
case $disable_keys {
true: {
file { '99unauth':
ensure => present,
content => "APT::Get::AllowUnauthenticated 1;\n",
path => "${apt_conf_d}/99unauth",
}
}
false: {
file { '99unauth':
ensure => absent,
path => "${apt_conf_d}/99unauth",
}
}
undef: { } # do nothing
default: { fail('Valid values for disable_keys are true or false') }
}
$proxy_set = $proxy_host ? {
undef => absent,
default => present
}
file { '01proxy':
ensure => $proxy_set,
path => "${apt_conf_d}/01proxy",
content => "Acquire::http::Proxy \"http://${proxy_host}:${proxy_port}\";\n",
notify => Exec['apt_update'],
mode => '0644',
owner => root,
group => root,
}
file { 'old-proxy-file':
ensure => absent,
path => "${apt_conf_d}/proxy",
notify => Exec['apt_update'],
}
# Need anchor to provide containment for dependencies.
anchor { 'apt::update':
require => Class['apt::update'],
}
# manage sources if present
if $sources != undef {
validate_hash($sources)
create_resources('apt::source', $sources)
}
}

View file

@ -0,0 +1,121 @@
# == Define: apt::key
#
# The apt::key defined type allows for keys to be added to apt's keyring
# which is used for package validation. This defined type uses the apt_key
# native type to manage keys. This is a simple wrapper around apt_key with
# a few safeguards in place.
#
# === Parameters
#
# [*key*]
# _default_: +$title+, the title/name of the resource
#
# Is a GPG key ID. This key ID is validated with a regex enforcing it
# to only contain valid hexadecimal characters, be precisely 8 or 16
# characters long and optionally prefixed with 0x.
#
# [*ensure*]
# _default_: +present+
#
# The state we want this key in, may be either one of:
# * +present+
# * +absent+
#
# [*key_content*]
# _default_: +undef+
#
# This parameter can be used to pass in a GPG key as a
# string in case it cannot be fetched from a remote location
# and using a file resource is for other reasons inconvenient.
#
# [*key_source*]
# _default_: +undef+
#
# This parameter can be used to pass in the location of a GPG
# key. This URI can take the form of a:
# * +URL+: ftp, http or https
# * +path+: absolute path to a file on the target system.
#
# [*key_server*]
# _default_: +undef+
#
# The keyserver from where to fetch our GPG key. It defaults to
# undef which results in apt_key's default keyserver being used,
# currently +keyserver.ubuntu.com+.
#
# [*key_options*]
# _default_: +undef+
#
# Additional options to pass on to `apt-key adv --keyserver-options`.
define apt::key (
$key = $title,
$ensure = present,
$key_content = undef,
$key_source = undef,
$key_server = undef,
$key_options = undef,
) {
validate_re($key, ['\A(0x)?[0-9a-fA-F]{8}\Z', '\A(0x)?[0-9a-fA-F]{16}\Z'])
validate_re($ensure, ['\Aabsent|present\Z',])
if $key_content {
validate_string($key_content)
}
if $key_source {
validate_re($key_source, ['\Ahttps?:\/\/', '\Aftp:\/\/', '\A\/\w+'])
}
if $key_server {
if !is_domain_name($key_server) {
fail('$key_server must be a valid domain name')
}
}
if $key_options {
validate_string($key_options)
}
case $ensure {
present: {
if defined(Anchor["apt_key ${key} absent"]){
fail("key with id ${key} already ensured as absent")
}
if !defined(Anchor["apt_key ${key} present"]) {
apt_key { $title:
ensure => $ensure,
id => $key,
source => $key_source,
content => $key_content,
server => $key_server,
keyserver_options => $key_options,
} ->
anchor { "apt_key ${key} present": }
}
}
absent: {
if defined(Anchor["apt_key ${key} present"]){
fail("key with id ${key} already ensured as present")
}
if !defined(Anchor["apt_key ${key} absent"]){
apt_key { $title:
ensure => $ensure,
id => $key,
source => $key_source,
content => $key_content,
server => $key_server,
keyserver_options => $key_options,
} ->
anchor { "apt_key ${key} absent": }
}
}
default: {
fail "Invalid 'ensure' value '${ensure}' for apt::key"
}
}
}

View file

@ -0,0 +1,55 @@
class apt::params {
$root = '/etc/apt'
$provider = '/usr/bin/apt-get'
$sources_list_d = "${root}/sources.list.d"
$apt_conf_d = "${root}/apt.conf.d"
$preferences_d = "${root}/preferences.d"
case $::lsbdistid {
'debian': {
case $::lsbdistcodename {
'squeeze': {
$backports_location = 'http://backports.debian.org/debian-backports'
$legacy_origin = true
$origins = ['${distro_id} oldstable',
'${distro_id} ${distro_codename}-security']
}
'wheezy': {
$backports_location = 'http://ftp.debian.org/debian/'
$legacy_origin = false
$origins = ['origin=Debian,archive=stable,label=Debian-Security']
}
default: {
$backports_location = 'http://http.debian.net/debian/'
$legacy_origin = false
$origins = ['origin=Debian,archive=stable,label=Debian-Security']
}
}
}
'ubuntu': {
case $::lsbdistcodename {
'lucid': {
$backports_location = 'http://us.archive.ubuntu.com/ubuntu'
$ppa_options = undef
$legacy_origin = true
$origins = ['${distro_id} ${distro_codename}-security']
}
'precise', 'trusty': {
$backports_location = 'http://us.archive.ubuntu.com/ubuntu'
$ppa_options = '-y'
$legacy_origin = true
$origins = ['${distro_id}:${distro_codename}-security']
}
default: {
$backports_location = 'http://old-releases.ubuntu.com/ubuntu'
$ppa_options = '-y'
$legacy_origin = true
$origins = ['${distro_id}:${distro_codename}-security']
}
}
}
default: {
fail("Unsupported lsbdistid (${::lsbdistid})")
}
}
}

View file

@ -0,0 +1,89 @@
# pin.pp
# pin a release in apt, useful for unstable repositories
define apt::pin(
$ensure = present,
$explanation = "${caller_module_name}: ${name}",
$order = '',
$packages = '*',
$priority = 0,
$release = '', # a=
$origin = '',
$version = '',
$codename = '', # n=
$release_version = '', # v=
$component = '', # c=
$originator = '', # o=
$label = '' # l=
) {
include apt::params
$preferences_d = $apt::params::preferences_d
if $order != '' and !is_integer($order) {
fail('Only integers are allowed in the apt::pin order param')
}
$pin_release_array = [
$release,
$codename,
$release_version,
$component,
$originator,
$label]
$pin_release = join($pin_release_array, '')
# Read the manpage 'apt_preferences(5)', especially the chapter
# 'Thea Effect of APT Preferences' to understand the following logic
# and the difference between specific and general form
if is_array($packages) {
$packages_string = join($packages, ' ')
} else {
$packages_string = $packages
}
if $packages_string != '*' { # specific form
if ( $pin_release != '' and ( $origin != '' or $version != '' )) or
( $origin != '' and ( $pin_release != '' or $version != '' )) or
( $version != '' and ( $pin_release != '' or $origin != '' )) {
fail('parameters release, origin, and version are mutually exclusive')
}
} else { # general form
if $version != '' {
fail('parameter version cannot be used in general form')
}
if ( $pin_release != '' and $origin != '' ) or
( $origin != '' and $pin_release != '' ) {
fail('parmeters release and origin are mutually exclusive')
}
}
$path = $order ? {
'' => "${preferences_d}/${name}.pref",
default => "${preferences_d}/${order}-${name}.pref",
}
# According to man 5 apt_preferences:
# The files have either no or "pref" as filename extension
# and only contain alphanumeric, hyphen (-), underscore (_) and period
# (.) characters. Otherwise APT will print a notice that it has ignored a
# file, unless that file matches a pattern in the
# Dir::Ignore-Files-Silently configuration list - in which case it will
# be silently ignored.
$file_name = regsubst($title, '[^0-9a-z\-_\.]', '_', 'IG')
file { "${file_name}.pref":
ensure => $ensure,
path => $path,
owner => root,
group => root,
mode => '0644',
content => template('apt/pin.pref.erb'),
}
}

View file

@ -0,0 +1,81 @@
# ppa.pp
define apt::ppa(
$ensure = 'present',
$release = $::lsbdistcodename,
$options = $apt::params::ppa_options,
) {
include apt::params
include apt::update
$sources_list_d = $apt::params::sources_list_d
if ! $release {
fail('lsbdistcodename fact not available: release parameter required')
}
if $::operatingsystem != 'Ubuntu' {
fail('apt::ppa is currently supported on Ubuntu only.')
}
$filename_without_slashes = regsubst($name, '/', '-', 'G')
$filename_without_dots = regsubst($filename_without_slashes, '\.', '_', 'G')
$filename_without_ppa = regsubst($filename_without_dots, '^ppa:', '', 'G')
$sources_list_d_filename = "${filename_without_ppa}-${release}.list"
if $ensure == 'present' {
$package = $::lsbdistrelease ? {
/^[1-9]\..*|1[01]\..*|12.04$/ => 'python-software-properties',
default => 'software-properties-common',
}
if ! defined(Package[$package]) {
package { $package: }
}
if defined(Class[apt]) {
$proxy_host = $apt::proxy_host
$proxy_port = $apt::proxy_port
case $proxy_host {
false, '': {
$proxy_env = []
}
default: {$proxy_env = ["http_proxy=http://${proxy_host}:${proxy_port}", "https_proxy=http://${proxy_host}:${proxy_port}"]}
}
} else {
$proxy_env = []
}
exec { "add-apt-repository-${name}":
environment => $proxy_env,
command => "/usr/bin/add-apt-repository ${options} ${name}",
unless => "/usr/bin/test -s ${sources_list_d}/${sources_list_d_filename}",
user => 'root',
logoutput => 'on_failure',
notify => Exec['apt_update'],
require => [
File['sources.list.d'],
Package[$package],
],
}
file { "${sources_list_d}/${sources_list_d_filename}":
ensure => file,
require => Exec["add-apt-repository-${name}"],
}
}
else {
file { "${sources_list_d}/${sources_list_d_filename}":
ensure => 'absent',
mode => '0644',
owner => 'root',
group => 'root',
notify => Exec['apt_update'],
}
}
# Need anchor to provide containment for dependencies.
anchor { "apt::ppa::${name}":
require => Class['apt::update'],
}
}

View file

@ -0,0 +1,17 @@
# release.pp
class apt::release (
$release_id
) {
include apt::params
$root = $apt::params::root
file { "${root}/apt.conf.d/01release":
owner => root,
group => root,
mode => '0644',
content => "APT::Default-Release \"${release_id}\";"
}
}

View file

@ -0,0 +1,87 @@
# source.pp
# add an apt source
define apt::source(
$ensure = present,
$location = '',
$release = 'UNDEF',
$repos = 'main',
$include_src = true,
$required_packages = false,
$key = undef,
$key_server = 'keyserver.ubuntu.com',
$key_content = undef,
$key_source = undef,
$pin = false,
$architecture = undef
) {
include apt::params
include apt::update
$sources_list_d = $apt::params::sources_list_d
$provider = $apt::params::provider
if $release == 'UNDEF' {
if $::lsbdistcodename == undef {
fail('lsbdistcodename fact not available: release parameter required')
} else {
$release_real = $::lsbdistcodename
}
} else {
$release_real = $release
}
file { "${name}.list":
ensure => $ensure,
path => "${sources_list_d}/${name}.list",
owner => root,
group => root,
mode => '0644',
content => template("${module_name}/source.list.erb"),
notify => Exec['apt_update'],
}
if ($pin != false) {
# Get the host portion out of the url so we can pin to origin
$url_split = split($location, '/')
$host = $url_split[2]
apt::pin { $name:
ensure => $ensure,
priority => $pin,
before => File["${name}.list"],
origin => $host,
}
}
if ($required_packages != false) and ($ensure == 'present') {
exec { "Required packages: '${required_packages}' for ${name}":
command => "${provider} -y install ${required_packages}",
logoutput => 'on_failure',
refreshonly => true,
tries => 3,
try_sleep => 1,
subscribe => File["${name}.list"],
before => Exec['apt_update'],
}
}
# We do not want to remove keys when the source is absent.
if $key and ($ensure == 'present') {
apt::key { "Add key: ${key} from Apt::Source ${title}":
ensure => present,
key => $key,
key_server => $key_server,
key_content => $key_content,
key_source => $key_source,
before => File["${name}.list"],
}
}
# Need anchor to provide containment for dependencies.
anchor { "apt::source::${name}":
require => Class['apt::update'],
}
}

View file

@ -0,0 +1,69 @@
# Class: apt::unattended_upgrades
#
# This class manages the unattended-upgrades package and related configuration
# files for ubuntu
#
# origins are the repositories to automatically upgrade included packages
# blacklist is a list of packages to not automatically upgrade
# update is how often to run "apt-get update" in days
# download is how often to run "apt-get upgrade --download-only" in days
# upgrade is how often to upgrade packages included in the origins list in days
# autoclean is how often to run "apt-get autoclean" in days
#
# information on the other options can be found in the 50unattended-upgrades
# file and in /etc/cron.daily/apt
#
class apt::unattended_upgrades (
$origins = $::apt::params::origins,
$blacklist = [],
$update = '1',
$download = '1',
$upgrade = '1',
$autoclean = '7',
$auto_fix = true,
$minimal_steps = false,
$install_on_shutdown = false,
$mail_to = 'NONE',
$mail_only_on_error = false,
$remove_unused = true,
$auto_reboot = false,
$dl_limit = 'NONE',
$enable = '1',
$backup_interval = '0',
$backup_level = '3',
$max_age = '0',
$min_age = '0',
$max_size = '0',
$download_delta = '0',
$verbose = '0',
) inherits ::apt::params {
validate_bool(
$auto_fix,
$minimal_steps,
$install_on_shutdown,
$mail_only_on_error,
$remove_unused,
$auto_reboot
)
validate_array($origins)
package { 'unattended-upgrades':
ensure => present,
}
File {
ensure => file,
owner => 'root',
group => 'root',
mode => '0644',
require => Package['unattended-upgrades'],
}
file {
'/etc/apt/apt.conf.d/50unattended-upgrades':
content => template('apt/50unattended-upgrades.erb');
'/etc/apt/apt.conf.d/10periodic':
content => template('apt/10periodic.erb');
}
}

View file

@ -0,0 +1,12 @@
class apt::update {
include apt::params
exec { 'apt_update':
command => "${apt::params::provider} update",
logoutput => 'on_failure',
refreshonly => true,
timeout => $apt::update_timeout,
tries => $apt::update_tries,
try_sleep => 1
}
}

41
modules/apt/metadata.json Normal file
View file

@ -0,0 +1,41 @@
{
"name": "puppetlabs-apt",
"version": "1.5.0",
"author": "Evolving Web / Puppet Labs",
"summary": "Puppet Labs Apt Module",
"license": "Apache License 2.0",
"source": "https://github.com/puppetlabs/puppetlabs-apt",
"project_page": "https://github.com/puppetlabs/puppetlabs-apt",
"issues_url": "https://github.com/puppetlabs/puppetlabs-apt/issues",
"operatingsystem_support": [
{
"operatingsystem": "Debian",
"operatingsystemrelease": [
"6",
"7"
]
},
{
"operatingsystem": "Ubuntu",
"operatingsystemrelease": [
"10.04",
"12.04",
"14.04"
]
}
],
"requirements": [
{
"name": "pe",
"version_requirement": ">= 3.2.0 < 3.4.0"
},
{
"name": "puppet",
"version_requirement": "3.x"
}
],
"description": "APT Module for Puppet",
"dependencies": [
{"name":"puppetlabs/stdlib","version_requirement":">= 2.2.1"}
]
}

View file

@ -0,0 +1,36 @@
require 'spec_helper_acceptance'
describe 'apt::builddep', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
context 'reset' do
it 'removes packages' do
shell('apt-get -y remove znc')
shell('apt-get -y remove g++')
end
end
context 'apt::builddep' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::builddep { 'znc': }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe 'should install g++ as a dependency' do
describe package('g++') do
it { should be_installed }
end
end
end
context 'reset' do
it 'removes packages' do
shell('apt-get -y remove znc')
shell('apt-get -y remove g++')
end
end
end

View file

@ -0,0 +1,446 @@
require 'spec_helper_acceptance'
PUPPETLABS_GPG_KEY_ID = '4BD6EC30'
PUPPETLABS_APT_URL = 'apt.puppetlabs.com'
PUPPETLABS_GPG_KEY_FILE = 'pubkey.gpg'
CENTOS_GPG_KEY_ID = 'C105B9DE'
CENTOS_REPO_URL = 'ftp.cvut.cz/centos'
CENTOS_GPG_KEY_FILE = 'RPM-GPG-KEY-CentOS-6'
describe 'apt_key', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
before(:each) do
shell("apt-key del #{PUPPETLABS_GPG_KEY_ID}",
:acceptable_exit_codes => [0,1,2])
end
describe 'default options' do
key_versions = {
'32bit key id' => '4BD6EC30',
'64bit key id' => '1054B7A24BD6EC30',
'32bit lowercase key id' => '4bd6ec30',
'64bit lowercase key id' => '1054b7a24bd6ec30',
'0x formatted 32bit key id' => '0x4BD6EC30',
'0x formatted 64bit key id' => '0x1054B7A24BD6EC30',
'0x formatted 32bit lowercase key id' => '0x4bd6ec30',
'0x formatted 64bit lowercase key id' => '0x1054b7a24bd6ec30',
}
key_versions.each do |key, value|
context "#{key}" do
it 'works' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '#{value}',
ensure => 'present',
}
EOS
apply_manifest(pp, :catch_failures => true)
expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
end
end
end
context 'invalid length key id' do
it 'fails' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '4B7A24BD6EC30',
}
EOS
apply_manifest(pp, :expect_failures => true) do |r|
expect(r.stderr).to match(/Valid values match/)
end
end
end
end
describe 'ensure =>' do
context 'absent' do
it 'is removed' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '#{PUPPETLABS_GPG_KEY_ID}',
ensure => 'absent',
}
EOS
# Install the key first
shell("apt-key adv --keyserver keyserver.ubuntu.com \
--recv-keys #{PUPPETLABS_GPG_KEY_ID}")
shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
# Time to remove it using Puppet
apply_manifest(pp, :catch_failures => true)
expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}",
:acceptable_exit_codes => [1])
end
end
end
describe 'content =>' do
context 'puppetlabs gpg key' do
it 'works' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '#{PUPPETLABS_GPG_KEY_ID}',
ensure => 'present',
content => "-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.12 (GNU/Linux)
Comment: GPGTools - http://gpgtools.org
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
=a34C
-----END PGP PUBLIC KEY BLOCK-----",
}
EOS
apply_manifest(pp, :catch_failures => true)
expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
end
end
context 'bogus key' do
it 'fails' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '#{PUPPETLABS_GPG_KEY_ID}',
ensure => 'present',
content => 'For posterity: such content, much bogus, wow',
}
EOS
apply_manifest(pp, :expect_failures => true) do |r|
expect(r.stderr).to match(/no valid OpenPGP data found/)
end
end
end
end
describe 'server =>' do
context 'pgp.mit.edu' do
it 'works' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '#{PUPPETLABS_GPG_KEY_ID}',
ensure => 'present',
server => 'pgp.mit.edu',
}
EOS
apply_manifest(pp, :catch_failures => true)
expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
end
end
context 'nonexistant.key.server' do
it 'fails' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '#{PUPPETLABS_GPG_KEY_ID}',
ensure => 'present',
server => 'nonexistant.key.server',
}
EOS
apply_manifest(pp, :expect_failures => true) do |r|
expect(r.stderr).to match(/(Host not found|Couldn't resolve host)/)
end
end
end
end
describe 'source =>' do
context 'http://' do
it 'works' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '#{PUPPETLABS_GPG_KEY_ID}',
ensure => 'present',
source => 'http://#{PUPPETLABS_APT_URL}/#{PUPPETLABS_GPG_KEY_FILE}',
}
EOS
apply_manifest(pp, :catch_failures => true)
expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
end
it 'fails with a 404' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '#{PUPPETLABS_GPG_KEY_ID}',
ensure => 'present',
source => 'http://#{PUPPETLABS_APT_URL}/herpderp.gpg',
}
EOS
apply_manifest(pp, :expect_failures => true) do |r|
expect(r.stderr).to match(/404 Not Found/)
end
end
it 'fails with a socket error' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '#{PUPPETLABS_GPG_KEY_ID}',
ensure => 'present',
source => 'http://apt.puppetlabss.com/herpderp.gpg',
}
EOS
apply_manifest(pp, :expect_failures => true) do |r|
expect(r.stderr).to match(/could not resolve/)
end
end
end
context 'ftp://' do
before(:each) do
shell("apt-key del #{CENTOS_GPG_KEY_ID}",
:acceptable_exit_codes => [0,1,2])
end
it 'works' do
pp = <<-EOS
apt_key { 'CentOS 6':
id => '#{CENTOS_GPG_KEY_ID}',
ensure => 'present',
source => 'ftp://#{CENTOS_REPO_URL}/#{CENTOS_GPG_KEY_FILE}',
}
EOS
apply_manifest(pp, :catch_failures => true)
expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
shell("apt-key list | grep #{CENTOS_GPG_KEY_ID}")
end
it 'fails with a 550' do
pp = <<-EOS
apt_key { 'CentOS 6':
id => '#{CENTOS_GPG_KEY_ID}',
ensure => 'present',
source => 'ftp://#{CENTOS_REPO_URL}/herpderp.gpg',
}
EOS
apply_manifest(pp, :expect_failures => true) do |r|
expect(r.stderr).to match(/550 Failed to open/)
end
end
it 'fails with a socket error' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '#{PUPPETLABS_GPG_KEY_ID}',
ensure => 'present',
source => 'ftp://apt.puppetlabss.com/herpderp.gpg',
}
EOS
apply_manifest(pp, :expect_failures => true) do |r|
expect(r.stderr).to match(/could not resolve/)
end
end
end
context 'https://' do
it 'works' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '#{PUPPETLABS_GPG_KEY_ID}',
ensure => 'present',
source => 'https://#{PUPPETLABS_APT_URL}/#{PUPPETLABS_GPG_KEY_FILE}',
}
EOS
apply_manifest(pp, :catch_failures => true)
expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
end
it 'fails with a 404' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '4BD6EC30',
ensure => 'present',
source => 'https://#{PUPPETLABS_APT_URL}/herpderp.gpg',
}
EOS
apply_manifest(pp, :expect_failures => true) do |r|
expect(r.stderr).to match(/404 Not Found/)
end
end
it 'fails with a socket error' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '4BD6EC30',
ensure => 'present',
source => 'https://apt.puppetlabss.com/herpderp.gpg',
}
EOS
apply_manifest(pp, :expect_failures => true) do |r|
expect(r.stderr).to match(/could not resolve/)
end
end
end
context '/path/that/exists' do
before(:each) do
shell("curl -o /tmp/puppetlabs-pubkey.gpg \
http://#{PUPPETLABS_APT_URL}/#{PUPPETLABS_GPG_KEY_FILE}")
end
after(:each) do
shell('rm /tmp/puppetlabs-pubkey.gpg')
end
it 'works' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '4BD6EC30',
ensure => 'present',
source => '/tmp/puppetlabs-pubkey.gpg',
}
EOS
apply_manifest(pp, :catch_failures => true)
expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
end
end
context '/path/that/does/not/exist' do
it 'fails' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '#{PUPPETLABS_GPG_KEY_ID}',
ensure => 'present',
source => '/tmp/totally_bogus.file',
}
EOS
apply_manifest(pp, :expect_failures => true) do |r|
expect(r.stderr).to match(/does not exist/)
end
end
end
context '/path/that/exists/with/bogus/content' do
before(:each) do
shell('echo "here be dragons" > /tmp/fake-key.gpg')
end
after(:each) do
shell('rm /tmp/fake-key.gpg')
end
it 'fails' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '#{PUPPETLABS_GPG_KEY_ID}',
ensure => 'present',
source => '/tmp/fake-key.gpg',
}
EOS
apply_manifest(pp, :expect_failures => true) do |r|
expect(r.stderr).to match(/no valid OpenPGP data found/)
end
end
end
end
describe 'keyserver_options =>' do
context 'debug' do
it 'works' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '#{PUPPETLABS_GPG_KEY_ID}',
ensure => 'present',
keyserver_options => 'debug',
}
EOS
apply_manifest(pp, :catch_failures => true)
expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
end
it 'fails on invalid options' do
pp = <<-EOS
apt_key { 'puppetlabs':
id => '#{PUPPETLABS_GPG_KEY_ID}',
ensure => 'present',
keyserver_options => 'this is totally bonkers',
}
EOS
apply_manifest(pp, :expect_failures => true) do |r|
expect(r.stderr).to match(/--keyserver-options this is totally/)
end
end
end
end
end

View file

@ -0,0 +1,200 @@
require 'spec_helper_acceptance'
describe 'apt::key', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
context 'apt::key' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::key { 'puppetlabs':
key => '4BD6EC30',
key_server => 'pgp.mit.edu',
}
apt::key { 'jenkins':
key => 'D50582E6',
key_source => 'http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key',
}
EOS
shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
shell('apt-key del D50582E6', :acceptable_exit_codes => [0,1,2])
apply_manifest(pp, :catch_failures => true)
end
describe 'keys should exist' do
it 'finds puppetlabs key' do
shell('apt-key list | grep 4BD6EC30')
end
it 'finds jenkins key' do
shell('apt-key list | grep D50582E6')
end
end
end
context 'ensure' do
context 'absent' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::key { 'puppetlabs':
ensure => absent,
key => '4BD6EC30',
key_server => 'pgp.mit.edu',
}
apt::key { 'jenkins':
ensure => absent,
key => 'D50582E6',
key_source => 'http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe 'keys shouldnt exist' do
it 'fails' do
shell('apt-key list | grep 4BD6EC30', :acceptable_exit_codes => [1])
end
it 'fails' do
shell('apt-key list | grep D50582E6', :acceptable_exit_codes => [1])
end
end
end
end
context 'reset' do
it 'clean up keys' do
shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
shell('apt-key del D50582E6', :acceptable_exit_codes => [0,1,2])
end
end
context 'key options' do
context 'key_content' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::key { 'puppetlabs':
key => '4BD6EC30',
key_content => '-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.12 (GNU/Linux)
Comment: GPGTools - http://gpgtools.org
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
=a34C
-----END PGP PUBLIC KEY BLOCK-----
',
}
EOS
shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
apply_manifest(pp, :catch_failures => true)
end
end
describe 'keys should exist' do
it 'finds puppetlabs key' do
shell('apt-key list | grep 4BD6EC30')
end
end
context 'key_source' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::key { 'puppetlabs':
key => '4BD6EC30',
key_source => 'http://apt.puppetlabs.com/pubkey.gpg',
}
EOS
shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
apply_manifest(pp, :catch_failures => true)
end
describe 'keys should exist' do
it 'finds puppetlabs key' do
shell('apt-key list | grep 4BD6EC30')
end
end
end
context 'key_options' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::key { 'puppetlabs':
key => '4BD6EC30',
key_source => 'http://apt.puppetlabs.com/pubkey.gpg',
key_options => 'debug'
}
EOS
shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
apply_manifest(pp, :catch_failures => true)
end
describe 'keys should exist' do
it 'finds puppetlabs key' do
shell('apt-key list | grep 4BD6EC30')
end
end
end
end
end

View file

@ -0,0 +1,138 @@
require 'spec_helper_acceptance'
if fact('operatingsystem') == 'Ubuntu'
describe 'apt::ppa', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
context 'reset' do
it 'removes ppa' do
shell('rm /etc/apt/sources.list.d/canonical-kernel-team-ppa-*', :acceptable_exit_codes => [0,1,2])
shell('rm /etc/apt/sources.list.d/raravena80-collectd5-*', :acceptable_exit_codes => [0,1,2])
end
end
context 'adding a ppa that doesnt exist' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::ppa { 'ppa:canonical-kernel-team/ppa': }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe 'contains the source file' do
it 'contains a kernel ppa source' do
shell('ls /etc/apt/sources.list.d/canonical-kernel-team-ppa-*', :acceptable_exit_codes => [0])
end
end
end
context 'reading a removed ppa.' do
it 'setup' do
# This leaves a blank file
shell('echo > /etc/apt/sources.list.d/raravena80-collectd5-$(lsb_release -c -s).list')
end
it 'should read it successfully' do
pp = <<-EOS
include '::apt'
apt::ppa { 'ppa:raravena80/collectd5': }
EOS
apply_manifest(pp, :catch_failures => true)
end
end
context 'reset' do
it 'removes added ppas' do
shell('rm /etc/apt/sources.list.d/canonical-kernel-team-ppa-*')
shell('rm /etc/apt/sources.list.d/raravena80-collectd5-*')
end
end
context 'ensure' do
context 'present' do
it 'works without failure' do
pp = <<-EOS
include '::apt'
apt::ppa { 'ppa:canonical-kernel-team/ppa': ensure => present }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe 'contains the source file' do
it 'contains a kernel ppa source' do
shell('ls /etc/apt/sources.list.d/canonical-kernel-team-ppa-*', :acceptable_exit_codes => [0])
end
end
end
end
context 'ensure' do
context 'absent' do
it 'works without failure' do
pp = <<-EOS
include '::apt'
apt::ppa { 'ppa:canonical-kernel-team/ppa': ensure => absent }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe 'doesnt contain the source file' do
it 'fails' do
shell('ls /etc/apt/sources.list.d/canonical-kernel-team-ppa-*', :acceptable_exit_codes => [2])
end
end
end
end
context 'release' do
context 'precise' do
it 'works without failure' do
pp = <<-EOS
include '::apt'
apt::ppa { 'ppa:canonical-kernel-team/ppa':
ensure => present,
release => precise,
}
EOS
shell('rm -rf /etc/apt/sources.list.d/canonical-kernel-team-ppa*', :acceptable_exit_codes => [0,1,2])
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/sources.list.d/canonical-kernel-team-ppa-precise.list') do
it { should be_file }
end
end
end
context 'options' do
context '-y', :unless => default[:platform].match(/10\.04/) do
it 'works without failure' do
pp = <<-EOS
include '::apt'
apt::ppa { 'ppa:canonical-kernel-team/ppa':
ensure => present,
release => precise,
options => '-y',
}
EOS
shell('rm -rf /etc/apt/sources.list.d/canonical-kernel-team-ppa*', :acceptable_exit_codes => [0,1,2])
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/sources.list.d/canonical-kernel-team-ppa-precise.list') do
it { should be_file }
end
end
end
context 'reset' do
it { shell('rm -rf /etc/apt/sources.list.d/canonical-kernel-team-ppa*', :acceptable_exit_codes => [0,1,2]) }
end
end
end

View file

@ -0,0 +1,326 @@
require 'spec_helper_acceptance'
describe 'apt::source', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
context 'apt::source' do
context 'ensure => present' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::source { 'puppetlabs':
ensure => present,
location => 'http://apt.puppetlabs.com',
repos => 'main',
key => '4BD6EC30',
key_server => 'pgp.mit.edu',
}
EOS
shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
shell('rm /etc/apt/sources.list.d/puppetlabs.list', :acceptable_exit_codes => [0,1,2])
apply_manifest(pp, :catch_failures => true)
end
describe 'key should exist' do
it 'finds puppetlabs key' do
shell('apt-key list | grep 4BD6EC30', :acceptable_exit_codes => [0])
end
end
describe file('/etc/apt/sources.list.d/puppetlabs.list') do
it { should be_file }
end
end
context 'ensure => absent' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::source { 'puppetlabs':
ensure => absent,
location => 'http://apt.puppetlabs.com',
repos => 'main',
key => '4BD6EC30',
key_server => 'pgp.mit.edu',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
# The key should remain -we don't delete those when deleting a source.
describe 'key should exist' do
it 'finds puppetlabs key' do
shell('apt-key list | grep 4BD6EC30', :acceptable_exit_codes => [0])
end
end
describe file('/etc/apt/sources.list.d/puppetlabs.list') do
it { should_not be_file }
end
end
end
context 'release' do
context 'test' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::source { 'puppetlabs':
ensure => present,
location => 'http://apt.puppetlabs.com',
repos => 'main',
key => '4BD6EC30',
key_server => 'pgp.mit.edu',
release => 'precise',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/sources.list.d/puppetlabs.list') do
it { should be_file }
it { should contain 'deb http://apt.puppetlabs.com precise main' }
end
end
end
context 'include_src' do
context 'true' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::source { 'puppetlabs':
ensure => present,
location => 'http://apt.puppetlabs.com',
repos => 'main',
key => '4BD6EC30',
key_server => 'pgp.mit.edu',
include_src => true,
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/sources.list.d/puppetlabs.list') do
it { should be_file }
it { should contain 'deb-src http://apt.puppetlabs.com' }
end
end
context 'false' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::source { 'puppetlabs':
ensure => present,
location => 'http://apt.puppetlabs.com',
repos => 'main',
key => '4BD6EC30',
key_server => 'pgp.mit.edu',
include_src => false,
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/sources.list.d/puppetlabs.list') do
it { should be_file }
it { should_not contain 'deb-src http://apt.puppetlabs.com' }
end
end
end
context 'required_packages' do
context 'vim' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::source { 'puppetlabs':
ensure => present,
location => 'http://apt.puppetlabs.com',
repos => 'main',
key => '4BD6EC30',
key_server => 'pgp.mit.edu',
required_packages => 'vim',
}
EOS
shell('apt-get -y remove vim')
apply_manifest(pp, :catch_failures => true)
end
describe package('vim') do
it { should be_installed }
end
end
end
context 'key content' do
context 'giant key' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::source { 'puppetlabs':
ensure => present,
location => 'http://apt.puppetlabs.com',
repos => 'main',
key => '4BD6EC30',
key_content => '-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.12 (GNU/Linux)
Comment: GPGTools - http://gpgtools.org
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
=a34C
-----END PGP PUBLIC KEY BLOCK-----',
}
EOS
shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/sources.list.d/puppetlabs.list') do
it { should be_file }
end
describe 'keys should exist' do
it 'finds puppetlabs key' do
shell('apt-key list | grep 4BD6EC30')
end
end
end
end
context 'key_source' do
context 'http://apt.puppetlabs.com/pubkey.gpg' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::source { 'puppetlabs':
ensure => present,
location => 'http://apt.puppetlabs.com',
release => 'precise',
repos => 'main',
key => '4BD6EC30',
key_source => 'http://apt.puppetlabs.com/pubkey.gpg',
}
EOS
shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/sources.list.d/puppetlabs.list') do
it { should be_file }
it { should contain 'deb http://apt.puppetlabs.com precise main' }
end
describe 'keys should exist' do
it 'finds puppetlabs key' do
shell('apt-key list | grep 4BD6EC30')
end
end
end
end
context 'pin' do
context 'false' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::source { 'puppetlabs':
ensure => present,
location => 'http://apt.puppetlabs.com',
repos => 'main',
key => '4BD6EC30',
key_server => 'pgp.mit.edu',
pin => false,
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/puppetlabs.pref') do
it { should_not be_file }
end
end
context 'true' do
it 'should work with no errors' do
pp = <<-EOS
include '::apt'
apt::source { 'puppetlabs':
ensure => present,
location => 'http://apt.puppetlabs.com',
repos => 'main',
key => '4BD6EC30',
key_server => 'pgp.mit.edu',
pin => true,
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/puppetlabs.pref') do
it { should be_file }
end
end
end
end

View file

@ -0,0 +1,280 @@
require 'spec_helper_acceptance'
describe 'apt class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
context 'reset' do
it 'fixes the sources.list' do
shell('cp /etc/apt/sources.list /tmp')
end
end
context 'always_apt_update => true' do
it 'should work with no errors' do
pp = <<-EOS
class { 'apt': always_apt_update => true }
EOS
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to match(/apt_update/)
end
end
end
context 'always_apt_update => false' do
it 'should work with no errors' do
pp = <<-EOS
class { 'apt': always_apt_update => false }
EOS
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to_not match(/apt_update/)
end
end
end
# disable_keys drops in a 99unauth file to ignore keys in
# other files.
context 'disable_keys => true' do
it 'should work with no errors' do
pp = <<-EOS
class { 'apt': disable_keys => true }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/99unauth') do
it { should be_file }
it { should contain 'APT::Get::AllowUnauthenticated 1;' }
end
end
context 'disable_keys => false' do
it 'should work with no errors' do
pp = <<-EOS
class { 'apt': disable_keys => false }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/99unauth') do
it { should_not be_file }
end
end
# proxy_host sets the proxy to use for transfers.
# proxy_port sets the proxy port to use.
context 'proxy settings' do
it 'should work with no errors' do
pp = <<-EOS
class { 'apt':
proxy_host => 'localhost',
proxy_port => '7042',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/01proxy') do
it { should be_file }
it { should contain 'Acquire::http::Proxy "http://localhost:7042\";' }
end
describe file('/etc/apt/apt.conf.d/proxy') do
it { should_not be_file }
end
end
context 'purge_sources' do
it 'creates a fake apt file' do
shell('touch /etc/apt/sources.list.d/fake.list')
shell('echo "deb fake" >> /etc/apt/sources.list')
end
it 'purge_sources_list and purge_sources_list_d => true' do
pp = <<-EOS
class { 'apt':
purge_sources_list => true,
purge_sources_list_d => true,
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/sources.list') do
it { should_not contain 'deb fake' }
end
describe file('/etc/apt/sources.list.d/fake.list') do
it { should_not be_file }
end
end
context 'proxy settings' do
it 'should work with no errors' do
pp = <<-EOS
class { 'apt':
proxy_host => 'localhost',
proxy_port => '7042',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/01proxy') do
it { should be_file }
it { should contain 'Acquire::http::Proxy "http://localhost:7042\";' }
end
describe file('/etc/apt/apt.conf.d/proxy') do
it { should_not be_file }
end
end
context 'purge_sources' do
context 'false' do
it 'creates a fake apt file' do
shell('touch /etc/apt/sources.list.d/fake.list')
shell('echo "deb fake" >> /etc/apt/sources.list')
end
it 'purge_sources_list and purge_sources_list_d => false' do
pp = <<-EOS
class { 'apt':
purge_sources_list => false,
purge_sources_list_d => false,
}
EOS
apply_manifest(pp, :catch_failures => false)
end
describe file('/etc/apt/sources.list') do
it { should contain 'deb fake' }
end
describe file('/etc/apt/sources.list.d/fake.list') do
it { should be_file }
end
end
context 'true' do
it 'creates a fake apt file' do
shell('touch /etc/apt/sources.list.d/fake.list')
shell('echo "deb fake" >> /etc/apt/sources.list')
end
it 'purge_sources_list and purge_sources_list_d => true' do
pp = <<-EOS
class { 'apt':
purge_sources_list => true,
purge_sources_list_d => true,
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/sources.list') do
it { should_not contain 'deb fake' }
end
describe file('/etc/apt/sources.list.d/fake.list') do
it { should_not be_file }
end
end
end
context 'purge_preferences' do
context 'false' do
it 'creates a preferences file' do
shell("echo 'original' > /etc/apt/preferences")
end
it 'should work with no errors' do
pp = <<-EOS
class { 'apt': purge_preferences => false }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences') do
it { should be_file }
it 'is not managed by Puppet' do
shell("grep 'original' /etc/apt/preferences", {:acceptable_exit_codes => 0})
end
end
end
context 'true' do
it 'creates a preferences file' do
shell('touch /etc/apt/preferences')
end
it 'should work with no errors' do
pp = <<-EOS
class { 'apt': purge_preferences => true }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences') do
it { should_not be_file }
end
end
end
context 'purge_preferences_d' do
context 'false' do
it 'creates a preferences file' do
shell('touch /etc/apt/preferences.d/test')
end
it 'should work with no errors' do
pp = <<-EOS
class { 'apt': purge_preferences_d => false }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/test') do
it { should be_file }
end
end
context 'true' do
it 'creates a preferences file' do
shell('touch /etc/apt/preferences.d/test')
end
it 'should work with no errors' do
pp = <<-EOS
class { 'apt': purge_preferences_d => true }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/test') do
it { should_not be_file }
end
end
end
context 'update_timeout' do
context '5000' do
it 'should work with no errors' do
pp = <<-EOS
class { 'apt': update_timeout => '5000' }
EOS
apply_manifest(pp, :catch_failures => true)
end
end
end
context 'reset' do
it 'fixes the sources.list' do
shell('cp /tmp/sources.list /etc/apt')
end
end
end

View file

@ -0,0 +1,73 @@
require 'spec_helper_acceptance'
codename = fact('lsbdistcodename')
case fact('operatingsystem')
when 'Ubuntu'
repos = 'main universe multiverse restricted'
when 'Debian'
repos = 'main contrib non-free'
end
describe 'apt::backports class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
context 'defaults' do
it 'should work with no errors' do
pp = <<-EOS
class { 'apt::backports': }
EOS
apply_manifest(pp, :catch_failures => true)
end
end
context 'release' do
it 'should work with no errors' do
pp = <<-EOS
class { 'apt::backports': release => '#{codename}' }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/sources.list.d/backports.list') do
it { should be_file }
it { should contain "#{codename}-backports #{repos}" }
end
end
context 'location' do
it 'should work with no errors' do
pp = <<-EOS
class { 'apt::backports': release => 'precise', location => 'http://localhost/ubuntu' }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/sources.list.d/backports.list') do
it { should be_file }
it { should contain "deb http://localhost/ubuntu precise-backports #{repos}" }
end
end
context 'pin_priority' do
it 'should work with no errors' do
pp = <<-EOS
class { 'apt::backports': pin_priority => 500, }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/backports.pref') do
it { should be_file }
it { should contain "Pin-Priority: 500" }
end
end
context 'reset' do
it 'deletes backport files' do
shell('rm -rf /etc/apt/sources.list.d/backports.list')
shell('rm -rf /etc/apt/preferences.d/backports.pref')
end
end
end

View file

@ -0,0 +1,17 @@
require 'spec_helper_acceptance'
describe 'apt class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
context 'default parameters' do
# Using puppet_apply as a helper
it 'should work with no errors' do
pp = <<-EOS
class { 'apt': }
EOS
# Run it twice and test for idempotency
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_failures => true)
end
end
end

View file

@ -0,0 +1,66 @@
require 'spec_helper_acceptance'
describe 'apt::conf define', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
context 'defaults' do
it 'should work with no errors' do
pp = <<-EOS
apt::conf { 'test':
content => 'test',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50test') do
it { should be_file }
it { should contain 'test' }
end
end
context 'ensure' do
context 'absent' do
it 'should work with no errors' do
pp = <<-EOS
apt::conf { 'test':
ensure => absent,
content => 'test',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50test') do
it { should_not be_file }
end
end
end
context 'priority' do
context '99' do
it 'should work with no errors' do
pp = <<-EOS
apt::conf { 'test':
ensure => present,
content => 'test',
priority => '99',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/99test') do
it { should be_file }
it { should contain 'test' }
end
end
end
context 'cleanup' do
it 'deletes 99test' do
shell ('rm -rf /etc/apt/apt.conf.d/99test')
end
end
end

View file

@ -0,0 +1,76 @@
require 'spec_helper_acceptance'
codename = fact('lsbdistcodename')
describe 'apt::force define', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
context 'defaults' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::force { 'vim': }
EOS
shell('apt-get remove -y vim')
apply_manifest(pp, :catch_failures => true)
end
describe package('vim') do
it { should be_installed }
end
end
context 'release' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::force { 'vim': release => '#{codename}' }
EOS
shell('apt-get remove -y vim')
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stdout).to match(/apt-get -y -t #{codename} install vim/)
end
end
describe package('vim') do
it { should be_installed }
end
end
context 'version' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::force { 'vim': version => '1.1.1' }
EOS
shell('apt-get remove -y vim')
apply_manifest(pp, :catch_failures => false) do |r|
expect(r.stdout).to match(/apt-get -y install vim=1.1.1/)
end
end
describe package('vim') do
it { should_not be_installed }
end
end
context 'timeout' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::force { 'ocaml': timeout => '1' }
EOS
shell('apt-get clean')
apply_manifest(pp, :expect_failures => true) do |r|
expect(r.stderr).to match(/Error: Command exceeded timeout/)
end
end
describe package('ocaml') do
it { should_not be_installed }
end
end
end

View file

@ -0,0 +1,10 @@
HOSTS:
debian-70rc1-x64:
roles:
- master
platform: debian-70rc1-x64
box : debian-70rc1-x64-vbox4210-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-70rc1-x64-vbox4210-nocm.box
hypervisor : vagrant
CONFIG:
type: foss

View file

@ -0,0 +1,11 @@
HOSTS:
debian-73-x64:
roles:
- master
platform: debian-7-amd64
box : debian-73-x64-virtualbox-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-nocm.box
hypervisor : vagrant
CONFIG:
log_level: debug
type: git

View file

@ -0,0 +1,11 @@
HOSTS:
ubuntu-server-12042-x64:
roles:
- master
platform: ubuntu-server-12.04-amd64
box : ubuntu-server-12042-x64-vbox4210-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
hypervisor : vagrant
CONFIG:
type: foss
vagrant_ssh_port_random: true

View file

@ -0,0 +1,11 @@
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:
log_level: debug
type: git

View file

@ -0,0 +1,10 @@
HOSTS:
ubuntu-server-12042-x64:
roles:
- master
platform: ubuntu-server-12.04-amd64
box : ubuntu-server-12042-x64-vbox4210-nocm
box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
hypervisor : vagrant
CONFIG:
type: foss

View file

@ -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

View file

@ -0,0 +1,286 @@
require 'spec_helper_acceptance'
describe 'apt::pin define', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
context 'defaults' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::pin { 'vim-puppet': }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/vim-puppet.pref') do
it { should be_file }
it { should contain 'Pin: release a=vim-puppet' }
end
end
context 'ensure' do
context 'present' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::pin { 'vim-puppet': ensure => present }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/vim-puppet.pref') do
it { should be_file }
it { should contain 'Pin: release a=vim-puppet' }
end
end
context 'absent' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::pin { 'vim-puppet': ensure => absent }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/vim-puppet.pref') do
it { should_not be_file }
end
end
end
context 'order' do
context '99' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::pin { 'vim-puppet':
ensure => present,
order => '99',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/99-vim-puppet.pref') do
it { should be_file }
it { should contain 'Pin: release a=vim-puppet' }
end
end
end
context 'packages' do
context 'test' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::pin { 'vim-puppet':
ensure => present,
packages => 'test',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/vim-puppet.pref') do
it { should be_file }
it { should contain 'Package: test' }
it { should contain 'Pin: release a=vim-puppet' }
end
end
context 'array' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::pin { 'array':
ensure => present,
packages => ['apache', 'ntop'],
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/array.pref') do
it { should be_file }
it { should contain 'Package: apache ntop' }
it { should contain 'Pin: release a=array' }
end
end
end
context 'release' do
context 'testrelease' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::pin { 'vim-puppet':
ensure => present,
release => 'testrelease',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/vim-puppet.pref') do
it { should be_file }
it { should contain 'Pin: release a=testrelease' }
end
end
end
context 'origin' do
context 'testrelease' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::pin { 'vim-puppet':
ensure => present,
origin => 'testrelease',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/vim-puppet.pref') do
it { should be_file }
it { should contain 'Pin: origin testrelease' }
end
end
end
context 'version' do
context '1.0.0' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::pin { 'vim-puppet':
ensure => present,
packages => 'test',
version => '1.0.0',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/vim-puppet.pref') do
it { should be_file }
it { should contain 'Package: test' }
it { should contain 'Pin: version 1.0.0' }
end
end
end
context 'codename' do
context 'testname' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::pin { 'vim-puppet':
ensure => present,
codename => 'testname',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/vim-puppet.pref') do
it { should be_file }
it { should contain 'Pin: release n=testname' }
end
end
end
context 'release_version' do
context '1.1.1' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::pin { 'vim-puppet':
ensure => present,
release_version => '1.1.1',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/vim-puppet.pref') do
it { should be_file }
it { should contain 'Pin: release v=1.1.1' }
end
end
end
context 'component' do
context 'testcomponent' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::pin { 'vim-puppet':
ensure => present,
component => 'testcomponent',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/vim-puppet.pref') do
it { should be_file }
it { should contain 'Pin: release c=testcomponent' }
end
end
end
context 'originator' do
context 'testorigin' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::pin { 'vim-puppet':
ensure => present,
originator => 'testorigin',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/vim-puppet.pref') do
it { should be_file }
it { should contain 'Pin: release o=testorigin' }
end
end
end
context 'label' do
context 'testlabel' do
it 'should work with no errors' do
pp = <<-EOS
include apt
apt::pin { 'vim-puppet':
ensure => present,
label => 'testlabel',
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/preferences.d/vim-puppet.pref') do
it { should be_file }
it { should contain 'Pin: release l=testlabel' }
end
end
end
end

View file

@ -0,0 +1,26 @@
require 'spec_helper_acceptance'
describe 'apt::release class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
context 'release_id' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::release': release_id => 'precise', }
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/01release') do
it { should be_file }
it { should contain 'APT::Default-Release "precise";' }
end
end
context 'reset' do
it 'cleans up' do
shell('rm -rf /etc/apt/apt.conf.d/01release')
end
end
end

View file

@ -0,0 +1,562 @@
require 'spec_helper_acceptance'
describe 'apt::unattended_upgrades class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
context 'defaults' do
it 'should work with no errors' do
pp = <<-EOS
include apt
include apt::unattended_upgrades
EOS
# Attempted workaround for problems seen on debian with
# something holding the package database open.
#shell('killall -9 apt-get')
#shell('killall -9 dpkg')
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/10periodic') do
it { should be_file }
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
end
end
context 'origins' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
origins => ['${distro_id}:${distro_codename}-test'],
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain '${distro_id}:${distro_codename}-test' }
end
end
context 'blacklist' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
blacklist => ['puppet']
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain 'puppet' }
end
end
context 'update' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
update => '99'
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/10periodic') do
it { should be_file }
it { should contain 'APT::Periodic::Update-Package-Lists "99";' }
end
end
context 'download' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
download => '99'
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/10periodic') do
it { should be_file }
it { should contain 'APT::Periodic::Download-Upgradeable-Packages "99";' }
end
end
context 'upgrade' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
upgrade => '99'
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/10periodic') do
it { should be_file }
it { should contain 'APT::Periodic::Unattended-Upgrade "99";' }
end
end
context 'autoclean' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
autoclean => '99'
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/10periodic') do
it { should be_file }
it { should contain 'APT::Periodic::AutocleanInterval "99";' }
end
end
context 'auto_fix' do
context 'true' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
auto_fix => true
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain 'Unattended-Upgrade::AutoFixInterruptedDpkg "true";' }
end
end
context 'false' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
auto_fix => false
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain 'Unattended-Upgrade::AutoFixInterruptedDpkg "false";' }
end
end
end
context 'minimal_steps' do
context 'true' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
minimal_steps => true
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain 'Unattended-Upgrade::MinimalSteps "true";' }
end
end
context 'false' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
minimal_steps => false
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain 'Unattended-Upgrade::MinimalSteps "false";' }
end
end
end
context 'install_on_shutdown' do
context 'true' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
install_on_shutdown => true
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain 'Unattended-Upgrade::InstallOnShutdown "true";' }
end
end
context 'false' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
install_on_shutdown => false
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain 'Unattended-Upgrade::InstallOnShutdown "false";' }
end
end
end
context 'mail_to' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
mail_to => 'test@example.com'
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain 'Unattended-Upgrade::Mail "test@example.com";' }
end
end
context 'mail_only_on_error' do
context 'true' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
mail_to => 'test@example.com',
mail_only_on_error => true
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain 'Unattended-Upgrade::MailOnlyOnError "true";' }
end
end
context 'false' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
mail_to => 'test@example.com',
mail_only_on_error => false,
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain 'Unattended-Upgrade::MailOnlyOnError "false";' }
end
end
context 'mail_to missing' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
mail_only_on_error => true,
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should_not contain 'Unattended-Upgrade::MailOnlyOnError "true";' }
end
end
end
context 'remove_unused' do
context 'true' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
remove_unused => true
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain 'Unattended-Upgrade::Remove-Unused-Dependencies "true";' }
end
end
context 'false' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
remove_unused => false,
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain 'Unattended-Upgrade::Remove-Unused-Dependencies "false";' }
end
end
end
context 'auto_reboot' do
context 'true' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
auto_reboot => true
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain 'Unattended-Upgrade::Automatic-Reboot "true";' }
end
end
context 'false' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
auto_reboot => false,
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain 'Unattended-Upgrade::Automatic-Reboot "false";' }
end
end
end
context 'dl_limit' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
dl_limit => '99'
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
it { should be_file }
it { should contain 'Acquire::http::Dl-Limit "99"' }
end
end
context 'enable' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
enable => '2'
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/10periodic') do
it { should be_file }
it { should contain 'APT::Periodic::Enable "2"' }
end
end
context 'backup_interval' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
backup_interval => '2'
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/10periodic') do
it { should be_file }
it { should contain 'APT::Periodic::BackUpArchiveInterval "2";' }
end
end
context 'backup_level' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
backup_level => '2'
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/10periodic') do
it { should be_file }
it { should contain 'APT::Periodic::BackUpLevel "2";' }
end
end
context 'max_age' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
max_age => '2'
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/10periodic') do
it { should be_file }
it { should contain 'APT::Periodic::MaxAge "2";' }
end
end
context 'min_age' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
min_age => '2'
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/10periodic') do
it { should be_file }
it { should contain 'APT::Periodic::MinAge "2";' }
end
end
context 'max_size' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
max_size => '2'
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/10periodic') do
it { should be_file }
it { should contain 'APT::Periodic::MaxSize "2";' }
end
end
context 'download_delta' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
download_delta => '2'
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/10periodic') do
it { should be_file }
it { should contain 'APT::Periodic::Download-Upgradeable-Packages-Debdelta "2";' }
end
end
context 'verbose' do
it 'should work with no errors' do
pp = <<-EOS
include apt
class { 'apt::unattended_upgrades':
verbose => '2'
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe file('/etc/apt/apt.conf.d/10periodic') do
it { should be_file }
it { should contain 'APT::Periodic::Verbose "2";' }
end
end
end

View file

@ -0,0 +1,10 @@
require 'spec_helper_acceptance'
describe 'unsupported distributions and OSes', :if => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
it 'class apt fails' do
pp = <<-EOS
class { 'apt': }
EOS
expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/This module only works on Debian or derivatives like Ubuntu/i)
end
end

View file

@ -0,0 +1,170 @@
require 'spec_helper'
describe 'apt', :type => :class do
let(:facts) { { :lsbdistid => 'Debian', :osfamily => 'Debian' } }
let :default_params do
{
:disable_keys => :undef,
:always_apt_update => false,
:purge_sources_list => false,
:purge_sources_list_d => false,
}
end
[{},
{
:disable_keys => true,
:always_apt_update => true,
:proxy_host => true,
:proxy_port => '3128',
:purge_sources_list => true,
:purge_sources_list_d => true,
},
{
:purge_preferences => true,
:purge_preferences_d => true,
},
{
:disable_keys => false
}
].each do |param_set|
describe "when #{param_set == {} ? "using default" : "specifying"} class parameters" do
let :param_hash do
default_params.merge(param_set)
end
let :params do
param_set
end
let :refresh_only_apt_update do
if param_hash[:always_apt_update]
false
else
true
end
end
it { should contain_class("apt::params") }
it {
if param_hash[:purge_sources_list]
should contain_file("sources.list").with({
'path' => "/etc/apt/sources.list",
'ensure' => "present",
'owner' => "root",
'group' => "root",
'mode' => "0644",
"content" => "# Repos managed by puppet.\n"
})
else
should contain_file("sources.list").with({
'path' => "/etc/apt/sources.list",
'ensure' => "present",
'owner' => "root",
'group' => "root",
'mode' => "0644",
'content' => nil
})
end
}
it {
if param_hash[:purge_sources_list_d]
should create_file("sources.list.d").with({
'path' => "/etc/apt/sources.list.d",
'ensure' => "directory",
'owner' => "root",
'group' => "root",
'purge' => true,
'recurse' => true,
'notify' => 'Exec[apt_update]'
})
else
should create_file("sources.list.d").with({
'path' => "/etc/apt/sources.list.d",
'ensure' => "directory",
'owner' => "root",
'group' => "root",
'purge' => false,
'recurse' => false,
'notify' => 'Exec[apt_update]'
})
end
}
it {
if param_hash[:purge_preferences]
should create_file('apt-preferences').with({
:ensure => 'absent',
:path => '/etc/apt/preferences',
})
else
should_not contain_file('apt-preferences')
end
}
it {
if param_hash[:purge_preferences_d]
should create_file("preferences.d").with({
'path' => "/etc/apt/preferences.d",
'ensure' => "directory",
'owner' => "root",
'group' => "root",
'purge' => true,
'recurse' => true,
})
else
should create_file("preferences.d").with({
'path' => "/etc/apt/preferences.d",
'ensure' => "directory",
'owner' => "root",
'group' => "root",
'purge' => false,
'recurse' => false,
})
end
}
it {
should contain_exec("apt_update").with({
'command' => "/usr/bin/apt-get update",
'refreshonly' => refresh_only_apt_update
})
}
it {
if param_hash[:disable_keys] == true
should create_file("99unauth").with({
'content' => "APT::Get::AllowUnauthenticated 1;\n",
'ensure' => "present",
'path' => "/etc/apt/apt.conf.d/99unauth"
})
elsif param_hash[:disable_keys] == false
should create_file("99unauth").with({
'ensure' => "absent",
'path' => "/etc/apt/apt.conf.d/99unauth"
})
elsif param_hash[:disable_keys] != :undef
should_not create_file("99unauth").with({
'path' => "/etc/apt/apt.conf.d/99unauth"
})
end
}
describe 'when setting a proxy' do
it {
if param_hash[:proxy_host]
should contain_file('01proxy').with(
'path' => '/etc/apt/apt.conf.d/01proxy',
'content' => "Acquire::http::Proxy \"http://#{param_hash[:proxy_host]}:#{param_hash[:proxy_port]}\";\n",
'notify' => "Exec[apt_update]"
)
else
should contain_file('01proxy').with(
'path' => '/etc/apt/apt.conf.d/01proxy',
'notify' => 'Exec[apt_update]',
'ensure' => 'absent'
)
end
}
end
end
end
end

View file

@ -0,0 +1,101 @@
require 'spec_helper'
describe 'apt::backports', :type => :class do
describe 'when asigning a custom priority to backports' do
let :facts do
{
'lsbdistcodename' => 'Karmic',
'lsbdistid' => 'Ubuntu'
}
end
context 'integer priority' do
let :params do { :pin_priority => 500 } end
it { should contain_apt__source('backports').with({
'location' => 'http://old-releases.ubuntu.com/ubuntu',
'release' => 'karmic-backports',
'repos' => 'main universe multiverse restricted',
'key' => '437D05B5',
'key_server' => 'pgp.mit.edu',
'pin' => 500,
})
}
end
context 'invalid priority' do
let :params do { :pin_priority => 'banana' } end
it 'should fail' do
expect { subject }.to raise_error(/must be an integer/)
end
end
end
describe 'when turning on backports for ubuntu karmic' do
let :facts do
{
'lsbdistcodename' => 'Karmic',
'lsbdistid' => 'Ubuntu'
}
end
it { should contain_apt__source('backports').with({
'location' => 'http://old-releases.ubuntu.com/ubuntu',
'release' => 'karmic-backports',
'repos' => 'main universe multiverse restricted',
'key' => '437D05B5',
'key_server' => 'pgp.mit.edu',
'pin' => 200,
})
}
end
describe "when turning on backports for debian squeeze" do
let :facts do
{
'lsbdistcodename' => 'Squeeze',
'lsbdistid' => 'Debian',
}
end
it { should contain_apt__source('backports').with({
'location' => 'http://backports.debian.org/debian-backports',
'release' => 'squeeze-backports',
'repos' => 'main contrib non-free',
'key' => '46925553',
'key_server' => 'pgp.mit.edu',
'pin' => 200,
})
}
end
describe "when turning on backports for debian squeeze but using your own mirror" do
let :facts do
{
'lsbdistcodename' => 'Squeeze',
'lsbdistid' => 'Debian'
}
end
let :location do
'http://mirrors.example.com/debian-backports'
end
let :params do
{ 'location' => location }
end
it { should contain_apt__source('backports').with({
'location' => location,
'release' => 'squeeze-backports',
'repos' => 'main contrib non-free',
'key' => '46925553',
'key_server' => 'pgp.mit.edu',
'pin' => 200,
})
}
end
end

View file

@ -0,0 +1,15 @@
require 'spec_helper'
describe 'apt::debian::testing', :type => :class do
let(:facts) { { :lsbdistid => 'Debian', :osfamily => 'Debian' } }
it {
should contain_apt__source("debian_testing").with({
"location" => "http://debian.mirror.iweb.ca/debian/",
"release" => "testing",
"repos" => "main contrib non-free",
"required_packages" => "debian-keyring debian-archive-keyring",
"key" => "46925553",
"key_server" => "subkeys.pgp.net",
"pin" => "-10"
})
}
end

View file

@ -0,0 +1,15 @@
require 'spec_helper'
describe 'apt::debian::unstable', :type => :class do
let(:facts) { { :lsbdistid => 'Debian', :osfamily => 'Debian' } }
it {
should contain_apt__source("debian_unstable").with({
"location" => "http://debian.mirror.iweb.ca/debian/",
"release" => "unstable",
"repos" => "main contrib non-free",
"required_packages" => "debian-keyring debian-archive-keyring",
"key" => "46925553",
"key_server" => "subkeys.pgp.net",
"pin" => "-10"
})
}
end

View file

@ -0,0 +1,57 @@
require 'spec_helper'
describe 'apt' do
context 'with sources defined on valid osfamily' do
let :facts do
{ :osfamily => 'Debian',
:lsbdistcodename => 'precise',
:lsbdistid => 'Debian',
}
end
let(:params) { { :sources => {
'debian_unstable' => {
'location' => 'http://debian.mirror.iweb.ca/debian/',
'release' => 'unstable',
'repos' => 'main contrib non-free',
'required_packages' => 'debian-keyring debian-archive-keyring',
'key' => '55BE302B',
'key_server' => 'subkeys.pgp.net',
'pin' => '-10',
'include_src' => true
},
'puppetlabs' => {
'location' => 'http://apt.puppetlabs.com',
'repos' => 'main',
'key' => '4BD6EC30',
'key_server' => 'pgp.mit.edu',
}
} } }
it {
should contain_file('debian_unstable.list').with({
'ensure' => 'present',
'path' => '/etc/apt/sources.list.d/debian_unstable.list',
'owner' => 'root',
'group' => 'root',
'mode' => '0644',
'notify' => 'Exec[apt_update]',
})
}
it { should contain_file('debian_unstable.list').with_content(/^deb http:\/\/debian.mirror.iweb.ca\/debian\/ unstable main contrib non-free$/) }
it { should contain_file('debian_unstable.list').with_content(/^deb-src http:\/\/debian.mirror.iweb.ca\/debian\/ unstable main contrib non-free$/) }
it {
should contain_file('puppetlabs.list').with({
'ensure' => 'present',
'path' => '/etc/apt/sources.list.d/puppetlabs.list',
'owner' => 'root',
'group' => 'root',
'mode' => '0644',
'notify' => 'Exec[apt_update]',
})
}
it { should contain_file('puppetlabs.list').with_content(/^deb http:\/\/apt.puppetlabs.com precise main$/) }
it { should contain_file('puppetlabs.list').with_content(/^deb-src http:\/\/apt.puppetlabs.com precise main$/) }
end
end

View file

@ -0,0 +1,27 @@
require 'spec_helper'
describe 'apt::params', :type => :class do
let(:facts) { { :lsbdistid => 'Debian', :osfamily => 'Debian' } }
let (:title) { 'my_package' }
it { should contain_apt__params }
# There are 4 resources in this class currently
# there should not be any more resources because it is a params class
# The resources are class[apt::params], class[main], class[settings], stage[main]
it "Should not contain any resources" do
subject.resources.size.should == 4
end
describe "With unknown lsbdistid" do
let(:facts) { { :lsbdistid => 'CentOS' } }
let (:title) { 'my_package' }
it do
expect {
should compile
}.to raise_error(Puppet::Error, /Unsupported lsbdistid/)
end
end
end

View file

@ -0,0 +1,23 @@
require 'spec_helper'
describe 'apt::release', :type => :class do
let(:facts) { { :lsbdistid => 'Debian' } }
let (:title) { 'my_package' }
let :param_set do
{ :release_id => 'precise' }
end
let (:params) { param_set }
it { should contain_class("apt::params") }
it {
should contain_file("/etc/apt/apt.conf.d/01release").with({
"mode" => "0644",
"owner" => "root",
"group" => "root",
"content" => "APT::Default-Release \"#{param_set[:release_id]}\";"
})
}
end

View file

@ -0,0 +1,291 @@
require 'spec_helper'
describe 'apt::unattended_upgrades', :type => :class do
let(:file_unattended) { '/etc/apt/apt.conf.d/50unattended-upgrades' }
let(:file_periodic) { '/etc/apt/apt.conf.d/10periodic' }
let(:facts) { { :lsbdistid => 'Debian' } }
it { should contain_package("unattended-upgrades") }
it {
should create_file("/etc/apt/apt.conf.d/50unattended-upgrades").with({
"owner" => "root",
"group" => "root",
"mode" => "0644",
"require" => "Package[unattended-upgrades]",
})
}
it {
should create_file("/etc/apt/apt.conf.d/10periodic").with({
"owner" => "root",
"group" => "root",
"mode" => "0644",
"require" => "Package[unattended-upgrades]",
})
}
describe "origins" do
describe 'on Debian' do
default_facts = { :lsbdistid => 'Debian' }
context 'defaults' do
let :facts do default_facts end
it {
should contain_file(file_unattended).with_content(
/^Unattended-Upgrade::Origins-Pattern/
).with_content(
/"origin=Debian,archive=stable,label=Debian-Security";/
)
}
end
context 'defaults with custom origin' do
let :facts do default_facts end
let :params do { :origins => ['bananana']} end
it {
should contain_file(file_unattended).with_content(
/^Unattended-Upgrade::Origins-Pattern/
).with_content(
/"bananana";/
)
}
end
context 'defaults with invalid origin' do
let :facts do default_facts end
let :params do { :origins => 'bananana'} end
it {
expect {subject}.to raise_error(/is not an Array/)
}
end
context 'squeeze' do
let :facts do default_facts.merge({:lsbdistcodename => 'squeeze'}) end
it {
should contain_file(file_unattended).with_content(
/^Unattended-Upgrade::Allowed-Origins/
).with_content(
/"\${distro_id} \${distro_codename}-security";/
).with_content(
/"\${distro_id} oldstable";/
)
}
end
context 'wheezy' do
let :facts do default_facts.merge({:lsbdistcodename => 'wheezy'}) end
it {
should contain_file(file_unattended).with_content(
/^Unattended-Upgrade::Origins-Pattern/
).with_content(
/"origin=Debian,archive=stable,label=Debian-Security";/
)
}
end
end
describe 'on Ubuntu' do
default_facts = { :lsbdistid => 'Ubuntu' }
context 'default' do
let :facts do default_facts end
it {
should contain_file(file_unattended).with_content(
/^Unattended-Upgrade::Allowed-Origins/
).with_content(
/"\${distro_id}\:\${distro_codename}-security";/
)
}
end
context 'lucid' do
let :facts do default_facts.merge({:lsbdistcodename => 'lucid'}) end
it {
should contain_file(file_unattended).with_content(
/^Unattended-Upgrade::Allowed-Origins/
).with_content(
/"\${distro_id} \${distro_codename}-security";/
)
}
end
context 'precise' do
let :facts do default_facts.merge({:lsbdistcodename => 'precise'}) end
it {
should contain_file(file_unattended).with_content(
/^Unattended-Upgrade::Allowed-Origins/
).with_content(
/"\${distro_id}\:\${distro_codename}-security";/
)
}
end
context 'trusty' do
let :facts do default_facts.merge({:lsbdistcodename => 'trusty'}) end
it {
should contain_file(file_unattended).with_content(
/^Unattended-Upgrade::Allowed-Origins/
).with_content(
/"\${distro_id}\:\${distro_codename}-security";/
)
}
end
end
end
describe "blacklist" do
describe "with param defaults" do
let(:params) {{ }}
it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Package-Blacklist \{\n\};$/) }
end
describe "with blacklist => []" do
let :params do
{ :blacklist => ['libc6', 'libc6-dev'] }
end
it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Package-Blacklist \{\n\t"libc6";\n\t"libc6-dev";\n\};$/) }
end
end
describe "with update => 2" do
let :params do
{ :update => "2" }
end
it { should contain_file(file_periodic).with_content(/^APT::Periodic::Update-Package-Lists "2";$/) }
end
describe "with download => 2" do
let :params do
{ :download => "2" }
end
it { should contain_file(file_periodic).with_content(/^APT::Periodic::Download-Upgradeable-Packages "2";$/) }
end
describe "with upgrade => 2" do
let :params do
{ :upgrade => "2" }
end
it { should contain_file(file_periodic).with_content(/^APT::Periodic::Unattended-Upgrade "2";$/) }
end
describe "with autoclean => 2" do
let :params do
{ :autoclean => "2" }
end
it { should contain_file(file_periodic).with_content(/^APT::Periodic::AutocleanInterval "2";$/) }
end
describe "with auto_fix => false" do
let :params do
{ :auto_fix => false }
end
it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::AutoFixInterruptedDpkg "false";$/) }
end
describe "with minimal_steps => true" do
let :params do
{ :minimal_steps => true }
end
it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::MinimalSteps "true";$/) }
end
describe "with install_on_shutdown => true" do
let :params do
{ :install_on_shutdown => true }
end
it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::InstallOnShutdown "true";$/) }
end
describe "mail_to" do
describe "param defaults" do
let(:params) {{ }}
it { should_not contain_file(file_unattended).with_content(/^Unattended-Upgrade::Mail /) }
it { should_not contain_file(file_unattended).with_content(/^Unattended-Upgrade::MailOnlyOnError /) }
end
describe "with mail_to => user@website, mail_only_on_error => true" do
let :params do
{ :mail_to => "user@website",
:mail_only_on_error => true }
end
it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Mail "user@website";$/) }
it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::MailOnlyOnError "true";$/) }
end
end
describe "with remove_unused => false" do
let :params do
{ :remove_unused => false }
end
it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Remove-Unused-Dependencies "false";$/) }
end
describe "with auto_reboot => true" do
let :params do
{ :auto_reboot => true }
end
it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Automatic-Reboot "true";$/) }
end
describe "dl_limit" do
describe "param defaults" do
let(:params) {{ }}
it { should_not contain_file(file_unattended).with_content(/^Acquire::http::Dl-Limit /) }
end
describe "with dl_limit => 70" do
let :params do
{ :dl_limit => "70" }
end
it { should contain_file(file_unattended).with_content(/^Acquire::http::Dl-Limit "70";$/) }
end
end
describe "with enable => 0" do
let :params do
{ :enable => "0" }
end
it { should contain_file(file_periodic).with_content(/^APT::Periodic::Enable "0";$/) }
end
describe "with backup_interval => 1" do
let :params do
{ :backup_interval => "1" }
end
it { should contain_file(file_periodic).with_content(/^APT::Periodic::BackUpArchiveInterval "1";$/) }
end
describe "with backup_level => 0" do
let :params do
{ :backup_level => "0" }
end
it { should contain_file(file_periodic).with_content(/^APT::Periodic::BackUpLevel "0";$/) }
end
describe "with max_age => 1" do
let :params do
{ :max_age => "1" }
end
it { should contain_file(file_periodic).with_content(/^APT::Periodic::MaxAge "1";$/) }
end
describe "with min_age => 1" do
let :params do
{ :min_age => "1" }
end
it { should contain_file(file_periodic).with_content(/^APT::Periodic::MinAge "1";$/) }
end
describe "with max_size => 1" do
let :params do
{ :max_size => "1" }
end
it { should contain_file(file_periodic).with_content(/^APT::Periodic::MaxSize "1";$/) }
end
describe "with download_delta => 2" do
let :params do
{ :download_delta => "2" }
end
it { should contain_file(file_periodic).with_content(/^APT::Periodic::Download-Upgradeable-Packages-Debdelta "2";$/) }
end
describe "with verbose => 2" do
let :params do
{ :verbose => "2" }
end
it { should contain_file(file_periodic).with_content(/^APT::Periodic::Verbose "2";$/) }
end
end

View file

@ -0,0 +1,19 @@
require 'spec_helper'
describe 'apt::builddep', :type => :define do
let(:facts) { { :lsbdistid => 'Debian' } }
let(:title) { 'my_package' }
describe "should require apt-get update" do
it { should contain_exec("apt_update").with({
'command' => "/usr/bin/apt-get update",
'refreshonly' => true
})
}
it { should contain_anchor("apt::builddep::my_package").with({
'require' => 'Class[Apt::Update]',
})
}
end
end

View file

@ -0,0 +1,58 @@
require 'spec_helper'
describe 'apt::conf', :type => :define do
let(:facts) { { :lsbdistid => 'Debian' } }
let :title do
'norecommends'
end
describe "when creating an apt preference" do
let :params do
{
:priority => '00',
:content => "Apt::Install-Recommends 0;\nApt::AutoRemove::InstallRecommends 1;\n"
}
end
let :filename do
"/etc/apt/apt.conf.d/00norecommends"
end
it { should contain_apt__conf('norecommends').with({
'priority' => '00',
'content' => "Apt::Install-Recommends 0;\nApt::AutoRemove::InstallRecommends 1;\n"
})
}
it { should contain_file(filename).with({
'ensure' => 'present',
'content' => "Apt::Install-Recommends 0;\nApt::AutoRemove::InstallRecommends 1;\n",
'owner' => 'root',
'group' => 'root',
'mode' => '0644',
})
}
end
describe "when removing an apt preference" do
let :params do
{
:ensure => 'absent',
:priority => '00',
:content => "Apt::Install-Recommends 0;\nApt::AutoRemove::InstallRecommends 1;\n"
}
end
let :filename do
"/etc/apt/apt.conf.d/00norecommends"
end
it { should contain_file(filename).with({
'ensure' => 'absent',
'content' => "Apt::Install-Recommends 0;\nApt::AutoRemove::InstallRecommends 1;\n",
'owner' => 'root',
'group' => 'root',
'mode' => '0644',
})
}
end
end

View file

@ -0,0 +1,58 @@
require 'spec_helper'
describe 'apt::force', :type => :define do
let(:facts) { { :lsbdistid => 'Debian' } }
let :pre_condition do
'include apt::params'
end
let :title do
'my_package'
end
let :default_params do
{
:release => false,
:version => false
}
end
describe "when using default parameters" do
let :params do
default_params
end
it { should contain_exec("/usr/bin/apt-get -y install #{title}").with(
:unless => "/usr/bin/dpkg -s #{title} | grep -q 'Status: install'",
:timeout => '300'
) }
end
describe "when specifying release parameter" do
let :params do
default_params.merge(:release => 'testing')
end
it { should contain_exec("/usr/bin/apt-get -y -t #{params[:release]} install #{title}").with(
:unless => "/usr/bin/test \$(/usr/bin/apt-cache policy -t #{params[:release]} #{title} | /bin/grep -E 'Installed|Candidate' | /usr/bin/uniq -s 14 | /usr/bin/wc -l) -eq 1"
) }
end
describe "when specifying version parameter" do
let :params do
default_params.merge(:version => '1')
end
it { should contain_exec("/usr/bin/apt-get -y install #{title}=#{params[:version]}").with(
:unless => "/usr/bin/dpkg -s #{title} | grep -q 'Version: #{params[:version]}'"
) }
end
describe "when specifying release and version parameters" do
let :params do
default_params.merge(
:release => 'testing',
:version => '1'
)
end
it { should contain_exec("/usr/bin/apt-get -y -t #{params[:release]} install #{title}=1").with(
:unless => "/usr/bin/apt-cache policy -t #{params[:release]} #{title} | /bin/grep -q 'Installed: #{params[:version]}'"
) }
end
end

View file

@ -0,0 +1,100 @@
require 'spec_helper'
describe 'apt::hold' do
let :facts do {
:osfamily => 'Debian',
:lsbdistid => 'Debian',
:lsbrelease => 'wheezy',
} end
let :title do
'vim'
end
let :default_params do {
:version => '1.1.1',
} end
describe 'default params' do
let :params do default_params end
it 'creates an apt preferences file' do
should contain_apt__hold(title).with({
:ensure => 'present',
:package => title,
:version => params[:version],
:priority => 1001,
})
should contain_apt__pin("hold #{title} at #{params[:version]}").with({
:ensure => 'present',
:packages => title,
:version => params[:version],
:priority => 1001,
})
end
end
describe 'ensure => absent' do
let :params do default_params.merge({:ensure => 'absent',}) end
it 'creates an apt preferences file' do
should contain_apt__hold(title).with({
:ensure => params[:ensure],
})
should contain_apt__pin("hold #{title} at #{params[:version]}").with({
:ensure => params[:ensure],
})
end
end
describe 'priority => 990' do
let :params do default_params.merge({:priority => 990,}) end
it 'creates an apt preferences file' do
should contain_apt__hold(title).with({
:ensure => 'present',
:package => title,
:version => params[:version],
:priority => params[:priority],
})
should contain_apt__pin("hold #{title} at #{params[:version]}").with({
:ensure => 'present',
:packages => title,
:version => params[:version],
:priority => params[:priority],
})
end
end
describe 'validation' do
context 'version => {}' do
let :params do { :version => {}, } end
it 'should fail' do
expect { subject }.to raise_error(/is not a string/)
end
end
context 'ensure => bananana' do
let :params do default_params.merge({:ensure => 'bananana',}) end
it 'should fail' do
expect { subject }.to raise_error(/does not match/)
end
end
context 'package => []' do
let :params do default_params.merge({:package => [],}) end
it 'should fail' do
expect { subject }.to raise_error(/is not a string/)
end
end
context 'priority => bananana' do
let :params do default_params.merge({:priority => 'bananana',}) end
it 'should fail' do
expect { subject }.to raise_error(/must be an integer/)
end
end
end
end

View file

@ -0,0 +1,285 @@
require 'spec_helper'
describe 'apt::key', :type => :define do
let(:facts) { { :lsbdistid => 'Debian' } }
GPG_KEY_ID = '4BD6EC30'
let :title do
GPG_KEY_ID
end
describe 'normal operation' do
describe 'default options' do
it 'contains the apt::key' do
should contain_apt__key(title).with({
:key => title,
:ensure => 'present',
})
end
it 'contains the apt_key' do
should contain_apt_key(title).with({
:id => title,
:ensure => 'present',
:source => nil,
:server => nil,
:content => nil,
:keyserver_options => nil,
})
end
it 'contains the apt_key present anchor' do
should contain_anchor("apt_key #{title} present")
end
end
describe 'title and key =>' do
let :title do
'puppetlabs'
end
let :params do {
:key => GPG_KEY_ID,
} end
it 'contains the apt::key' do
should contain_apt__key(title).with({
:key => GPG_KEY_ID,
:ensure => 'present',
})
end
it 'contains the apt_key' do
should contain_apt_key(title).with({
:id => GPG_KEY_ID,
:ensure => 'present',
:source => nil,
:server => nil,
:content => nil,
:keyserver_options => nil,
})
end
it 'contains the apt_key present anchor' do
should contain_anchor("apt_key #{GPG_KEY_ID} present")
end
end
describe 'ensure => absent' do
let :params do {
:ensure => 'absent',
} end
it 'contains the apt::key' do
should contain_apt__key(title).with({
:key => title,
:ensure => 'absent',
})
end
it 'contains the apt_key' do
should contain_apt_key(title).with({
:id => title,
:ensure => 'absent',
:source => nil,
:server => nil,
:content => nil,
:keyserver_options => nil,
})
end
it 'contains the apt_key absent anchor' do
should contain_anchor("apt_key #{title} absent")
end
end
describe 'key_content =>' do
let :params do {
:key_content => 'GPG key content',
} end
it 'contains the apt::key' do
should contain_apt__key(title).with({
:key => title,
:ensure => 'present',
:key_content => params[:key_content],
})
end
it 'contains the apt_key' do
should contain_apt_key(title).with({
:id => title,
:ensure => 'present',
:source => nil,
:server => nil,
:content => params[:key_content],
:keyserver_options => nil,
})
end
it 'contains the apt_key present anchor' do
should contain_anchor("apt_key #{title} present")
end
end
describe 'key_source =>' do
let :params do {
:key_source => 'http://apt.puppetlabs.com/pubkey.gpg',
} end
it 'contains the apt::key' do
should contain_apt__key(title).with({
:key => title,
:ensure => 'present',
:key_source => params[:key_source],
})
end
it 'contains the apt_key' do
should contain_apt_key(title).with({
:id => title,
:ensure => 'present',
:source => params[:key_source],
:server => nil,
:content => nil,
:keyserver_options => nil,
})
end
it 'contains the apt_key present anchor' do
should contain_anchor("apt_key #{title} present")
end
end
describe 'key_server =>' do
let :params do {
:key_server => 'pgp.mit.edu',
} end
it 'contains the apt::key' do
should contain_apt__key(title).with({
:key => title,
:ensure => 'present',
:key_server => 'pgp.mit.edu',
})
end
it 'contains the apt_key' do
should contain_apt_key(title).with({
:id => title,
:ensure => 'present',
:source => nil,
:server => params[:key_server],
:content => nil,
:keyserver_options => nil,
})
end
it 'contains the apt_key present anchor' do
should contain_anchor("apt_key #{title} present")
end
end
describe 'key_options =>' do
let :params do {
:key_options => 'debug',
} end
it 'contains the apt::key' do
should contain_apt__key(title).with({
:key => title,
:ensure => 'present',
:key_options => 'debug',
})
end
it 'contains the apt_key' do
should contain_apt_key(title).with({
:id => title,
:ensure => 'present',
:source => nil,
:server => nil,
:content => nil,
:keyserver_options => params[:key_options],
})
end
it 'contains the apt_key present anchor' do
should contain_anchor("apt_key #{title} present")
end
end
end
describe 'validation' do
context 'invalid key' do
let :title do
'Out of rum. Why? Why are we out of rum?'
end
it 'fails' do
expect { subject }.to raise_error(/does not match/)
end
end
context 'invalid source' do
let :params do {
:key_source => 'afp://puppetlabs.com/key.gpg',
} end
it 'fails' do
expect { subject }.to raise_error(/does not match/)
end
end
context 'invalid content' do
let :params do {
:key_content => [],
} end
it 'fails' do
expect { subject }.to raise_error(/is not a string/)
end
end
context 'invalid server' do
let :params do {
:key_server => 'two bottles of rum',
} end
it 'fails' do
expect { subject }.to raise_error(/must be a valid domain name/)
end
end
context 'invalid keyserver_options' do
let :params do {
:key_options => {},
} end
it 'fails' do
expect { subject }.to raise_error(/is not a string/)
end
end
end
describe 'duplication' do
context 'two apt::key resources for same key, different titles' do
let :pre_condition do
"apt::key { 'duplicate': key => #{title}, }"
end
it 'contains two apt::key resources' do
should contain_apt__key('duplicate').with({
:key => title,
:ensure => 'present',
})
should contain_apt__key(title).with({
:key => title,
:ensure => 'present',
})
end
it 'contains only a single apt_key' do
should contain_apt_key('duplicate').with({
:id => title,
:ensure => 'present',
:source => nil,
:server => nil,
:content => nil,
:keyserver_options => nil,
})
should_not contain_apt_key(title)
end
end
context 'two apt::key resources, different ensure' do
let :pre_condition do
"apt::key { 'duplicate': key => #{title}, ensure => 'absent', }"
end
it 'informs the user of the impossibility' do
expect { subject }.to raise_error(/already ensured as absent/)
end
end
end
end

View file

@ -0,0 +1,120 @@
require 'spec_helper'
describe 'apt::pin', :type => :define do
let(:facts) { { :lsbdistid => 'Debian' } }
let(:title) { 'my_pin' }
let :default_params do
{
:ensure => 'present',
:order => '',
:packages => '*',
:priority => '0',
:release => nil
}
end
[
{ :params => {},
:content => "Explanation: : my_pin\nPackage: *\nPin: release a=my_pin\nPin-Priority: 0\n"
},
{
:params => {
:packages => 'apache',
:priority => '1'
},
:content => "Explanation: : my_pin\nPackage: apache\nPin: release a=my_pin\nPin-Priority: 1\n"
},
{
:params => {
:order => 50,
:packages => 'apache',
:priority => '1'
},
:content => "Explanation: : my_pin\nPackage: apache\nPin: release a=my_pin\nPin-Priority: 1\n"
},
{
:params => {
:ensure => 'absent',
:packages => 'apache',
:priority => '1'
},
:content => "Explanation: : my_pin\nPackage: apache\nPin: release a=my_pin\nPin-Priority: 1\n"
},
{
:params => {
:packages => 'apache',
:priority => '1',
:release => 'my_newpin'
},
:content => "Explanation: : my_pin\nPackage: apache\nPin: release a=my_newpin\nPin-Priority: 1\n"
},
{
:params => {
:packages => 'apache',
:priority => '1',
:version => '2.2.16*'
},
:content => "Explanation: : my_pin\nPackage: apache\nPin: version 2.2.16*\nPin-Priority: 1\n"
},
{
:params => {
:priority => '1',
:origin => 'ftp.de.debian.org'
},
:content => "Explanation: : my_pin\nPackage: *\nPin: origin ftp.de.debian.org\nPin-Priority: 1\n"
},
{
:params => {
:packages => 'apache',
:priority => '1',
:release => 'stable',
:codename => 'wheezy',
:release_version => '3.0',
:component => 'main',
:originator => 'Debian',
:label => 'Debian'
},
:content => "Explanation: : my_pin\nPackage: apache\nPin: release a=stable, n=wheezy, v=3.0, c=main, o=Debian, l=Debian\nPin-Priority: 1\n"
},
{
:params => {
:packages => ['apache', 'ntop'],
},
:content => "Explanation: : my_pin\nPackage: apache ntop\nPin: release a=my_pin\nPin-Priority: 0\n"
},
].each do |param_set|
describe "when #{param_set == {} ? "using default" : "specifying"} define parameters" do
let :param_hash do
default_params.merge(param_set[:params])
end
let :params do
param_set[:params]
end
it { should contain_class("apt::params") }
it { should contain_file("#{title}.pref").with({
'ensure' => param_hash[:ensure],
'path' => "/etc/apt/preferences.d/#{param_hash[:order] == '' ? "" : "#{param_hash[:order]}-"}#{title}.pref",
'owner' => 'root',
'group' => 'root',
'mode' => '0644',
'content' => param_set[:content],
})
}
end
end
describe 'resource title with invalid chars' do
context 'spaces' do
let(:title) { 'oh my god this is not valid' }
it { should contain_file('oh_my_god_this_is_not_valid.pref') }
end
context '#$&*$' do
let(:title) { 'so && many $* invalid @! things' }
it { should contain_file('so____many____invalid____things.pref') }
end
end
end

View file

@ -0,0 +1,158 @@
require 'spec_helper'
describe 'apt::ppa', :type => :define do
[
{
:lsbdistrelease => '11.04',
:lsbdistcodename => 'natty',
:operatingsystem => 'Ubuntu',
:lsbdistid => 'Ubuntu',
:package => 'python-software-properties'
},
{
:lsbdistrelease => '12.10',
:lsbdistcodename => 'quantal',
:operatingsystem => 'Ubuntu',
:lsbdistid => 'Ubuntu',
:package => 'software-properties-common'
},
].each do |platform|
context "on #{platform[:lsbdistcodename]}" do
let :facts do
{
:lsbdistrelease => platform[:lsbdistrelease],
:lsbdistcodename => platform[:lsbdistcodename],
:operatingsystem => platform[:operatingsystem],
:lsbdistid => platform[:lsbdistid],
:osfamily => 'Debian',
}
end
let :release do
"#{platform[:lsbdistcodename]}"
end
let :package do
"#{platform[:package]}"
end
let :options do
"-y"
end
['ppa:dans_ppa', 'dans_ppa','ppa:dans-daily/ubuntu'].each do |t|
describe "with title #{t}" do
let :pre_condition do
'class { "apt": }'
end
let :title do
t
end
let :filename do
t.sub(/^ppa:/,'').gsub('/','-') << "-" << "#{release}.list"
end
it { should contain_package("#{package}") }
it { should contain_exec("apt_update").with(
'command' => '/usr/bin/apt-get update',
'refreshonly' => true
)
}
it { should contain_exec("add-apt-repository-#{t}").with(
'command' => "/usr/bin/add-apt-repository #{options} #{t}",
'unless' => "/usr/bin/test -s /etc/apt/sources.list.d/#{filename}",
'require' => ["File[sources.list.d]", "Package[#{package}]"],
'notify' => "Exec[apt_update]"
)
}
it { should create_file("/etc/apt/sources.list.d/#{filename}").with(
'ensure' => 'file',
'require' => "Exec[add-apt-repository-#{t}]"
)
}
end
end
describe 'without a proxy defined' do
let :title do
'rspec_ppa'
end
let :pre_condition do
'class { "apt":
proxy_host => false
}'
end
let :filename do
"#{title}-#{release}.list"
end
it { should contain_exec("add-apt-repository-#{title}").with(
'environment' => [],
'command' => "/usr/bin/add-apt-repository #{options} #{title}",
'unless' => "/usr/bin/test -s /etc/apt/sources.list.d/#{filename}",
'require' => ["File[sources.list.d]", "Package[#{package}]"],
'notify' => "Exec[apt_update]"
)
}
end
describe 'behind a proxy' do
let :title do
'rspec_ppa'
end
let :pre_condition do
'class { "apt":
proxy_host => "user:pass@proxy",
}'
end
let :filename do
"#{title}-#{release}.list"
end
it { should contain_exec("add-apt-repository-#{title}").with(
'environment' => [
"http_proxy=http://user:pass@proxy:8080",
"https_proxy=http://user:pass@proxy:8080",
],
'command' => "/usr/bin/add-apt-repository #{options} #{title}",
'unless' => "/usr/bin/test -s /etc/apt/sources.list.d/#{filename}",
'require' => ["File[sources.list.d]", "Package[#{package}]"],
'notify' => "Exec[apt_update]"
)
}
end
end
end
[ { :lsbdistcodename => 'natty',
:package => 'python-software-properties' },
{ :lsbdistcodename => 'quantal',
:package => 'software-properties-common'},
].each do |platform|
context "on #{platform[:lsbdistcodename]}" do
describe "it should not error if package['#{platform[:package]}'] is already defined" do
let :pre_condition do
'class {"apt": }' +
'package { "#{platform[:package]}": }->Apt::Ppa["ppa"]'
end
let :facts do
{:lsbdistcodename => '#{platform[:lsbdistcodename]}',
:operatingsystem => 'Ubuntu',
:lsbdistid => 'Ubuntu',
:osfamily => 'Debian'}
end
let(:title) { "ppa" }
let(:release) { "#{platform[:lsbdistcodename]}" }
it { should contain_package('#{platform[:package]}') }
end
end
end
describe "without Class[apt] should raise a Puppet::Error" do
let(:release) { "natty" }
let(:title) { "ppa" }
it { expect { should contain_apt__ppa(title) }.to raise_error(Puppet::Error) }
end
describe "without release should raise a Puppet::Error" do
let(:title) { "ppa:" }
it { expect { should contain_apt__ppa(:release) }.to raise_error(Puppet::Error) }
end
end

View file

@ -0,0 +1,172 @@
require 'spec_helper'
describe 'apt::source', :type => :define do
let(:facts) { { :lsbdistid => 'Debian' } }
GPG_KEY_ID = '4BD6EC30'
let :title do
'my_source'
end
let :default_params do
{
:ensure => 'present',
:location => '',
:release => 'karmic',
:repos => 'main',
:include_src => true,
:required_packages => false,
:key => false,
:key_server => false,
:key_content => false,
:key_source => false,
:pin => false
}
end
[{},
{
:location => 'http://example.com',
:release => 'precise',
:repos => 'security',
:include_src => false,
:required_packages => 'apache',
:key => GPG_KEY_ID,
:key_server => 'keyserver.debian.com',
:pin => '600',
:key_content => 'ABCD1234'
},
{
:key => GPG_KEY_ID,
:key_server => 'keyserver.debian.com',
},
{
:ensure => 'absent',
:location => 'http://example.com',
:release => 'precise',
:repos => 'security',
},
{
:release => '',
},
{
:release => 'custom',
},
{
:architecture => 'amd64',
}
].each do |param_set|
describe "when #{param_set == {} ? "using default" : "specifying"} class parameters" do
let :param_hash do
default_params.merge(param_set)
end
let :facts do
{:lsbdistcodename => 'karmic', :lsbdistid => 'Ubuntu'}
end
let :params do
param_set
end
let :filename do
"/etc/apt/sources.list.d/#{title}.list"
end
let :content do
content = "# #{title}"
if param_hash[:architecture]
arch = "[arch=#{param_hash[:architecture]}] "
end
content << "\ndeb #{arch}#{param_hash[:location]} #{param_hash[:release]} #{param_hash[:repos]}\n"
if param_hash[:include_src]
content << "deb-src #{arch}#{param_hash[:location]} #{param_hash[:release]} #{param_hash[:repos]}\n"
end
content
end
it { should contain_apt__params }
it { should contain_file("#{title}.list").with({
'ensure' => param_hash[:ensure],
'path' => filename,
'owner' => 'root',
'group' => 'root',
'mode' => '0644',
'content' => content,
})
}
it {
if param_hash[:pin]
should contain_apt__pin(title).with({
"priority" => param_hash[:pin],
"before" => "File[#{title}.list]"
})
else
should_not contain_apt__pin(title).with({
"priority" => param_hash[:pin],
"before" => "File[#{title}.list]"
})
end
}
it {
should contain_exec("apt_update").with({
"command" => "/usr/bin/apt-get update",
"refreshonly" => true
})
}
it {
if param_hash[:required_packages]
should contain_exec("Required packages: '#{param_hash[:required_packages]}' for #{title}").with({
"command" => "/usr/bin/apt-get -y install #{param_hash[:required_packages]}",
"subscribe" => "File[#{title}.list]",
"refreshonly" => true,
"before" => 'Exec[apt_update]',
})
else
should_not contain_exec("Required packages: '#{param_hash[:required_packages]}' for #{title}").with({
"command" => "/usr/bin/apt-get -y install #{param_hash[:required_packages]}",
"subscribe" => "File[#{title}.list]",
"refreshonly" => true
})
end
}
it {
key_server = param_hash[:key_server] || nil
key_content = param_hash[:key_content] || nil
key_source = param_hash[:key_source] || nil
if param_hash[:key]
should contain_apt__key("Add key: #{param_hash[:key]} from Apt::Source #{title}").with({
"key" => param_hash[:key],
"ensure" => :present,
"key_server" => key_server,
"key_content" => key_content,
"key_source" => key_source,
"before" => "File[#{title}.list]"
})
else
should_not contain_apt__key("Add key: #{param_hash[:key]} from Apt::Source #{title}").with({
"key" => param_hash[:key],
"ensure" => :present,
"key_server" => param_hash[:key_server],
"key_content" => param_hash[:key_content],
"key_source" => param_hash[:key_source],
"before" => "File[#{title}.list]"
})
end
}
end
end
describe "without release should raise a Puppet::Error" do
let(:default_params) { Hash.new }
let(:facts) { Hash.new }
it { expect { should raise_error(Puppet::Error) } }
let(:facts) { { :lsbdistcodename => 'lucid', :lsbdistid => 'Ubuntu' } }
it { should contain_apt__source(title) }
end
end

View file

@ -0,0 +1 @@
require 'puppetlabs_spec_helper/module_spec_helper'

View file

@ -0,0 +1,33 @@
require 'beaker-rspec'
# Install Puppet
unless ENV['RS_PROVISION'] == 'no'
hosts.each do |host|
if host.is_pe?
install_pe
else
install_puppet
on host, "mkdir -p #{host['distmoduledir']}"
end
end
end
UNSUPPORTED_PLATFORMS = ['RedHat','Suse','windows','AIX','Solaris']
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
puppet_module_install(:source => proj_root, :module_name => 'apt')
hosts.each do |host|
shell('/bin/touch /etc/puppet/hiera.yaml')
shell('puppet module install puppetlabs-stdlib --version 2.2.1', { :acceptable_exit_codes => [0,1] })
end
end
end

View file

@ -0,0 +1,160 @@
require 'spec_helper'
require 'puppet'
describe Puppet::Type::type(:apt_key) do
context 'only namevar 32bit key id' do
let(:resource) { Puppet::Type.type(:apt_key).new(
:id => '4BD6EC30'
)}
it 'id is set' do
resource[:id].should eq '4BD6EC30'
end
it 'name is set to id' do
resource[:name].should eq '4BD6EC30'
end
it 'keyserver is default' do
resource[:server].should eq :'keyserver.ubuntu.com'
end
it 'source is not set' do
resource[:source].should eq nil
end
it 'content is not set' do
resource[:content].should eq nil
end
end
context 'with a lowercase 32bit key id' do
let(:resource) { Puppet::Type.type(:apt_key).new(
:id => '4bd6ec30'
)}
it 'id is set' do
resource[:id].should eq '4BD6EC30'
end
end
context 'with a 64bit key id' do
let(:resource) { Puppet::Type.type(:apt_key).new(
:id => 'FFFFFFFF4BD6EC30'
)}
it 'id is set' do
resource[:id].should eq '4BD6EC30'
end
end
context 'with a 0x formatted key id' do
let(:resource) { Puppet::Type.type(:apt_key).new(
:id => '0x4BD6EC30'
)}
it 'id is set' do
resource[:id].should eq '4BD6EC30'
end
end
context 'with a 0x formatted lowercase key id' do
let(:resource) { Puppet::Type.type(:apt_key).new(
:id => '0x4bd6ec30'
)}
it 'id is set' do
resource[:id].should eq '4BD6EC30'
end
end
context 'with a 0x formatted 64bit key id' do
let(:resource) { Puppet::Type.type(:apt_key).new(
:id => '0xFFFFFFFF4BD6EC30'
)}
it 'id is set' do
resource[:id].should eq '4BD6EC30'
end
end
context 'with source' do
let(:resource) { Puppet::Type.type(:apt_key).new(
:id => '4BD6EC30',
:source => 'http://apt.puppetlabs.com/pubkey.gpg'
)}
it 'source is set to the URL' do
resource[:source].should eq 'http://apt.puppetlabs.com/pubkey.gpg'
end
end
context 'with content' do
let(:resource) { Puppet::Type.type(:apt_key).new(
:id => '4BD6EC30',
:content => 'http://apt.puppetlabs.com/pubkey.gpg'
)}
it 'content is set to the string' do
resource[:content].should eq 'http://apt.puppetlabs.com/pubkey.gpg'
end
end
context 'with keyserver' do
let(:resource) { Puppet::Type.type(:apt_key).new(
:id => '4BD6EC30',
:server => 'http://keyring.debian.org'
)}
it 'keyserver is set to Debian' do
resource[:server].should eq 'http://keyring.debian.org'
end
end
context 'validation' do
it 'raises an error if content and source are set' do
expect { Puppet::Type.type(:apt_key).new(
:id => '4BD6EC30',
:source => 'http://apt.puppetlabs.com/pubkey.gpg',
:content => 'Completely invalid as a GPG key'
)}.to raise_error(/content and source are mutually exclusive/)
end
it 'raises an error if a weird length key is used' do
expect { Puppet::Type.type(:apt_key).new(
:id => 'F4BD6EC30',
:source => 'http://apt.puppetlabs.com/pubkey.gpg',
:content => 'Completely invalid as a GPG key'
)}.to raise_error(/Valid values match/)
end
it 'raises an error when an invalid URI scheme is used in source' do
expect { Puppet::Type.type(:apt_key).new(
:id => '4BD6EC30',
:source => 'hkp://pgp.mit.edu'
)}.to raise_error(/Valid values match/)
end
it 'allows the http URI scheme in source' do
expect { Puppet::Type.type(:apt_key).new(
:id => '4BD6EC30',
:source => 'http://pgp.mit.edu'
)}.to_not raise_error
end
it 'allows the https URI scheme in source' do
expect { Puppet::Type.type(:apt_key).new(
:id => '4BD6EC30',
:source => 'https://pgp.mit.edu'
)}.to_not raise_error
end
it 'allows the ftp URI scheme in source' do
expect { Puppet::Type.type(:apt_key).new(
:id => '4BD6EC30',
:source => 'ftp://pgp.mit.edu'
)}.to_not raise_error
end
it 'allows an absolute path in source' do
expect { Puppet::Type.type(:apt_key).new(
:id => '4BD6EC30',
:source => '/path/to/a/file'
)}.to_not raise_error
end
end
end

View file

@ -0,0 +1,12 @@
APT::Periodic::Enable "<%= @enable %>";
APT::Periodic::BackUpArchiveInterval "<%= @backup_interval %>";
APT::Periodic::BackUpLevel "<%= @backup_level %>";
APT::Periodic::MaxAge "<%= @max_age %>";
APT::Periodic::MinAge "<%= @min_age %>";
APT::Periodic::MaxSize "<%= @max_size %>";
APT::Periodic::Update-Package-Lists "<%= @update %>";
APT::Periodic::Download-Upgradeable-Packages "<%= @download %>";
APT::Periodic::Download-Upgradeable-Packages-Debdelta "<%= @download_delta %>";
APT::Periodic::Unattended-Upgrade "<%= @upgrade %>";
APT::Periodic::AutocleanInterval "<%= @autoclean %>";
APT::Periodic::Verbose "<%= @verbose %>";

View file

@ -0,0 +1,57 @@
// Automatically upgrade packages from these (origin:archive) pairs
<%- if @legacy_origin -%>
Unattended-Upgrade::Allowed-Origins {
<%- else -%>
Unattended-Upgrade::Origins-Pattern {
<%- end -%>
<% @origins.each do |origin| -%>
"<%= origin %>";
<% end -%>
};
// List of packages to not update
Unattended-Upgrade::Package-Blacklist {
<% @blacklist.each do |package| -%>
"<%= package %>";
<% end -%>
};
// This option allows you to control if on a unclean dpkg exit
// unattended-upgrades will automatically run
// dpkg --force-confold --configure -a
// The default is true, to ensure updates keep getting installed
Unattended-Upgrade::AutoFixInterruptedDpkg "<%= @auto_fix %>";
// Split the upgrade into the smallest possible chunks so that
// they can be interrupted with SIGUSR1. This makes the upgrade
// a bit slower but it has the benefit that shutdown while a upgrade
// is running is possible (with a small delay)
Unattended-Upgrade::MinimalSteps "<%= @minimal_steps %>";
// Install all unattended-upgrades when the machine is shuting down
// instead of doing it in the background while the machine is running
// This will (obviously) make shutdown slower
Unattended-Upgrade::InstallOnShutdown "<%= @install_on_shutdown %>";
// Send email to this address for problems or packages upgrades
// If empty or unset then no email is sent, make sure that you
// have a working mail setup on your system. A package that provides
// 'mailx' must be installed.
<% if @mail_to != "NONE" %>Unattended-Upgrade::Mail "<%= @mail_to %>";<% end %>
// Set this value to "true" to get emails only on errors. Default
// is to always send a mail if Unattended-Upgrade::Mail is set
<% if @mail_to != "NONE" %>Unattended-Upgrade::MailOnlyOnError "<%= @mail_only_on_error %>";<% end %>
// Do automatic removal of new unused dependencies after the upgrade
// (equivalent to apt-get autoremove)
Unattended-Upgrade::Remove-Unused-Dependencies "<%= @remove_unused %>";
// Automatically reboot *WITHOUT CONFIRMATION* if a
// the file /var/run/reboot-required is found after the upgrade
Unattended-Upgrade::Automatic-Reboot "<%= @auto_reboot %>";
// Use apt bandwidth limit feature, this example limits the download
// speed to 70kb/sec
<% if @dl_limit != "NONE" %>Acquire::http::Dl-Limit "<%= @dl_limit %>";<% end %>

View file

@ -0,0 +1,21 @@
<%-
@pin = "release a=#{@name}" # default value
if @pin_release.length > 0
options = []
options.push("a=#{@release}") if @release.length > 0
options.push("n=#{@codename}") if @codename.length > 0
options.push("v=#{@release_version}") if @release_version.length > 0
options.push("c=#{@component}") if @component.length > 0
options.push("o=#{@originator}") if @originator.length > 0
options.push("l=#{@label}") if @label.length > 0
@pin = "release #{options.join(', ')}"
elsif @version.length > 0
@pin = "version #{@version}"
elsif @origin.length > 0
@pin = "origin #{@origin}"
end
-%>
Explanation: <%= @explanation %>
Package: <%= @packages_string %>
Pin: <%= @pin %>
Pin-Priority: <%= @priority %>

View file

@ -0,0 +1,5 @@
# <%= @name %>
deb <% if @architecture %>[arch=<%= @architecture %>] <% end %><%= @location %> <%= @release_real %> <%= @repos %>
<%- if @include_src then -%>
deb-src <% if @architecture %>[arch=<%= @architecture %>] <% end %><%= @location %> <%= @release_real %> <%= @repos %>
<%- end -%>

View file

@ -0,0 +1,2 @@
class { 'apt': }
apt::builddep{ 'glusterfs-server': }

View file

@ -0,0 +1,2 @@
class { 'apt': }
class { 'apt::debian::testing': }

View file

@ -0,0 +1,2 @@
class { 'apt': }
class { 'apt::debian::unstable': }

View file

@ -0,0 +1,17 @@
# force.pp
# force a package from a specific release
apt::force { 'package1':
release => 'backports',
}
# force a package to be a specific version
apt::force { 'package2':
version => '1.0.0-1',
}
# force a package from a specific release to be a specific version
apt::force { 'package3':
release => 'sid',
version => '2.0.0-1',
}

View file

@ -0,0 +1 @@
class { 'apt': }

6
modules/apt/tests/key.pp Normal file
View file

@ -0,0 +1,6 @@
# Declare Apt key for apt.puppetlabs.com source
apt::key { 'puppetlabs':
key => '4BD6EC30',
key_server => 'pgp.mit.edu',
key_options => 'http-proxy="http://proxyuser:proxypass@example.org:3128"',
}

View file

@ -0,0 +1 @@
include apt::params

5
modules/apt/tests/pin.pp Normal file
View file

@ -0,0 +1,5 @@
# pin a release in apt, useful for unstable repositories
apt::pin { 'foo':
packages => '*',
priority => 0,
}

4
modules/apt/tests/ppa.pp Normal file
View file

@ -0,0 +1,4 @@
class { 'apt': }
# Example declaration of an Apt PPA
apt::ppa{ 'ppa:openstack-ppa/bleeding-edge': }

View file

@ -0,0 +1,4 @@
class { 'apt': }
class { 'apt::release':
release_id => 'karmic'
}

View file

@ -0,0 +1,29 @@
# Declare the apt class to manage /etc/apt/sources.list and /etc/sources.list.d
class { 'apt': }
# Install the puppetlabs apt source
# Release is automatically obtained from lsbdistcodename fact if available.
apt::source { 'puppetlabs':
location => 'http://apt.puppetlabs.com',
repos => 'main',
key => '4BD6EC30',
key_server => 'pgp.mit.edu',
}
# test two sources with the same key
apt::source { 'debian_testing':
location => 'http://debian.mirror.iweb.ca/debian/',
release => 'testing',
repos => 'main contrib non-free',
key => '46925553',
key_server => 'subkeys.pgp.net',
pin => '-10',
}
apt::source { 'debian_unstable':
location => 'http://debian.mirror.iweb.ca/debian/',
release => 'unstable',
repos => 'main contrib non-free',
key => '46925553',
key_server => 'subkeys.pgp.net',
pin => '-10',
}

View file

@ -0,0 +1 @@
include apt::unattended_upgrades

127
modules/concat/CHANGELOG Normal file
View file

@ -0,0 +1,127 @@
2014-05-14 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 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.
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

20
modules/concat/Gemfile Normal file
View file

@ -0,0 +1,20 @@
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 'beaker', :require => false
gem 'beaker-rspec', :require => false
gem 'puppet-lint', :require => false
gem 'serverspec', :require => false
gem 'pry', :require => false
end
if puppetversion = ENV['PUPPET_GEM_VERSION']
gem 'puppet', puppetversion, :require => false
else
gem 'puppet', :require => false
end
# vim:ft=ruby

14
modules/concat/LICENSE Normal file
View file

@ -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.

View file

@ -0,0 +1,9 @@
name 'puppetlabs-concat'
version '1.1.0'
source 'git://github.com/puppetlabs/puppetlabs-concat.git'
author 'Puppetlabs'
license 'Apache 2.0'
summary 'Concat module'
description 'Concat module'
project_page 'http://github.com/puppetlabs/puppetlabs-concat'
dependency 'puppetlabs/stdlib', '>= 4.0.0'

441
modules/concat/README.md Normal file
View file

@ -0,0 +1,441 @@
#Concat
[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-concat.png?branch=master)](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:
<pre>
Puppet modules on this server:
-- Apache
-- MySQL
</pre>
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.
######Example
- warn => true
- warn => false
#####`warn_message`
Set the contents of the warning message.
######Example
- warn_message => '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'
#####`ensure`
Control the file of fragment created.
######Example
- ensure => 'present'
- ensure => 'absent'
- ensure => 'file'
- ensure => 'directory'
#####`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 cant 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

5
modules/concat/Rakefile Normal file
View file

@ -0,0 +1,5 @@
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.send('disable_quoted_booleans')

View file

@ -0,0 +1,137 @@
# 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 => ""
}
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
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))
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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,121 @@
# == 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.')
}
validate_string($order)
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 {
$_ensure = 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.')
}
$_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 = $_ensure ? {
'' => 'file',
undef => 'file',
'file' => 'file',
'present' => 'file',
'absent' => 'absent',
default => $_ensure,
}
# if it looks line ensure => /target syntax was used, fish that out
if ! ($_ensure in ['', 'present', 'absent', 'file' ]) {
$ensure_target = $_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,
alias => "concat_fragment_${name}",
notify => Exec["concat_${target}"]
}
}

View file

@ -0,0 +1,232 @@
# == 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)
validate_string($backup)
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',
}
exec { "concat_${name}":
alias => "concat_${fragdir}",
command => $absent_exec_command,
path => $absent_exec_path
}
}
}
# vim:sw=2:ts=2:expandtab:textwidth=79

View file

@ -0,0 +1,58 @@
# === 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 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' }
$script_name = $::kernel ? {
'windows' => '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 = $::kernel ? {
'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',
}
}

View file

@ -0,0 +1,67 @@
{
"name": "puppetlabs-concat",
"version": "1.1.0",
"source": "git://github.com/puppetlabs/puppetlabs-concat.git",
"author": "Puppetlabs",
"license": "Apache 2.0",
"summary": "Concat module",
"description": "Concat module",
"project_page": "http://github.com/puppetlabs/puppetlabs-concat",
"dependencies": [
{
"name": "puppetlabs/stdlib",
"version_requirement": ">= 4.0.0"
}
],
"types": [
],
"checksums": {
"CHANGELOG": "fca146b0dcd7cc60a9082b8e301a2e18",
"Gemfile": "3cadf91e1baf9c8b7d2b1c3036676ba9",
"LICENSE": "f5a76685d453424cd63dde1535811cf0",
"Modulefile": "f8abb1236ed5211c4a3aa732431c2e19",
"README.md": "adecb8db1313997083179540b20ede86",
"Rakefile": "e415d40cd8db238f02bf4575d5e1e693",
"files/concatfragments.rb": "6784c28044a4204efb75fe4eb759816a",
"files/concatfragments.sh": "7bbe7c5fce25a5ddd20415d909ba44fc",
"lib/facter/concat_basedir.rb": "ff080677e7f192b9b96911698b0b9b3d",
"manifests/fragment.pp": "8bfd199e757f6a57f6174b558f87d2ce",
"manifests/init.pp": "79c6dc5bf0b2b0da3ce84cc2f0ae5f02",
"manifests/setup.pp": "0ff9f4d9b4c01360606ae29d8df31ff0",
"spec/acceptance/backup_spec.rb": "d4ffdf3d4f5a1b7c0aa64dd118375124",
"spec/acceptance/concat_spec.rb": "600243521241dac0b238ad01b10c7132",
"spec/acceptance/deprecation_warnings_spec.rb": "40286704d0f544437293ed8a1cc66fe9",
"spec/acceptance/empty_spec.rb": "c2edc5cef72870b0894e1b2184207325",
"spec/acceptance/fragment_source_spec.rb": "c5cda233f208b71d7d5cc89dfa4be81d",
"spec/acceptance/newline_spec.rb": "55b9f470bdff4c0245da6895c9b6e64d",
"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": "092dd2c588a9f87fa1fb12997c0723ef",
"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": "3d68f9581097bb3a807ba1931c961959",
"spec/acceptance/nodesets/fedora-18-x64.yml": "80e41b1ee16ea489f53164bfdae58855",
"spec/acceptance/nodesets/rhel-7-x64.yml": "91b55d29f059e23383c7bc352b5d671d",
"spec/acceptance/nodesets/sles-11-x64.yml": "44e4c6c15c018333bfa9840a5e702f66",
"spec/acceptance/nodesets/sles-11sp1-x64.yml": "fa0046bd89c1ab4ba9521ad79db234cd",
"spec/acceptance/nodesets/ubuntu-server-10044-x64.yml": "75e86400b7889888dc0781c0ae1a1297",
"spec/acceptance/nodesets/ubuntu-server-12042-x64.yml": "d30d73e34cd50b043c7d14e305955269",
"spec/acceptance/nodesets/ubuntu-server-1404-x64.yml": "5f0aed10098ac5b78e4217bb27c7aaf0",
"spec/acceptance/order_spec.rb": "0de9b4993a3e3f6f36c52bb18f48280c",
"spec/acceptance/quoted_paths_spec.rb": "953a5a665bd4bb468e70856260c47c6e",
"spec/acceptance/replace_spec.rb": "7072d819d5997ad227fc17f4b813fe4f",
"spec/acceptance/symbolic_name_spec.rb": "10e856a87253cf8bbef95f8f9635b63e",
"spec/acceptance/warn_spec.rb": "ec03f0fa8086fc4be03da1c5aff25097",
"spec/spec_helper.rb": "0db89c9a486df193c0e40095422e19dc",
"spec/spec_helper_acceptance.rb": "5be78c42f01346abf097bbcab34ff424",
"spec/unit/classes/concat_setup_spec.rb": "6d3729833715d65f3c50c2153caed6bc",
"spec/unit/defines/concat_fragment_spec.rb": "ced7c3b1b6d7f2e65c6dc066aa8c0527",
"spec/unit/defines/concat_spec.rb": "d8da592546c9811bf40e111bf52755dc",
"spec/unit/facts/concat_basedir_spec.rb": "cf00f5a07948436fa0a84d00fc098539",
"tests/fragment.pp": "9adc3d9ba61676066072e1b949a37dbb",
"tests/init.pp": "bd3ce7d2ee146744b5dbbaae8a927043"
}
}

View file

@ -0,0 +1,101 @@
require 'spec_helper_acceptance'
describe 'concat backup parameter' do
context '=> puppet' do
before :all do
shell('rm -rf /tmp/concat')
shell('mkdir -p /tmp/concat')
shell("/bin/echo 'old contents' > /tmp/concat/file")
end
pp = <<-EOS
concat { '/tmp/concat/file':
backup => 'puppet',
}
concat::fragment { 'new file':
target => '/tmp/concat/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.stderr).to eq("")
expect(r.stdout).to match(/Filebucketed \/tmp\/concat\/file to puppet with sum 0140c31db86293a1a1e080ce9b91305f/) # sum is for file contents of 'old contents'
end
expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
end
describe file('/tmp/concat/file') do
it { should be_file }
it { should contain 'new contents' }
end
end
context '=> .backup' do
before :all do
shell('rm -rf /tmp/concat')
shell('mkdir -p /tmp/concat')
shell("/bin/echo 'old contents' > /tmp/concat/file")
end
pp = <<-EOS
concat { '/tmp/concat/file':
backup => '.backup',
}
concat::fragment { 'new file':
target => '/tmp/concat/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
expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
end
describe file('/tmp/concat/file') do
it { should be_file }
it { should contain 'new contents' }
end
describe file('/tmp/concat/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
shell('rm -rf /tmp/concat')
shell('mkdir -p /tmp/concat')
shell("/bin/echo 'old contents' > /tmp/concat/file")
end
pp = <<-EOS
concat { '/tmp/concat/file':
backup => '.backup',
}
concat::fragment { 'new file':
target => '/tmp/concat/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.stderr).to eq("")
expect(r.stdout).to_not match(/Filebucketed/)
end
expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
end
describe file('/tmp/concat/file') do
it { should be_file }
it { should contain 'new contents' }
end
end
end

View file

@ -0,0 +1,204 @@
require 'spec_helper_acceptance'
describe 'basic concat test' do
shared_examples 'successfully_applied' do |pp|
it 'applies the manifest twice with no stderr' do
expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
end
describe file("#{default['puppetvardir']}/concat") do
it { should be_directory }
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
it { should be_mode 755 }
end
describe file("#{default['puppetvardir']}/concat/bin") do
it { should be_directory }
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
it { should be_mode 755 }
end
describe file("#{default['puppetvardir']}/concat/bin/concatfragments.sh") do
it { should be_file }
it { should be_owned_by 'root' }
#it { should be_grouped_into 'root' }
it { should be_mode 755 }
end
describe file("#{default['puppetvardir']}/concat/_tmp_concat_file") do
it { should be_directory }
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
it { should be_mode 750 }
end
describe file("#{default['puppetvardir']}/concat/_tmp_concat_file/fragments") do
it { should be_directory }
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
it { should be_mode 750 }
end
describe file("#{default['puppetvardir']}/concat/_tmp_concat_file/fragments.concat") do
it { should be_file }
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
it { should be_mode 640 }
end
describe file("#{default['puppetvardir']}/concat/_tmp_concat_file/fragments.concat.out") do
it { should be_file }
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
it { should be_mode 640 }
end
end
context 'owner/group root' do
pp = <<-EOS
concat { '/tmp/concat/file':
owner => 'root',
group => 'root',
mode => '0644',
}
concat::fragment { '1':
target => '/tmp/concat/file',
content => '1',
order => '01',
}
concat::fragment { '2':
target => '/tmp/concat/file',
content => '2',
order => '02',
}
EOS
it_behaves_like 'successfully_applied', pp
describe file('/tmp/concat/file') do
it { should be_file }
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
it { should be_mode 644 }
it { should contain '1' }
it { should contain '2' }
end
describe file("#{default['puppetvardir']}/concat/_tmp_concat_file/fragments/01_1") do
it { should be_file }
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
it { should be_mode 640 }
end
describe file("#{default['puppetvardir']}/concat/_tmp_concat_file/fragments/02_2") do
it { should be_file }
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
it { should be_mode 640 }
end
end
context 'owner/group non-root' do
before(:all) do
shell "groupadd -g 64444 bob"
shell "useradd -u 42 -g 64444 bob"
end
after(:all) do
shell "userdel bob"
end
pp="
concat { '/tmp/concat/file':
owner => 'bob',
group => 'bob',
mode => '0644',
}
concat::fragment { '1':
target => '/tmp/concat/file',
content => '1',
order => '01',
}
concat::fragment { '2':
target => '/tmp/concat/file',
content => '2',
order => '02',
}
"
it_behaves_like 'successfully_applied', pp
describe file('/tmp/concat/file') do
it { should be_file }
it { should be_owned_by 'bob' }
it { should be_grouped_into 'bob' }
it { should be_mode 644 }
it { should contain '1' }
it { should contain '2' }
end
describe file("#{default['puppetvardir']}/concat/_tmp_concat_file/fragments/01_1") do
it { should be_file }
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
it { should be_mode 640 }
it { should contain '1' }
end
describe file("#{default['puppetvardir']}/concat/_tmp_concat_file/fragments/02_2") do
it { should be_file }
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
it { should be_mode 640 }
it { should contain '2' }
end
end
context 'ensure' do
context 'works when set to present with path set' do
pp="
concat { 'file':
ensure => present,
path => '/tmp/concat/file',
mode => '0644',
}
concat::fragment { '1':
target => 'file',
content => '1',
order => '01',
}
"
it_behaves_like 'successfully_applied', pp
describe file('/tmp/concat/file') do
it { should be_file }
it { should be_mode 644 }
it { should contain '1' }
end
end
context 'works when set to absent with path set' do
pp="
concat { 'file':
ensure => absent,
path => '/tmp/concat/file',
mode => '0644',
}
concat::fragment { '1':
target => 'file',
content => '1',
order => '01',
}
"
# Can't used shared examples as this will always trigger the exec when
# absent is set.
it 'applies the manifest twice with no stderr' do
expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
end
describe file('/tmp/concat/file') do
it { should_not be_file }
end
end
end
end

View file

@ -0,0 +1,230 @@
require 'spec_helper_acceptance'
describe 'deprecation warnings' do
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 { '/tmp/concat/file':
gnu => 'foo',
}
concat::fragment { 'foo':
target => '/tmp/concat/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 { '/tmp/concat/file':
warn => '#{warn}',
}
concat::fragment { 'foo':
target => '/tmp/concat/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('/tmp/concat/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 { '/tmp/concat/file':
warn => '#{warn}',
}
concat::fragment { 'foo':
target => '/tmp/concat/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('/tmp/concat/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' > /tmp/concat/file1")
end
after(:all) do
# XXX this test may leave behind a symlink in the fragment directory
# which could cause warnings and/or breakage from the subsequent tests
# unless we clean it up.
shell('rm -rf /tmp/concat /var/lib/puppet/concat')
shell('mkdir -p /tmp/concat')
end
pp = <<-EOS
concat { '/tmp/concat/file': }
concat::fragment { 'foo':
target => '/tmp/concat/file',
ensure => '/tmp/concat/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('/tmp/concat/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' do
pp = <<-EOS
concat { '/tmp/concat/file': }
concat::fragment { 'foo':
target => '/tmp/concat/file',
content => 'new content',
}
EOS
it 'applies the manifest twice with no stderr' do
expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
end
describe file('/tmp/concat/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 { '/tmp/concat/file': }
concat::fragment { 'foo':
target => '/tmp/concat/file',
ensure => '/tmp/concat/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('/tmp/concat/file') do
it { should be_file }
end
describe 'the fragment can be changed from a symlink to a plain file' do
pp = <<-EOS
concat { '/tmp/concat/file': }
concat::fragment { 'foo':
target => '/tmp/concat/file',
content => 'new content',
}
EOS
it 'applies the manifest twice with no stderr' do
expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
end
describe file('/tmp/concat/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 { '/tmp/concat/file': }
concat::fragment { 'foo':
target => '/tmp/concat/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 { '/tmp/concat/file': }
concat::fragment { 'foo':
target => '/tmp/concat/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 { '/tmp/concat/file': }
concat::fragment { 'foo':
target => '/tmp/concat/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 { '/tmp/concat/file': }
concat::fragment { 'foo':
target => '/tmp/concat/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

View file

@ -0,0 +1,24 @@
require 'spec_helper_acceptance'
describe 'concat force empty parameter' do
context 'should run successfully' do
pp = <<-EOS
concat { '/tmp/concat/file':
owner => root,
group => root,
mode => '0644',
force => true,
}
EOS
it 'applies the manifest twice with no stderr' do
expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
end
describe file('/tmp/concat/file') do
it { should be_file }
it { should_not contain '1\n2' }
end
end
end

Some files were not shown because too many files have changed in this diff Show more