summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkwadronaut <kwadronaut@leap.se>2014-07-29 19:08:36 +0200
committerkwadronaut <kwadronaut@leap.se>2014-07-29 19:08:36 +0200
commitba32e368e22078cac65d27531a1cf7d0962ec984 (patch)
treed28ae4bd79d5d4f61ecf3d8b8cd55c9e306b960d
parent78c4e8d748138833ba07b71bcfc1ea538c4a2dfb (diff)
parent1696203589b66cc374bd8f5f21e82d5b92eb391b (diff)
Update: Merge remote-tracking branch 'upstream/master'HEADmaster
-rw-r--r--.fixtures.yml6
-rw-r--r--.gitignore9
-rw-r--r--.travis.yml19
-rw-r--r--Gemfile25
-rw-r--r--Modulefile4
-rw-r--r--README.md184
-rw-r--r--Rakefile2
-rw-r--r--lib/facter/pip_version.rb27
-rw-r--r--lib/facter/python_version.rb40
-rw-r--r--lib/facter/virtualenv_version.rb27
-rw-r--r--manifests/config.pp35
-rw-r--r--manifests/gunicorn.pp4
-rw-r--r--manifests/init.pp34
-rw-r--r--manifests/install.pp56
-rw-r--r--manifests/pip.pp151
-rw-r--r--manifests/requirements.pp67
-rw-r--r--manifests/virtualenv.pp114
-rw-r--r--spec/classes/python_spec.rb228
-rw-r--r--spec/defines/requirements_spec.rb53
-rw-r--r--spec_helper.rb25
-rw-r--r--templates/gunicorn.erb32
21 files changed, 967 insertions, 175 deletions
diff --git a/.fixtures.yml b/.fixtures.yml
new file mode 100644
index 0000000..6dcef97
--- /dev/null
+++ b/.fixtures.yml
@@ -0,0 +1,6 @@
+ fixtures:
+ repositories:
+ stdlib: "git://github.com/puppetlabs/puppetlabs-stdlib.git"
+# concat: "git://github.com/puppetlabs/puppetlabs-concat.git"
+ symlinks:
+ python: "#{source_dir}" \ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..56a7f81
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+pkg/
+
+# ignore rbvenv files used for puppet-lint, rspect etc.
+.ruby-version
+.rbenv-gemsets
+
+# ignore geppetto files
+.project
+metadata.json
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..bfe2d16
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,19 @@
+---
+language: ruby
+bundler_args: --without development
+script: "bundle exec rake validate && bundle exec rake lint && bundle exec rake spec SPEC_OPTS='--format documentation'"
+matrix:
+ fast_finish: true
+ include:
+ - rvm: 1.9.3
+ env: PUPPET_GEM_VERSION="~> 3.0"
+ - rvm: 2.0.0
+ env: PUPPET_GEM_VERSION="~> 3.0"
+ - rvm: 1.9.3
+ env: PUPPET_GEM_VERSION="~> 3.5.0" STRICT_VARIABLES="yes"
+ - rvm: 2.0.0
+ env: PUPPET_GEM_VERSION="~> 3.5.0" STRICT_VARIABLES="yes"
+ - rvm: 2.0.0
+ env: PUPPET_GEM_VERSION="~> 3.6.2" STRICT_VARIABLES="yes"
+notifications:
+ email: false
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..60f5f8d
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,25 @@
+source ENV['GEM_SOURCE'] || "https://rubygems.org"
+
+group :development, :test do
+ gem 'rake', :require => false
+ gem 'rspec-puppet', :require => false
+ gem 'puppetlabs_spec_helper', :require => false
+ gem 'serverspec', :require => false
+ gem 'puppet-lint', :require => false
+ gem 'beaker', :require => false
+ gem 'beaker-rspec', :require => false
+ gem 'pry', :require => false
+ gem 'simplecov', :require => false
+end
+
+if facterversion = ENV['FACTER_GEM_VERSION']
+ gem 'facter', facterversion, :require => false
+else
+ gem 'facter', :require => false
+end
+
+if puppetversion = ENV['PUPPET_GEM_VERSION']
+ gem 'puppet', puppetversion, :require => false
+else
+ gem 'puppet', :require => false
+end
diff --git a/Modulefile b/Modulefile
index c7f2f97..af6843f 100644
--- a/Modulefile
+++ b/Modulefile
@@ -1,5 +1,5 @@
-name 'puppet-python'
-version '1.0.0'
+name 'stankevich-python'
+version '1.7.7'
author 'Sergey Stankevich'
license 'Apache License, Version 2.0'
diff --git a/README.md b/README.md
index aafff6a..cb0b712 100644
--- a/README.md
+++ b/README.md
@@ -3,112 +3,188 @@
Puppet module for installing and managing python, pip, virtualenvs and Gunicorn virtual hosts.
+**Version 1.1.x Notes**
+
+Version 1.1.x makes several fundamental changes to the core of this module, adding some additional features, improving performance and making operations more robust in general.
+
+Please note that several changes have been made in v1.1.x which make manifests incompatible with the previous version. However, modifying your manifests to suit is trivial. Please see the notes below.
+
+Currently, the changes you need to make are as follows:
+
+* All pip definitions MUST include the owner field which specifies which user owns the virtualenv that packages will be installed in. Adding this greatly improves performance and efficiency of this module.
+* You must explicitly specify pip => true in the python class if you want pip installed. As such, the pip package is now independent of the dev package and so one can exist without the other.
+
+## Installation
+
+``` shell
+cd /etc/puppet/modules
+git clone git://github.com/stankevich/puppet-python.git python
+```
+
## Usage
### python
Installs and manages python, python-dev, python-virtualenv and Gunicorn.
-**version** — Python version to install. Default: system default
+**version** - Python version to install. Default: system default
+
+**pip** - Install python-pip. Default: false
+
+**dev** - Install python-dev. Default: false
-**dev** — Install python-dev. Default: false
+**virtualenv** - Install python-virtualenv. Default: false
-**virtualenv** — Install python-virtualenv. Default: false
+**gunicorn** - Install Gunicorn. Default: false
-**gunicorn** — Install Gunicorn. Default: false
+**manage_gunicorn** - Allow Installation / Removal of Gunicorn. Default: true
- class { 'python':
- version => 'system',
- dev => true,
- virtualenv => true,
- gunicorn => true,
- }
+```puppet
+ class { 'python':
+ version => 'system',
+ dev => true,
+ virtualenv => true,
+ gunicorn => true,
+ } }
+```
### python::pip
Installs and manages packages from pip.
-**ensure** — present/absent. Default: present
+**pkgname** - the name of the package to install. Required.
+
+**ensure** - present/latest/absent. Default: present
+
+**virtualenv** - virtualenv to run pip in. Default: system (no virtualenv)
+
+**url** - URL to install from. Default: none
-**virtualenv** — virtualenv to run pip in.
+**owner** - The owner of the virtualenv to ensure that packages are installed with the correct permissions (must be specified). Default: root
-**url** — URL to install from. Default: none
+**proxy** - Proxy server to use for outbound connections. Default: none
-**proxy** — Proxy server to use for outbound connections. Default: none
+**environment** - Additional environment variables required to install the packages. Default: none
- python::pip { 'flask':
- virtualenv => '/var/www/project1',
- proxy => 'http://proxy.domain.com:3128',
- }
+**egg** - The egg name to use. Default: $name of the class, e.g. cx_Oracle
+
+**install_args** - Array of additional flags to pass to pip during installaton. Default: none
+
+**uninstall_args** - Array of additional flags to pass to pip during uninstall. Default: none
+
+**timeout** - Timeout for the pip install command. Defaults to 1800.
+```puppet
+ python::pip { 'cx_Oracle':
+ pkgname => 'cx_Oracle',
+ virtualenv => '/var/www/project1',
+ owner => 'appuser',
+ proxy => 'http://proxy.domain.com:3128',
+ environment => 'ORACLE_HOME=/usr/lib/oracle/11.2/client64',
+ install_args => ['-e'],
+ timeout => 1800,
+ }
+```
### python::requirements
Installs and manages Python packages from requirements file.
-**virtualenv** — virtualenv to run pip in. Default: system-wide
+**virtualenv** - virtualenv to run pip in. Default: system-wide
+
+**proxy** - Proxy server to use for outbound connections. Default: none
+
+**owner** - The owner of the virtualenv to ensure that packages are installed with the correct permissions (must be specified). Default: root
+
+**src** - The ``--src`` parameter to ``pip``, used to specify where to install ``--editable`` resources; by default no ``--src`` parameter is passed to ``pip``.
-**proxy** — Proxy server to use for outbound connections. Default: none
+**group** - The group that was used to create the virtualenv. This is used to create the requirements file with correct permissions if it's not present already.
- python::requirements { '/var/www/project1/requirements.txt':
- virtualenv => '/var/www/project1',
- proxy => 'http://proxy.domain.com:3128',
- }
+```puppet
+ python::requirements { '/var/www/project1/requirements.txt':
+ virtualenv => '/var/www/project1',
+ proxy => 'http://proxy.domain.com:3128',
+ owner => 'appuser',
+ group => 'apps',
+ }
+```
### python::virtualenv
Creates Python virtualenv.
-**ensure** — present/absent. Default: present
+**ensure** - present/absent. Default: present
+
+**version** - Python version to use. Default: system default
+
+**requirements** - Path to pip requirements.txt file. Default: none
+
+**proxy** - Proxy server to use for outbound connections. Default: none
+
+**systempkgs** - Copy system site-packages into virtualenv. Default: don't
+
+**distribute** - Include distribute in the virtualenv. Default: true
+
+**venv_dir** - The location of the virtualenv if resource path not specified. Must be absolute path. Default: resource name
-**version** — Python version to use. Default: system default
+**owner** - Specify the owner of this virtualenv
-**requirements** — Path to pip requirements.txt file. Default: none
+**group** - Specify the group for this virtualenv
-**proxy** — Proxy server to use for outbound connections. Default: none
+**index** - Base URL of Python package index. Default: none
-**systempkgs** — Copy system site-packages into virtualenv. Default: don't
+**cwd** - The directory from which to run the "pip install" command. Default: undef
-**distribute** — Include distribute in the virtualenv. Default: true
+**timeout** - The maximum time in seconds the "pip install" command should take. Default: 1800
- python::virtualenv { '/var/www/project1':
- ensure => present,
- version => 'system',
- requirements => '/var/www/project1/requirements.txt',
- proxy => 'http://proxy.domain.com:3128',
- systempkgs => true,
- distribute => false,
- }
+```puppet
+ python::virtualenv { '/var/www/project1':
+ ensure => present,
+ version => 'system',
+ requirements => '/var/www/project1/requirements.txt',
+ proxy => 'http://proxy.domain.com:3128',
+ systempkgs => true,
+ distribute => false,
+ venv_dir => '/home/appuser/virtualenvs',
+ owner => 'appuser',
+ group => 'apps',
+ cwd => '/var/www/project1',
+ timeout => 0,
+ }
+```
### python::gunicorn
Manages Gunicorn virtual hosts.
-**ensure** — present/absent. Default: present
+**ensure** - present/absent. Default: present
-**virtualenv** — Run in virtualenv, specify directory. Default: disabled
+**virtualenv** - Run in virtualenv, specify directory. Default: disabled
-**mode** — Gunicorn mode. wsgi/django. Default: wsgi
+**mode** - Gunicorn mode. wsgi/django. Default: wsgi
-**dir** — Application directory.
+**dir** - Application directory.
-**bind** — Bind on: 'HOST', 'HOST:PORT', 'unix:PATH'. Default: unix:/tmp/gunicorn-$name.socket or unix:${virtualenv}/${name}.socket
+**bind** - Bind on: 'HOST', 'HOST:PORT', 'unix:PATH'. Default: unix:/tmp/gunicorn-$name.socket or unix:${virtualenv}/${name}.socket
-**environment** — Set ENVIRONMENT variable. Default: none
+**environment** - Set ENVIRONMENT variable. Default: none
-**template** — Which ERB template to use. Default: python/gunicorn.erb
+**template** - Which ERB template to use. Default: python/gunicorn.erb
- python::gunicorn { 'vhost':
- ensure => present,
- virtualenv => '/var/www/project1',
- mode => 'wsgi',
- dir => '/var/www/project1/current',
- bind => 'unix:/tmp/gunicorn.socket',
- environment => 'prod',
- template => 'python/gunicorn.erb',
- }
+```puppet
+ python::gunicorn { 'vhost':
+ ensure => present,
+ virtualenv => '/var/www/project1',
+ mode => 'wsgi',
+ dir => '/var/www/project1/current',
+ bind => 'unix:/tmp/gunicorn.socket',
+ environment => 'prod',
+ template => 'python/gunicorn.erb',
+ }
+```
## Authors
[Sergey Stankevich](https://github.com/stankevich)
[Ashley Penney](https://github.com/apenney)
[Marc Fournier](https://github.com/mfournier)
+[Fotis Gimian](https://github.com/fgimian)
diff --git a/Rakefile b/Rakefile
index 58df3ec..b133dff 100644
--- a/Rakefile
+++ b/Rakefile
@@ -6,3 +6,5 @@ PuppetLint.configuration.with_filename = true
PuppetLint.configuration.send('disable_documentation')
PuppetLint.configuration.send('disable_class_parameter_defaults')
PuppetLint.configuration.send('disable_80chars')
+
+require 'puppetlabs_spec_helper/rake_tasks'
diff --git a/lib/facter/pip_version.rb b/lib/facter/pip_version.rb
new file mode 100644
index 0000000..ce32f98
--- /dev/null
+++ b/lib/facter/pip_version.rb
@@ -0,0 +1,27 @@
+# Make pip version available as a fact
+# Works with pip loaded and without, pip installed using pip and package installed
+require 'puppet'
+pkg = Puppet::Type.type(:package).new(:name => "python-pip")
+Facter.add("pip_version") do
+ has_weight 100
+ setcode do
+ begin
+ /^pip (\d+\.\d+\.?\d*).*$/.match(Facter::Util::Resolution.exec('pip --version 2>/dev/null'))[1]
+ rescue
+ false
+ end
+ end
+end
+
+Facter.add("pip_version") do
+ has_weight 50
+ setcode do
+ begin
+ unless [:absent,'purged'].include?(pkg.retrieve[pkg.property(:ensure)])
+ /^.*(\d+\.\d+\.\d+).*$/.match(pkg.retrieve[pkg.property(:ensure)])[1]
+ end
+ rescue
+ false
+ end
+ end
+end
diff --git a/lib/facter/python_version.rb b/lib/facter/python_version.rb
new file mode 100644
index 0000000..bb9ec98
--- /dev/null
+++ b/lib/facter/python_version.rb
@@ -0,0 +1,40 @@
+# Make python versions available as facts
+# In lists default python and system python versions
+require 'puppet'
+pkg = Puppet::Type.type(:package).new(:name => "python")
+
+Facter.add("system_python_version") do
+ setcode do
+ begin
+ unless [:absent,'purged'].include?(pkg.retrieve[pkg.property(:ensure)])
+ /^(\d+\.\d+\.\d+).*$/.match(pkg.retrieve[pkg.property(:ensure)])[1]
+ end
+ rescue
+ false
+ end
+ end
+end
+
+Facter.add("python_version") do
+ has_weight 100
+ setcode do
+ begin
+ /^.*(\d+\.\d+\.\d+)$/.match(Facter::Util::Resolution.exec('python -V 2>&1'))[1]
+ rescue
+ false
+ end
+ end
+end
+
+Facter.add("python_version") do
+ has_weight 50
+ setcode do
+ begin
+ unless [:absent,'purged'].include?(pkg.retrieve[pkg.property(:ensure)])
+ /^.*(\d+\.\d+\.\d+).*$/.match(pkg.retrieve[pkg.property(:ensure)])[1]
+ end
+ rescue
+ false
+ end
+ end
+end
diff --git a/lib/facter/virtualenv_version.rb b/lib/facter/virtualenv_version.rb
new file mode 100644
index 0000000..04736ed
--- /dev/null
+++ b/lib/facter/virtualenv_version.rb
@@ -0,0 +1,27 @@
+# Make virtualenv version available as a fact
+# Works with virualenv loaded and without, pip installed and package installed
+require 'puppet'
+pkg = Puppet::Type.type(:package).new(:name => "virtualenv")
+Facter.add("virtualenv_version") do
+ has_weight 100
+ setcode do
+ begin
+ Facter::Util::Resolution.exec('virtualenv --version')
+ rescue
+ false
+ end
+ end
+end
+
+Facter.add("virtualenv_version") do
+ has_weight 50
+ setcode do
+ begin
+ unless [:absent,'purged'].include?(pkg.retrieve[pkg.property(:ensure)])
+ /^.*(\d+\.\d+\.\d+).*$/.match(pkg.retrieve[pkg.property(:ensure)])[1]
+ end
+ rescue
+ false
+ end
+ end
+end
diff --git a/manifests/config.pp b/manifests/config.pp
index 49e5230..c7196f2 100644
--- a/manifests/config.pp
+++ b/manifests/config.pp
@@ -1,3 +1,18 @@
+# == Define: python::config
+#
+# Optionally installs the gunicorn service
+#
+# === Examples
+#
+# include python::config
+#
+# === Authors
+#
+# Sergey Stankevich
+# Ashley Penney
+# Fotis Gimian
+#
+
class python::config {
Class['python::install'] -> Python::Pip <| |>
@@ -6,17 +21,19 @@ class python::config {
Python::Virtualenv <| |> -> Python::Pip <| |>
- if $python::gunicorn {
- Class['python::install'] -> Python::Gunicorn <| |>
+ if $python::manage_gunicorn {
+ if $python::gunicorn {
+ Class['python::install'] -> Python::Gunicorn <| |>
- Python::Gunicorn <| |> ~> Service['gunicorn']
+ Python::Gunicorn <| |> ~> Service['gunicorn']
- service { 'gunicorn':
- ensure => running,
- enable => true,
- hasrestart => true,
- hasstatus => false,
- pattern => '/usr/bin/gunicorn',
+ service { 'gunicorn':
+ ensure => running,
+ enable => true,
+ hasrestart => true,
+ hasstatus => false,
+ pattern => '/usr/bin/gunicorn',
+ }
}
}
diff --git a/manifests/gunicorn.pp b/manifests/gunicorn.pp
index 13f4872..159afa3 100644
--- a/manifests/gunicorn.pp
+++ b/manifests/gunicorn.pp
@@ -37,6 +37,8 @@
# dir => '/var/www/project1/current',
# bind => 'unix:/tmp/gunicorn.socket',
# environment => 'prod',
+# owner => 'www-data',
+# group => 'www-data',
# template => 'python/gunicorn.erb',
# }
#
@@ -53,6 +55,8 @@ define python::gunicorn (
$dir = false,
$bind = false,
$environment = false,
+ $owner = 'www-data',
+ $group = 'www-data',
$template = 'python/gunicorn.erb',
) {
diff --git a/manifests/init.pp b/manifests/init.pp
index 8e8de9e..65a7e66 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -7,19 +7,27 @@
# [*version*]
# Python version to install. Default: system default
#
+# [*pip*]
+# Install python-pip. Default: false
+#
# [*dev*]
# Install python-dev. Default: false
#
# [*virtualenv*]
-# Install python-virtualenv. Default: false
+# Install python-virtualenv. Default: false, also accepts 'pip' which will
+# install latest virtualenv from pip rather than package manager
#
# [*gunicorn*]
# Install Gunicorn. Default: false
#
+# [*manage_gunicorn*]
+# Allow Installation / Removal of Gunicorn. Default: true
+#
# === Examples
#
# class { 'python':
# version => 'system',
+# pip => true,
# dev => true,
# virtualenv => true,
# gunicorn => true,
@@ -30,21 +38,25 @@
# Sergey Stankevich
#
class python (
- $version = 'system',
- $dev = false,
- $virtualenv = false,
- $gunicorn = false
+ $version = 'system',
+ $pip = false,
+ $dev = false,
+ $virtualenv = false,
+ $gunicorn = false,
+ $manage_gunicorn = true,
+ $provider = undef
) {
# Module compatibility check
- $compatible = [ 'Debian', 'Ubuntu', 'CentOS', 'RedHat' ]
- if ! ($::operatingsystem in $compatible) {
+ $compatible = [ 'Debian', 'RedHat']
+ if ! ($::osfamily in $compatible) {
fail("Module is not compatible with ${::operatingsystem}")
}
- Class['python::install'] -> Class['python::config']
-
- include python::install
- include python::config
+ # Anchor pattern to contain dependencies
+ anchor { 'python::begin': } ->
+ class { 'python::install': } ->
+ class { 'python::config': } ->
+ anchor { 'python::end': }
}
diff --git a/manifests/install.pp b/manifests/install.pp
index cf0a13e..a8d7d36 100644
--- a/manifests/install.pp
+++ b/manifests/install.pp
@@ -1,36 +1,68 @@
+# == Define: python::install
+#
+# Installs core python packages
+#
+# === Examples
+#
+# include python::install
+#
+# === Authors
+#
+# Sergey Stankevich
+# Ashley Penney
+# Fotis Gimian
+#
+
class python::install {
$python = $python::version ? {
'system' => 'python',
+ 'pypy' => 'pypy',
default => "python${python::version}",
}
- $pythondev = $::operatingsystem ? {
- /(?i:RedHat|CentOS|Fedora)/ => "$python-devel",
- /(?i:Debian|Ubuntu)/ => "$python-dev"
+ $pythondev = $::osfamily ? {
+ 'RedHat' => "${python}-devel",
+ 'Debian' => "${python}-dev"
}
- package { $python: ensure => present }
-
$dev_ensure = $python::dev ? {
true => present,
default => absent,
}
- package { [ $pythondev, 'python-pip' ]: ensure => $dev_ensure }
-
- $venv_ensure = $python::virtualenv ? {
+ $pip_ensure = $python::pip ? {
true => present,
default => absent,
}
- package { 'python-virtualenv': ensure => $venv_ensure }
-
- $gunicorn_ensure = $python::gunicorn ? {
+ $venv_ensure = $python::virtualenv ? {
true => present,
default => absent,
}
- package { 'gunicorn': ensure => $gunicorn_ensure }
+ # Install latest from pip if pip is the provider
+ case $python::provider {
+ pip: {
+ package { 'virtualenv': ensure => latest, provider => pip }
+ package { 'pip': ensure => latest, provider => pip }
+ package { $pythondev: ensure => latest }
+ package { "python==${python::version}": ensure => latest, provider => pip }
+ }
+ default: {
+ package { 'python-virtualenv': ensure => $venv_ensure }
+ package { 'python-pip': ensure => $pip_ensure }
+ package { $pythondev: ensure => $dev_ensure }
+ package { $python: ensure => present }
+ }
+ }
+
+ if $python::manage_gunicorn {
+ $gunicorn_ensure = $python::gunicorn ? {
+ true => present,
+ default => absent,
+ }
+ package { 'gunicorn': ensure => $gunicorn_ensure }
+ }
}
diff --git a/manifests/pip.pp b/manifests/pip.pp
index 3a8ec1b..dd2be0d 100644
--- a/manifests/pip.pp
+++ b/manifests/pip.pp
@@ -4,6 +4,12 @@
#
# === Parameters
#
+# [*name]
+# must be unique
+#
+# [*pkgname]
+# name of the package. If pkgname is not specified, use name (title) instead.
+#
# [*ensure*]
# present|absent. Default: present
#
@@ -13,9 +19,29 @@
# [*url*]
# URL to install from. Default: none
#
+# [*owner*]
+# The owner of the virtualenv being manipulated. Default: root
+#
# [*proxy*]
# Proxy server to use for outbound connections. Default: none
#
+# [*editable*]
+# Boolean. If true the package is installed as an editable resource.
+#
+# [*environment*]
+# Additional environment variables required to install the packages. Default: none
+#
+# [*timeout*]
+# The maximum time in seconds the "pip install" command should take. Default: 1800
+#
+# [*install_args*]
+# String. Any additional installation arguments that will be supplied
+# when running pip install.
+#
+# [*uninstall args*]
+# String. Any additional arguments that will be supplied when running
+# pip uninstall.
+#
# === Examples
#
# python::pip { 'flask':
@@ -26,12 +52,21 @@
# === Authors
#
# Sergey Stankevich
+# Fotis Gimian
#
define python::pip (
- $virtualenv,
- $ensure = present,
- $url = false,
- $proxy = false
+ $pkgname = $name,
+ $ensure = present,
+ $virtualenv = 'system',
+ $url = false,
+ $owner = 'root',
+ $proxy = false,
+ $egg = false,
+ $editable = false,
+ $environment = [],
+ $install_args = '',
+ $uninstall_args = '',
+ $timeout = 1800,
) {
# Parameter validation
@@ -39,33 +74,123 @@ define python::pip (
fail('python::pip: virtualenv parameter must not be empty')
}
+ if $virtualenv == 'system' and $owner != 'root' {
+ fail('python::pip: root user must be used when virtualenv is system')
+ }
+
+ $cwd = $virtualenv ? {
+ 'system' => '/',
+ default => $virtualenv,
+ }
+
+ $pip_env = $virtualenv ? {
+ 'system' => 'pip',
+ default => "${virtualenv}/bin/pip",
+ }
+
$proxy_flag = $proxy ? {
false => '',
default => "--proxy=${proxy}",
}
- $grep_regex = $name ? {
- /==/ => "^${name}\$",
- default => "^${name}==",
+ if $editable == true {
+ $install_editable = ' -e '
+ }
+ else {
+ $install_editable = ''
+ }
+
+ #TODO: Do more robust argument checking, but below is a start
+ if ($ensure == absent) and ($install_args != '') {
+ fail('python::pip cannot provide install_args with ensure => absent')
+ }
+
+ if ($ensure == present) and ($uninstall_args != '') {
+ fail('python::pip cannot provide uninstall_args with ensure => present')
+ }
+
+ # Check if searching by explicit version.
+ if $ensure =~ /^((19|20)[0-9][0-9]-(0[1-9]|1[1-2])-([0-2][1-9]|3[0-1])|[0-9]+\.[0-9]+(\.[0-9]+)?)$/ {
+ $grep_regex = "^${pkgname}==${ensure}\$"
+ } else {
+ $grep_regex = $pkgname ? {
+ /==/ => "^${pkgname}\$",
+ default => "^${pkgname}==",
+ }
+ }
+
+ $egg_name = $egg ? {
+ false => $pkgname,
+ default => $egg
}
$source = $url ? {
- false => $name,
- default => "${url}#egg=${name}",
+ false => $pkgname,
+ default => "${url}#egg=${egg_name}",
}
+ # We need to jump through hoops to make sure we issue the correct pip command
+ # depending on wheel support and versions.
+ #
+ # Pip does not support wheels prior to version 1.4.0
+ # Pip wheels require setuptools/distribute > 0.8
+ # Python 2.6 and older does not support setuptools/distribute > 0.8
+ # Pip >= 1.5 tries to use wheels by default, even if wheel package is not
+ # installed, in this case the --no-use-wheel flag needs to be passed
+ # Versions prior to 1.5 don't support the --no-use-wheel flag
+ #
+ # To check for this we test for wheel parameter using help and then using
+ # version, this makes sure we only use wheels if they are supported and
+ # installed
+
+
case $ensure {
+ /^((19|20)[0-9][0-9]-(0[1-9]|1[1-2])-([0-2][1-9]|3[0-1])|[0-9]+\.[0-9]+(\.[0-9]+)?)$/: {
+ # Version formats as per http://guide.python-distribute.org/specification.html#standard-versioning-schemes
+ # Explicit version.
+ exec { "pip_install_${name}":
+ command => "${pip_env} wheel --help > /dev/null 2>&1 && { ${pip_env} wheel --version > /dev/null 2>&1 || wheel_support_flag='--no-use-wheel'; } ; { ${pip_env} --log ${cwd}/pip.log install ${install_args} \$wheel_support_flag ${proxy_flag} ${install_args} ${install_editable} ${source}==${ensure} || ${pip_env} --log ${cwd}/pip.log install ${install_args} ${proxy_flag} ${install_args} ${install_editable} ${source}==${ensure} ;}",
+ unless => "${pip_env} freeze | grep -i -e ${grep_regex}",
+ user => $owner,
+ environment => $environment,
+ path => ['/usr/local/bin','/usr/bin','/bin', '/usr/sbin'],
+ timeout => $timeout,
+ }
+ }
+
present: {
+ # Whatever version is available.
+ exec { "pip_install_${name}":
+ command => "${pip_env} wheel --help > /dev/null 2>&1 && { ${pip_env} wheel --version > /dev/null 2>&1 || wheel_support_flag='--no-use-wheel'; } ; { ${pip_env} --log ${cwd}/pip.log install \$wheel_support_flag ${proxy_flag} ${install_args} ${install_editable} ${source} || ${pip_env} --log ${cwd}/pip.log install ${proxy_flag} ${install_args} ${install_editable} ${source} ;}",
+ unless => "${pip_env} freeze | grep -i -e ${grep_regex}",
+ user => $owner,
+ environment => $environment,
+ path => ['/usr/local/bin','/usr/bin','/bin', '/usr/sbin'],
+ timeout => $timeout,
+ }
+ }
+
+ latest: {
+ # Latest version.
exec { "pip_install_${name}":
- command => "${virtualenv}/bin/pip install ${proxy_flag} ${source}",
- unless => "${virtualenv}/bin/pip freeze | grep -i -e ${grep_regex}",
+ command => "${pip_env} wheel --help > /dev/null 2>&1 && { ${pip_env} wheel --version > /dev/null 2>&1 || wheel_support_flag='--no-use-wheel'; } ; { ${pip_env} --log ${cwd}/pip.log install --upgrade \$wheel_support_flag ${proxy_flag} ${uninstall_args} ${install_editable} ${source} || ${pip_env} --log ${cwd}/pip.log install --upgrade ${proxy_flag} ${uninstall_args} ${install_editable} ${source} ;}",
+ unless => "${pip_env} search ${source} | grep -i INSTALLED | grep -i latest",
+ user => $owner,
+ environment => $environment,
+ path => ['/usr/local/bin','/usr/bin','/bin', '/usr/sbin'],
+ timeout => $timeout,
}
}
default: {
+ # Anti-action, uninstall.
exec { "pip_uninstall_${name}":
- command => "echo y | ${virtualenv}/bin/pip uninstall ${proxy_flag} ${name}",
- onlyif => "${virtualenv}/bin/pip freeze | grep -i -e ${grep_regex}",
+ command => "echo y | ${pip_env} uninstall ${uninstall_args} ${proxy_flag}",
+ onlyif => "${pip_env} freeze | grep -i -e ${grep_regex}",
+ user => $owner,
+ environment => $environment,
+ path => ['/usr/local/bin','/usr/bin','/bin', '/usr/sbin'],
+ timeout => $timeout,
}
}
}
diff --git a/manifests/requirements.pp b/manifests/requirements.pp
index 67d24ce..d9b6242 100644
--- a/manifests/requirements.pp
+++ b/manifests/requirements.pp
@@ -10,9 +10,31 @@
# [*virtualenv*]
# virtualenv to run pip in. Default: system-wide
#
+# [*owner*]
+# The owner of the virtualenv being manipulated. Default: root
+#
+# [*group*]
+# The group relating to the virtualenv being manipulated. Default: root
+#
# [*proxy*]
# Proxy server to use for outbound connections. Default: none
#
+# [*src*]
+# Pip --src parameter; if the requirements file contains --editable resources,
+# this parameter specifies where they will be installed. See the pip
+# documentation for more. Default: none (i.e. use the pip default).
+#
+# [*environment*]
+# Additional environment variables required to install the packages. Default: none
+#
+# [*forceupdate*]
+# Run a pip install requirements even if we don't receive an event from the
+# requirements file - Useful for when the requirements file is written as part of a
+# resource other than file (E.g vcsrepo)
+#
+# [*cwd*]
+# The directory from which to run the "pip install" command. Default: undef
+#
# === Examples
#
# python::requirements { '/var/www/project1/requirements.txt':
@@ -24,22 +46,31 @@
#
# Sergey Stankevich
# Ashley Penney
+# Fotis Gimian
#
define python::requirements (
$requirements = $name,
$virtualenv = 'system',
- $proxy = false,
$owner = 'root',
- $group = 'root'
+ $group = 'root',
+ $proxy = false,
+ $src = false,
+ $environment = [],
+ $forceupdate = false,
+ $cwd = undef,
) {
- $cwd = $virtualenv ? {
+ if $virtualenv == 'system' and ($owner != 'root' or $group != 'root') {
+ fail('python::pip: root user must be used when virtualenv is system')
+ }
+
+ $rootdir = $virtualenv ? {
'system' => '/',
- default => "${virtualenv}/bin/",
+ default => $virtualenv,
}
$pip_env = $virtualenv ? {
- 'system' => '`which pip`',
+ 'system' => 'pip',
default => "${virtualenv}/bin/pip",
}
@@ -48,7 +79,10 @@ define python::requirements (
default => "--proxy=${proxy}",
}
- $req_crc = "${requirements}.sha1"
+ $src_flag = $src ? {
+ false => '',
+ default => "--src=${src}",
+ }
# This will ensure multiple python::virtualenv definitions can share the
# the same requirements file.
@@ -58,28 +92,21 @@ define python::requirements (
mode => '0644',
owner => $owner,
group => $group,
+ audit => content,
replace => false,
content => '# Puppet will install and/or update pip packages listed here',
}
}
- # SHA1 checksum to detect changes
- exec { "python_requirements_check_${name}":
- provider => shell,
- command => "sha1sum ${requirements} > ${req_crc}",
- unless => "sha1sum -c ${req_crc}",
- user => $owner,
- require => File[$requirements],
- }
-
- exec { "python_requirements_update_${name}":
+ exec { "python_requirements${name}":
provider => shell,
- command => "${pip_env} install ${proxy_flag} -Ur ${requirements}",
- cwd => $cwd,
- refreshonly => true,
+ command => "${pip_env} --log ${rootdir}/pip.log install ${proxy_flag} ${src_flag} -r ${requirements}",
+ refreshonly => !$forceupdate,
timeout => 1800,
+ cwd => $cwd,
user => $owner,
- subscribe => Exec["python_requirements_check_${name}"],
+ subscribe => File[$requirements],
+ environment => $environment,
}
}
diff --git a/manifests/virtualenv.pp b/manifests/virtualenv.pp
index 9f9e96c..d3bc3b5 100644
--- a/manifests/virtualenv.pp
+++ b/manifests/virtualenv.pp
@@ -13,15 +13,39 @@
# [*requirements*]
# Path to pip requirements.txt file. Default: none
#
-# [*proxy*]
-# Proxy server to use for outbound connections. Default: none
-#
# [*systempkgs*]
# Copy system site-packages into virtualenv. Default: don't
+# If virtualenv version < 1.7 this flag has no effect since
+# [*venv_dir*]
+# Directory to install virtualenv to. Default: $name
#
# [*distribute*]
# Include distribute in the virtualenv. Default: true
#
+# [*index*]
+# Base URL of Python package index. Default: none (http://pypi.python.org/simple/)
+#
+# [*owner*]
+# The owner of the virtualenv being manipulated. Default: root
+#
+# [*group*]
+# The group relating to the virtualenv being manipulated. Default: root
+#
+# [*proxy*]
+# Proxy server to use for outbound connections. Default: none
+#
+# [*environment*]
+# Additional environment variables required to install the packages. Default: none
+#
+# [*path*]
+# Specifies the PATH variable. Default: [ '/bin', '/usr/bin', '/usr/sbin' ]
+#
+# [*cwd*]
+# The directory from which to run the "pip install" command. Default: undef
+#
+# [*timeout*]
+# The maximum time in seconds the "pip install" command should take. Default: 1800
+#
# === Examples
#
# python::virtualenv { '/var/www/project1':
@@ -38,25 +62,30 @@
# Sergey Stankevich
# Ashley Penney
# Marc Fournier
+# Fotis Gimian
#
define python::virtualenv (
- $ensure = present,
- $version = 'system',
- $requirements = false,
- $proxy = false,
- $systempkgs = false,
- $distribute = true,
- $owner = 'root',
- $group = 'root',
- $index = false,
+ $ensure = present,
+ $version = 'system',
+ $requirements = false,
+ $systempkgs = false,
+ $venv_dir = $name,
+ $distribute = true,
+ $index = false,
+ $owner = 'root',
+ $group = 'root',
+ $proxy = false,
+ $environment = [],
+ $path = [ '/bin', '/usr/bin', '/usr/sbin' ],
+ $cwd = undef,
+ $timeout = 1800
) {
- $venv_dir = $name
-
if $ensure == 'present' {
$python = $version ? {
'system' => 'python',
+ 'pypy' => 'pypy',
default => "python${version}",
}
@@ -70,46 +99,57 @@ define python::virtualenv (
default => "&& export http_proxy=${proxy}",
}
- $system_pkgs_flag = $systempkgs ? {
- false => '',
- default => '--system-site-packages',
+ # Virtualenv versions prior to 1.7 do not support the
+ # --system-site-packages flag, default off for prior versions
+ # Prior to version 1.7 the default was equal to --system-site-packages
+ # and the flag --no-site-packages had to be passed to do the opposite
+ if (( versioncmp($::virtualenv_version,'1.7') > 0 ) and ( $systempkgs == true )) {
+ $system_pkgs_flag = '--system-site-packages'
+ } elsif (( versioncmp($::virtualenv_version,'1.7') < 0 ) and ( $systempkgs == false )) {
+ $system_pkgs_flag = '--no-site-packages'
+ } else {
+ $system_pkgs_flag = $systempkgs ? {
+ true => '--system-site-packages',
+ false => '--no-site-packages',
+ default => fail('Invalid value for systempkgs. Boolean value is expected')
+ }
}
$distribute_pkg = $distribute ? {
true => 'distribute',
- default => '',
+ default => 'setuptools',
}
$pypi_index = $index ? {
false => '',
default => "-i ${index}",
}
+ # Python 2.6 and older does not support setuptools/distribute > 0.8 which
+ # is required for pip wheel support, pip therefor requires --no-use-wheel flag
+ # if the # pip version is more recent than 1.4.1 but using an old python or
+ # setuputils/distribute version
+ # To check for this we test for wheel parameter using help and then using
+ # version, this makes sure we only use wheels if they are supported
exec { "python_virtualenv_${venv_dir}":
- command => "mkdir -p ${venv_dir} \
- ${proxy_command} \
- && virtualenv -p `which ${python}` ${system_pkgs_flag} ${venv_dir} \
- && ${venv_dir}/bin/pip install ${pypi_index} ${proxy_flag} --upgrade ${distribute_pkg} pip",
- user => $owner,
- creates => $venv_dir,
- path => [ '/bin', '/usr/bin', '/usr/sbin' ],
- }
-
- file{$venv_dir:
- ensure => directory,
- owner => $owner,
- group => $group,
- recurse => true,
- require => Exec["python_virtualenv_${venv_dir}"],
+ command => "mkdir -p ${venv_dir} ${proxy_command} && virtualenv ${system_pkgs_flag} -p ${python} ${venv_dir} && ${venv_dir}/bin/pip wheel --help > /dev/null 2>&1 && { ${venv_dir}/bin/pip wheel --version > /dev/null 2>&1 || wheel_support_flag='--no-use-wheel'; } ; { ${venv_dir}/bin/pip --log ${venv_dir}/pip.log install ${pypi_index} ${proxy_flag} \$wheel_support_flag --upgrade pip ${distribute_pkg} || ${venv_dir}/bin/pip --log ${venv_dir}/pip.log install ${pypi_index} ${proxy_flag} --upgrade pip ${distribute_pkg} ;}",
+ user => $owner,
+ creates => "${venv_dir}/bin/activate",
+ path => $path,
+ cwd => '/tmp',
+ environment => $environment,
+ unless => "grep '^[\\t ]*VIRTUAL_ENV=[\\\\'\\\"]*${venv_dir}[\\\"\\\\'][\\t ]*$' ${venv_dir}/bin/activate", #Unless activate exists and VIRTUAL_ENV is correct we re-create the virtualenv
}
if $requirements {
exec { "python_requirements_initial_install_${requirements}_${venv_dir}":
- command => "${venv_dir}/bin/pip install ${pypi_index} ${proxy_flag} --requirement ${requirements}",
+ command => "${venv_dir}/bin/pip wheel --help > /dev/null 2>&1 && { ${venv_dir}/bin/pip wheel --version > /dev/null 2>&1 || wheel_support_flag='--no-use-wheel'; } ; ${venv_dir}/bin/pip --log ${venv_dir}/pip.log install ${pypi_index} ${proxy_flag} \$wheel_support_flag -r ${requirements}",
refreshonly => true,
- timeout => 1800,
+ timeout => $timeout,
user => $owner,
subscribe => Exec["python_virtualenv_${venv_dir}"],
+ environment => $environment,
+ cwd => $cwd
}
python::requirements { "${requirements}_${venv_dir}":
@@ -118,10 +158,10 @@ define python::virtualenv (
proxy => $proxy,
owner => $owner,
group => $group,
+ cwd => $cwd,
require => Exec["python_virtualenv_${venv_dir}"],
}
}
-
} elsif $ensure == 'absent' {
file { $venv_dir:
@@ -130,7 +170,5 @@ define python::virtualenv (
recurse => true,
purge => true,
}
-
}
-
}
diff --git a/spec/classes/python_spec.rb b/spec/classes/python_spec.rb
new file mode 100644
index 0000000..9552ce4
--- /dev/null
+++ b/spec/classes/python_spec.rb
@@ -0,0 +1,228 @@
+require_relative '../../spec_helper'
+
+describe 'python', :type => :class do
+ context "on Debian OS" do
+ let :facts do
+ {
+ :id => 'root',
+ :kernel => 'Linux',
+ :lsbdistcodename => 'squeeze',
+ :osfamily => 'Debian',
+ :operatingsystem => 'Debian',
+ :operatingsystemrelease => '6',
+ :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
+ :concat_basedir => '/dne',
+ }
+ end
+
+ it { is_expected.to contain_class("python::install") }
+ # Base debian packages.
+ it { is_expected.to contain_package("python") }
+ it { is_expected.to contain_package("python-dev") }
+ it { is_expected.to contain_package("python-pip") }
+ # Basic python packages (from pip)
+ it { is_expected.to contain_package("python-virtualenv")}
+
+ describe "with python::dev" do
+ context "true" do
+ let (:params) {{ :dev => true }}
+ it { is_expected.to contain_package("python-dev").with(
+ "ensure" => "present")
+ }
+ end
+ context "empty/default" do
+ it { is_expected.to contain_package("python-dev").with(
+ "ensure" => "absent")
+ }
+ end
+ end
+
+
+ describe "with manage_gunicorn" do
+ context "true" do
+ let (:params) {{ :manage_gunicorn => true }}
+ it { is_expected.to contain_package("gunicorn") }
+ end
+ context "empty args" do
+ #let (:params) {{ :manage_gunicorn => '' }}
+ it { is_expected.to contain_package("gunicorn") }
+ end
+ context "false" do
+ let (:params) {{ :manage_gunicorn => false }}
+ it {is_expected.not_to contain_package("gunicorn")}
+ end
+ end
+
+ describe "with python::provider" do
+ context "pip" do
+ let (:params) {{ :provider => 'pip' }}
+ it { is_expected.to contain_package("virtualenv").with(
+ "provider" => "pip"
+ )}
+ it { is_expected.to contain_package("pip").with(
+ "provider" => "pip"
+ )}
+ end
+
+ # python::provider
+ context "default" do
+ let (:params) {{ :provider => '' }}
+ it { is_expected.to contain_package("python-virtualenv")}
+ it { is_expected.to contain_package("python-pip")}
+
+ describe "with python::virtualenv" do
+ context "true" do
+ let (:params) {{
+ :provider => '',
+ :virtualenv => true
+ }}
+ it { is_expected.to contain_package("python-virtualenv").with(
+ "ensure" => "present"
+ )}
+ end
+ end
+
+ describe "with python::virtualenv" do
+ context "default/empty" do
+ let (:params) {{
+ :provider => '',
+ :virtualenv => ''
+ }}
+ it { is_expected.to contain_package("python-virtualenv").with(
+ "ensure" => "absent"
+ )}
+ end
+ end
+
+
+ end
+ end
+
+ describe "with python::dev" do
+ context "true" do
+ let (:params) {{ :dev => true }}
+ it { is_expected.to contain_package("python-dev").with(
+ "ensure" => "present")
+ }
+ end
+ context "default/empty" do
+ let (:params) {{ :dev => '' }}
+ it { is_expected.to contain_package("python-dev").with(
+ "ensure" => "absent")
+ }
+ end
+
+ end
+
+ context "on a Redhat 5 OS" do
+ let :facts do
+ {
+ :id => 'root',
+ :kernel => 'Linux',
+ :osfamily => 'RedHat',
+ :operatingsystem => 'RedHat',
+ :operatingsystemrelease => '5',
+ :concat_basedir => '/dne',
+ :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
+ }
+ end
+ it { is_expected.to contain_class("python::install") }
+ # Base debian packages.
+ it { is_expected.to contain_package("python") }
+ it { is_expected.to contain_package("python-devel") }
+ it { is_expected.to contain_package("python-pip") }
+ # Basic python packages (from pip)
+ it { is_expected.to contain_package("python-virtualenv")}
+
+ describe "with python::dev" do
+ context "true" do
+ let (:params) {{ :dev => true }}
+ it { is_expected.to contain_package("python-devel").with(
+ "ensure" => "present")
+ }
+ end
+ context "empty/default" do
+ it { is_expected.to contain_package("python-devel").with(
+ "ensure" => "absent")
+ }
+ end
+ end
+
+
+ describe "with manage_gunicorn" do
+ context "true" do
+ let (:params) {{ :manage_gunicorn => true }}
+ it { is_expected.to contain_package("gunicorn") }
+ end
+ context "empty args" do
+ #let (:params) {{ :manage_gunicorn => '' }}
+ it { is_expected.to contain_package("gunicorn") }
+ end
+ context "false" do
+ let (:params) {{ :manage_gunicorn => false }}
+ it {is_expected.not_to contain_package("gunicorn")}
+ end
+ end
+
+ describe "with python::provider" do
+ context "pip" do
+ let (:params) {{ :provider => 'pip' }}
+ it { is_expected.to contain_package("virtualenv").with(
+ "provider" => "pip"
+ )}
+ it { is_expected.to contain_package("pip").with(
+ "provider" => "pip"
+ )}
+ end
+
+ # python::provider
+ context "default" do
+ let (:params) {{ :provider => '' }}
+ it { is_expected.to contain_package("python-virtualenv")}
+ it { is_expected.to contain_package("python-pip")}
+
+ describe "with python::virtualenv" do
+ context "true" do
+ let (:params) {{
+ :provider => '',
+ :virtualenv => true
+ }}
+ it { is_expected.to contain_package("python-virtualenv").with(
+ "ensure" => "present"
+ )}
+ end
+ end
+
+ describe "with python::virtualenv" do
+ context "default/empty" do
+ let (:params) {{
+ :provider => '',
+ :virtualenv => ''
+ }}
+ it { is_expected.to contain_package("python-virtualenv").with(
+ "ensure" => "absent"
+ )}
+ end
+ end
+
+
+ end
+ end
+
+ describe "with python::dev" do
+ context "true" do
+ let (:params) {{ :dev => true }}
+ it { is_expected.to contain_package("python-devel").with(
+ "ensure" => "present")
+ }
+ end
+ context "default/empty" do
+ let (:params) {{ :dev => '' }}
+ it { is_expected.to contain_package("python-devel").with(
+ "ensure" => "absent")
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/spec/defines/requirements_spec.rb b/spec/defines/requirements_spec.rb
new file mode 100644
index 0000000..f8144f3
--- /dev/null
+++ b/spec/defines/requirements_spec.rb
@@ -0,0 +1,53 @@
+require_relative '../../spec_helper'
+
+describe 'python::requirements', :type => :define do
+ let (:title) { '/requirements.txt' }
+ context "on Debian OS" do
+ let :facts do
+ {
+ :id => 'root',
+ :kernel => 'Linux',
+ :lsbdistcodename => 'squeeze',
+ :osfamily => 'Debian',
+ :operatingsystem => 'Debian',
+ :operatingsystemrelease => '6',
+ :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
+ :concat_basedir => '/dne',
+ }
+ end
+
+ describe "requirements as" do
+ context "/requirements.txt" do
+ let (:params) {{ :requirements => "/requirements.txt" }}
+ it { is_expected.to contain_file("/requirements.txt").with(
+ "mode" => "0644"
+
+ )}
+ end
+
+ describe "with owner" do
+ context "bob:bob" do
+ let (:params) {{
+ :owner => 'bob',
+ :group => 'bob'
+ }}
+ it do
+ expect {
+ should compile
+ }.to raise_error(Puppet::Error, /root user must be used when virtualenv is system/)
+ end
+
+ end
+ end
+
+ describe "with owner" do
+ context "default" do
+ it { is_expected.to contain_file("/requirements.txt").with(
+ "owner" => "root",
+ "group" => "root"
+ )}
+ end
+ end
+ end
+ end
+end
diff --git a/spec_helper.rb b/spec_helper.rb
new file mode 100644
index 0000000..65379ee
--- /dev/null
+++ b/spec_helper.rb
@@ -0,0 +1,25 @@
+require 'puppetlabs_spec_helper/module_spec_helper'
+
+RSpec.configure do |c|
+ c.treat_symbols_as_metadata_keys_with_true_values = true
+
+ c.before :each do
+ # Ensure that we don't accidentally cache facts and environment
+ # between test cases.
+ Facter::Util::Loader.any_instance.stubs(:load_all)
+ Facter.clear
+ Facter.clear_messages
+
+ # Store any environment variables away to be restored later
+ @old_env = {}
+ ENV.each_key {|k| @old_env[k] = ENV[k]}
+
+ if ENV['STRICT_VARIABLES'] == 'yes'
+ Puppet.settings[:strict_variables]=true
+ end
+ end
+end
+
+shared_examples :compile, :compile => true do
+ it { should compile.with_all_deps }
+end
diff --git a/templates/gunicorn.erb b/templates/gunicorn.erb
index 1a96531..10f81fa 100644
--- a/templates/gunicorn.erb
+++ b/templates/gunicorn.erb
@@ -1,36 +1,36 @@
CONFIG = {
-<% if mode == 'django' -%>
+<% if @mode == 'django' -%>
'mode': 'django',
<% else -%>
'mode': 'wsgi',
<% end -%>
-<% if virtualenv -%>
+<% if @virtualenv -%>
'environment': {
-<% if environment -%>
- 'ENVIRONMENT': '<%= environment %>',
+<% if @environment -%>
+ 'ENVIRONMENT': '<%= @environment %>',
<% end -%>
- 'PYTHONPATH': '<%= virtualenv %>'
+ 'PYTHONPATH': '<%= @virtualenv %>'
},
<% end -%>
- 'working_dir': '<%= dir %>',
- 'user': 'www-data',
- 'group': 'www-data',
-<% if virtualenv -%>
- 'python': '<%= virtualenv %>/bin/python',
+ 'working_dir': '<%= @dir %>',
+ 'user': '<%= @owner %>',
+ 'group': '<%= @group %>',
+<% if @virtualenv -%>
+ 'python': '<%= @virtualenv %>/bin/python',
<% else -%>
'python': '/usr/bin/python',
<% end -%>
'args': (
-<% if !virtualenv and !bind -%>
- '--bind=unix:/tmp/gunicorn-<%= name %>.socket',
-<% elsif virtualenv and !bind -%>
- '--bind=unix:<%= virtualenv %>/<%= name %>.socket',
+<% if !@virtualenv and !@bind -%>
+ '--bind=unix:/tmp/gunicorn-<%= @name %>.socket',
+<% elsif @virtualenv and !@bind -%>
+ '--bind=unix:<%= @virtualenv %>/<%= @name %>.socket',
<% else -%>
- '--bind=<%= bind %>',
+ '--bind=<%= @bind %>',
<% end -%>
'--workers=<%= @processorcount.to_i*2 %>',
'--timeout=30',
-<% if mode != 'django' -%>
+<% if @mode != 'django' -%>
'app:app',
<% end -%>
),