#forge_modules:
# stdlib: "puppetlabs/stdlib"
repositories:
+ epel:
+ repo: "https://github.com/stahnma/puppet-module-epel.git"
+ ref: "7322b80c268087bc4b967a9a6ca29923853971f8"
firewall: "git://github.com/puppetlabs/puppetlabs-firewall.git"
- stdlib: "git://github.com/puppetlabs/puppetlabs-stdlib.git"
postgresql: "git://github.com/puppetlabs/puppetlabs-postgresql.git"
+ python: "git://github.com/stankevich/puppet-python.git"
+ stdlib: "git://github.com/puppetlabs/puppetlabs-stdlib.git"
+ uwsgi: "git://github.com/jfpdx/puppet-uwsgi.git"
symlinks:
mailman3: "#{source_dir}"
--- /dev/null
+#-*- coding: utf-8 -*-
+"""
+Django settings for HyperKitty + Postorius
+"""
+
+import os
+BASE_DIR = os.path.dirname(os.path.abspath(__file__))
+VAR_DIR = "/var/spool"
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'change-that-at-install-time'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = False
+
+TEMPLATE_DEBUG = DEBUG
+
+ADMINS = (
+ ('Mailman Admin', 'root@localhost'),
+)
+
+# Hosts/domain names that are valid for this site; required if DEBUG is False
+# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
+ALLOWED_HOSTS = ["localhost"]
+# And for BrowserID too, see
+# http://django-browserid.rtfd.org/page/user/settings.html#django.conf.settings.BROWSERID_AUDIENCES
+BROWSERID_AUDIENCES = [ "http://localhost", "http://localhost:8000" ]
+
+# Mailman API credentials
+MAILMAN_REST_SERVER = MAILMAN_API_URL = 'http://localhost:8001'
+MAILMAN_API_USER = MAILMAN_USER = 'restadmin'
+MAILMAN_API_PASS = MAILMAN_PASS = 'restpass'
+MAILMAN_ARCHIVER_KEY = 'SecretArchiverAPIKey'
+MAILMAN_ARCHIVER_FROM = ('127.0.0.1', '::1', '::ffff:127.0.0.1')
+
+# Application definition
+
+INSTALLED_APPS = (
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ #'django.contrib.sites',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ # Uncomment the next line to enable the admin:
+ 'django.contrib.admin',
+ # Uncomment the next line to enable admin documentation:
+ # 'django.contrib.admindocs',
+ 'hyperkitty',
+ 'social.apps.django_app.default',
+ 'rest_framework',
+ 'django_gravatar',
+ 'crispy_forms',
+ 'paintstore',
+ 'compressor',
+ 'django_browserid',
+ 'haystack',
+ 'django_extensions',
+ 'postorius',
+)
+
+
+MIDDLEWARE_CLASSES = (
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ # Uncomment the next line for simple clickjacking protection:
+ # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+ 'hyperkitty.middleware.SSLRedirect',
+ 'hyperkitty.middleware.TimezoneMiddleware',
+)
+
+ROOT_URLCONF = 'mailman_web.urls'
+
+# CSS theme for postorius
+MAILMAN_THEME = "default"
+
+
+# Database
+# https://docs.djangoproject.com/en/1.6/ref/settings/#databases
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.postgresql_psycopg2', # Last part is one of 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
+ 'NAME': 'mailmanweb', # Example, change as needed
+ 'USER': 'mailmanweb', # Example, change as needed
+ 'PASSWORD': 'change-this-password', # Example, obviously
+ 'HOST': '127.0.0.1', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
+ 'PORT': '', # Set to empty string for default.
+ }
+}
+
+
+# If you're behind a proxy, use the X-Forwarded-Host header
+# See https://docs.djangoproject.com/en/1.5/ref/settings/#use-x-forwarded-host
+#USE_X_FORWARDED_HOST = True
+# And if your proxy does your SSL encoding for you, set SECURE_PROXY_SSL_HEADER
+# see https://docs.djangoproject.com/en/1.5/ref/settings/#secure-proxy-ssl-header
+#SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
+
+# Internationalization
+# https://docs.djangoproject.com/en/1.6/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'America/Chicago'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/1.6/howto/static-files/
+
+# Absolute filesystem path to the directory that will hold user-uploaded files.
+# Example: "/var/www/example.com/media/"
+MEDIA_ROOT = ''
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash.
+# Examples: "http://example.com/media/", "http://media.example.com/"
+MEDIA_URL = ''
+
+# Absolute path to the directory static files should be collected to.
+# Don't put anything in this directory yourself; store your static files
+# in apps' "static/" subdirectories and in STATICFILES_DIRS.
+# Example: "/var/www/example.com/static/"
+#STATIC_ROOT = ''
+STATIC_ROOT = os.path.join(VAR_DIR, "mailman-web", "static")
+
+# URL prefix for static files.
+# Example: "http://example.com/static/", "http://static.example.com/"
+STATIC_URL = '/static/'
+
+# Additional locations of static files
+STATICFILES_DIRS = (
+ # Put strings here, like "/home/html/static" or "C:/www/django/static".
+ # Always use forward slashes, even on Windows.
+ # Don't forget to use absolute paths, not relative paths.
+)
+
+# List of finder classes that know how to find static files in
+# various locations.
+STATICFILES_FINDERS = (
+ 'django.contrib.staticfiles.finders.FileSystemFinder',
+ 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
+# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
+ 'compressor.finders.CompressorFinder',
+)
+
+
+TEMPLATE_CONTEXT_PROCESSORS = (
+ "django.contrib.auth.context_processors.auth",
+ "django.contrib.messages.context_processors.messages",
+ "django.core.context_processors.debug",
+ "django.core.context_processors.i18n",
+ "django.core.context_processors.media",
+ "django.core.context_processors.static",
+ "django.core.context_processors.csrf",
+ "django.core.context_processors.request",
+ "django.core.context_processors.tz",
+ "django.contrib.messages.context_processors.messages",
+ "social.apps.django_app.context_processors.backends",
+ "social.apps.django_app.context_processors.login_redirect",
+ "hyperkitty.context_processors.export_settings",
+ "hyperkitty.context_processors.postorius_info",
+ "postorius.context_processors.postorius",
+)
+
+TEMPLATE_DIRS = (
+ # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
+ # Always use forward slashes, even on Windows.
+ # Don't forget to use absolute paths, not relative paths.
+)
+
+# Django 1.6+ defaults to a JSON serializer, but it won't work with django-openid, see
+# https://bugs.launchpad.net/django-openid-auth/+bug/1252826
+SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
+
+
+LOGIN_URL = '/archives/accounts/login/'
+LOGIN_REDIRECT_URL = '/archives/'
+LOGIN_ERROR_URL = '/archives/accounts/login/'
+
+BROWSERID_USERNAME_ALGO = lambda email: email # Use the email as identifier
+BROWSERID_VERIFY_CLASS = "django_browserid.views.Verify"
+
+
+
+#
+# Social auth
+#
+
+AUTHENTICATION_BACKENDS = (
+ #'social.backends.open_id.OpenIdAuth',
+ # http://python-social-auth.readthedocs.org/en/latest/backends/google.html
+ 'social.backends.google.GoogleOpenId',
+ #'social.backends.google.GoogleOAuth2',
+ #'social.backends.twitter.TwitterOAuth',
+ 'social.backends.yahoo.YahooOpenId',
+ 'django_browserid.auth.BrowserIDBackend',
+ 'django.contrib.auth.backends.ModelBackend',
+)
+
+SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL = True
+
+# http://python-social-auth.readthedocs.org/en/latest/pipeline.html#authentication-pipeline
+SOCIAL_AUTH_PIPELINE = (
+ 'social.pipeline.social_auth.social_details',
+ 'social.pipeline.social_auth.social_uid',
+ 'social.pipeline.social_auth.auth_allowed',
+ 'social.pipeline.social_auth.social_user',
+ 'social.pipeline.user.get_username',
+ # Associates the current social details with another user account with
+ # a similar email address. Disabled by default, enable with care:
+ # http://python-social-auth.readthedocs.org/en/latest/use_cases.html#associate-users-by-email
+ #'social.pipeline.social_auth.associate_by_email',
+ 'social.pipeline.user.create_user',
+ 'social.pipeline.social_auth.associate_user',
+ 'social.pipeline.social_auth.load_extra_data',
+ 'social.pipeline.user.user_details',
+)
+
+
+
+#
+# Gravatar
+# https://github.com/twaddington/django-gravatar
+#
+# Gravatar base url.
+#GRAVATAR_URL = 'http://cdn.libravatar.org/'
+# Gravatar base secure https url.
+#GRAVATAR_SECURE_URL = 'https://seccdn.libravatar.org/'
+# Gravatar size in pixels.
+#GRAVATAR_DEFAULT_SIZE = '80'
+# An image url or one of the following: 'mm', 'identicon', 'monsterid', 'wavatar', 'retro'.
+#GRAVATAR_DEFAULT_IMAGE = 'mm'
+# One of the following: 'g', 'pg', 'r', 'x'.
+#GRAVATAR_DEFAULT_RATING = 'g'
+# True to use https by default, False for plain http.
+#GRAVATAR_DEFAULT_SECURE = True
+
+#
+# django-compressor
+# https://pypi.python.org/pypi/django_compressor
+#
+COMPRESS_PRECOMPILERS = (
+ ('text/less', 'lessc {infile} {outfile}'),
+)
+COMPRESS_OFFLINE = True
+# needed for debug mode
+#INTERNAL_IPS = ('127.0.0.1',)
+
+# Django Crispy Forms
+CRISPY_TEMPLATE_PACK = 'bootstrap3'
+CRISPY_FAIL_SILENTLY = not DEBUG
+
+
+#
+# Full-text search engine
+#
+HAYSTACK_CONNECTIONS = {
+ 'default': {
+ 'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
+ 'PATH': os.path.join(VAR_DIR, "mailman-web", "fulltext_index"),
+ },
+}
+
+
+# A sample logging configuration. The only tangible logging
+# performed by this configuration is to send an email to
+# the site admins on every HTTP 500 error when DEBUG=False.
+# See http://docs.djangoproject.com/en/dev/topics/logging for
+# more details on how to customize your logging configuration.
+LOGGING = {
+ 'version': 1,
+ 'disable_existing_loggers': False,
+ 'filters': {
+ 'require_debug_false': {
+ '()': 'django.utils.log.RequireDebugFalse'
+ }
+ },
+ 'handlers': {
+ 'mail_admins': {
+ 'level': 'ERROR',
+ 'filters': ['require_debug_false'],
+ 'class': 'django.utils.log.AdminEmailHandler'
+ },
+ 'file':{
+ 'level': 'INFO',
+ #'class': 'logging.handlers.RotatingFileHandler',
+ 'class': 'logging.handlers.WatchedFileHandler',
+ 'filename': '/var/log/mailman-web/mailman-web.log',
+ 'formatter': 'verbose',
+ },
+ },
+ 'loggers': {
+ #'django.request': {
+ # 'handlers': ['mail_admins'],
+ # 'level': 'ERROR',
+ # 'propagate': True,
+ #},
+ 'django.request': {
+ 'handlers': ['file'],
+ 'level': 'ERROR',
+ 'propagate': True,
+ },
+ 'django': {
+ 'handlers': ['file'],
+ 'level': 'ERROR',
+ 'propagate': True,
+ },
+ 'hyperkitty': {
+ 'handlers': ['file'],
+ 'level': 'INFO',
+ 'propagate': True,
+ },
+ },
+ 'formatters': {
+ 'verbose': {
+ 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
+ },
+ 'simple': {
+ 'format': '%(levelname)s %(message)s'
+ },
+ },
+ 'root': {
+ 'handlers': ['file'],
+ 'level': 'INFO',
+ },
+}
+
+
+## Cache: use the local memcached server
+#CACHES = {
+# 'default': {
+# 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
+# 'LOCATION': '127.0.0.1:11211',
+# }
+#}
+
+
+
+#
+# HyperKitty-specific
+#
+
+APP_NAME = 'Mailing-list archives'
+
+# Allow authentication with the internal user database?
+# By default, only a login through Persona or your email provider is allowed.
+USE_INTERNAL_AUTH = False
+
+# Use SSL when logged in
+USE_SSL = True
+
+# Only display mailing-lists from the same virtual host as the webserver
+FILTER_VHOST = False
+
+# This is for development purposes
+USE_MOCKUPS = False
+
+
+try:
+ from settings_local import *
+except ImportError:
+ pass
--- /dev/null
+from django.conf.urls import patterns, include, url
+from django.core.urlresolvers import reverse_lazy
+from django.views.generic import RedirectView
+
+# Comment the next two lines to disable the admin:
+from django.contrib import admin
+admin.autodiscover()
+
+urlpatterns = patterns('',
+ url(r'^$', RedirectView.as_view(url=reverse_lazy('hyperkitty.views.index.index'))),
+ url(r'^mailman3/', include('postorius.urls')),
+ url(r'^archives/', include('hyperkitty.urls')),
+ url(r'', include('social.apps.django_app.urls', namespace='social'), {"SSL": True}),
+ url(r'', include('django_browserid.urls'), {"SSL": True}),
+)
--- /dev/null
+"""
+WSGI config for mailman-web project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/
+"""
+
+# Set the DJANGO_SETTINGS_MODULE environnement variable to the python path to
+# your settings module (development or production)
+
+from django.core.wsgi import get_wsgi_application
+application = get_wsgi_application()
--- /dev/null
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mailman_web.settings")
+
+ from django.core.management import execute_from_command_line
+
+ execute_from_command_line(sys.argv)
$web_user = 'mailman3-web'
$web_homedir = '/opt/mailman3-web'
- $web_vardir = '/opt/mailman3-web/var'
- $web_staticdir = '/opt/mailman3-web/var/static'
+ $web_logfile = '/opt/mailman3-web/mailman3-web.log'
+ $web_vardir = '/opt/mailman3-web/data'
+ $web_staticdir = '/opt/mailman3-web/static'
$web_security_key = 'GENERATE'
$web_browserid_audiences = [ 'http://localhost:8000', 'http://127.0.0.1:8000' ]
$web_database_engine = 'django.db.backends.sqlite3'
- $web_database_name = "os.path.join(VAR_DIR, 'mailman-web', 'mailman-web.sqlite')"
+ $web_database_name = "os.path.join(VAR_DIR, 'mailman-web.sqlite')"
+ $web_haystack_engine = 'haystack.backends.whoosh_backend.WhooshEngine'
+ $web_haystack_path = "os.path.join(VAR_DIR, 'fulltext_index')"
# Mailman Core default options hashes
$core_default_allowed_hosts = {
# Web options hashes
$web_default_options = {
- 'VAR_DIR' => $mailman3::params::web_vardir,
- 'SECURITY_KEY' => $mailman3::params::web_security_key,
- 'BROWSERID_AUDIENCES' => $mailman3::params::web_browserid_audiences,
- 'STATIC_ROOT' => $mailman3::params::web_staticdir,
- 'DATABASES' => {
+ 'paths' => {
+ 'var_dir' => $mailman3::params::web_vardir,
+ 'static_dir' => $mailman3::params::web_staticdir,
+ 'log_file' => $mailman3::params::web_logfile,
+ },
+ 'security_key' => $mailman3::params::web_security_key,
+ 'browserid_audiences' => $mailman3::params::web_browserid_audiences,
+ 'databases' => {
'default' => {
- 'ENGINE' => $mailman3::params::web_database_engine,
- 'NAME' => $mailman3::params::web_database_name,
+ 'engine' => $mailman3::params::web_database_engine,
+ 'name' => $mailman3::params::web_database_name,
+ },
+ },
+ 'haystack_connections' => {
+ 'default' => {
+ 'engine' => $mailman3::params::web_haystack_engine,
+ 'path' => $mailman3::params::web_haystack_path,
},
},
}
$web_homedir,
$web_user,
) {
+ validate_string($django_version)
+ validate_string($hyperkitty_version)
+ validate_bool($install_web)
+ validate_bool($manage_django_packages)
+ validate_bool($manage_webserver)
+ validate_hash($options)
+ validate_string($postorius_version)
+ validate_absolute_path($web_homedir)
+ validate_string($web_user)
+
+ # install web server if we are managing web server
+ if ($manage_webserver) {
+ include '::uwsgi'
+ }
+
+ # pulls path out of config data into variables we can use
+ # if we don't have these keys defined, something is wrong
+ if has_key($options, 'paths') {
+
+ if has_key($options['paths'], 'var_dir') {
+ validate_absolute_path($options['paths']['var_dir'])
+ $web_vardir = $options['paths']['var_dir']
+ }
+ else { fail "No valid var_dir in options['paths']" }
+
+ if has_key($options['paths'], 'static_dir') {
+ validate_absolute_path($options['paths']['static_dir'])
+ $web_staticdir = $options['paths']['static_dir']
+ }
+ else { fail "No valid static_dir in options['paths']" }
+
+ if has_key($options['paths'], 'log_file') {
+ validate_absolute_path($options['paths']['log_file'])
+ $web_logfile = $options['paths']['log_file']
+ }
+ else { fail "No valid log_file in options['paths']" }
+
+ }
+ else { fail "No valid 'paths' section in options hash" }
+
+
+ if ($install_web) {
+
+ # include python class for pip and virtualenv
+ include ::python
+
+ # create service user
+ user { $web_user:
+ ensure => present,
+ comment => 'Mailman3 Web Service User',
+ home => $web_homedir,
+ managehome => true,
+ shell => '/bin/bash',
+ system => true,
+ }
+
+ # create needed dirs and files from config data
+ file { [
+ $web_vardir,
+ $web_staticdir,
+ $web_homedir,
+ ]:
+ ensure => directory,
+ owner => $web_user,
+ group => $web_user,
+ require => User[$web_user],
+ }
+
+ file { $web_logfile:
+ ensure => file,
+ owner => $web_user,
+ group => $web_user,
+ require => User[$web_user],
+ }
+
+ # install django production project files from mailman-bundler
+ file { "${web_homedir}/djangoproject":
+ ensure => directory,
+ owner => $web_user,
+ group => $web_user,
+ source => 'puppet:///modules/mailman3/djangoproject',
+ recurse => remote,
+ require => User[$web_user],
+ }
+
+ # create virtualenv
+ python::virtualenv { "${web_homedir}/virtualenv":
+ ensure => present,
+ version => 'system',
+ systempkgs => true,
+ owner => $web_user,
+ group => $web_user,
+ cwd => "${web_homedir}/virtualenv",
+ timeout => 0,
+ require => [
+ User[$web_user],
+ Class['::python'],
+ ],
+ }
+
+ if ($manage_django_packages) {
+ python::pip { 'Django':
+ ensure => $django_version,
+ virtualenv => "${web_homedir}/virtualenv",
+ before => [
+ Python::Pip['postorius'],
+ Python::Pip['hyperkitty'],
+ ],
+ }
+ }
+ else {
+ warning "If Django has not already been installed in global site-packages, \
+Pip will install it as a dependency automatically."
+ }
+
+ # install mailman3-web packages
+ # pip resources autorequire their virtualenvs
+ python::pip { 'postorius':
+ ensure => $postorius_version,
+ virtualenv => "${web_homedir}/virtualenv",
+ }
+
+ python::pip { 'hyperkitty':
+ ensure => $hyperkitty_version,
+ virtualenv => "${web_homedir}/virtualenv",
+ }
+
+ # TODO: should figure out based on options whether to install these deps
+ python::pip { 'whoosh':
+ ensure => present,
+ virtualenv => "${web_homedir}/virtualenv",
+ }
+
+ python::pip { 'beautifulsoup':
+ ensure => present,
+ virtualenv => "${web_homedir}/virtualenv",
+ }
+
+ include mailman3::repo
+
+ package { 'nodejs-less':
+ ensure => installed,
+ require => Class['mailman3::repo'],
+ }
+
+ }
+
}
--- /dev/null
+require 'spec_helper'
+
+describe 'mailman3::web::install', :type => :class do
+ # uwsgi class freaks out on my machine unless we overwrite facts.
+ # We're pretending to be Debian to avoid rspec errors originating from the
+ # epel class, which is included by the python class we are including.
+ let(:facts) { {
+ :fdqn => 'my.test.com',
+ :ipaddress => '10.0.0.42',
+ :osfamily => 'Debian',
+ :operatingsystem => '8.0',
+ } }
+
+
+
+ # No default params, so we should fail with 'must pass' if empty
+ context 'with defaults for all parameters' do
+ let(:params) {{}}
+
+ it do
+ expect {
+ should compile
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError,
+ /Must pass /)
+ end
+ end
+
+ context 'with good defaults for all parameters' do
+
+ let(:params) {
+ {
+ 'django_version' => '1.7',
+ 'hyperkitty_version' => 'present',
+ 'install_web' => true,
+ 'manage_django_packages' => true,
+ 'manage_webserver' => true,
+ 'postorius_version' => 'present',
+ 'web_homedir' => '/opt/mailman3-web',
+ 'web_user' => 'mailman3-web',
+ 'options' => {
+ 'paths' => {
+ 'var_dir' => '/opt/mailman3-web/data',
+ 'static_dir' => '/opt/mailman3-web/static',
+ 'log_file' => '/opt/mailman3-web/mailman3-web.log',
+ },
+ },
+ }
+ }
+
+ it { is_expected.to contain_class('uwsgi') }
+ it { is_expected.to contain_class('python') }
+ it { is_expected.to contain_class('mailman3::repo') }
+
+ it { is_expected.to contain_user('mailman3-web').with(
+ 'home' => '/opt/mailman3-web',
+ ) }
+
+ it { is_expected.to contain_file('/opt/mailman3-web/data').with(
+ 'owner' => 'mailman3-web',
+ 'group' => 'mailman3-web',
+ ).that_requires('User[mailman3-web]') }
+
+ it { is_expected.to contain_file('/opt/mailman3-web/static').with(
+ 'owner' => 'mailman3-web',
+ 'group' => 'mailman3-web',
+ ).that_requires('User[mailman3-web]') }
+
+ it { is_expected.to contain_file('/opt/mailman3-web/mailman3-web.log').with(
+ 'owner' => 'mailman3-web',
+ 'group' => 'mailman3-web',
+ ).that_requires('User[mailman3-web]') }
+
+ it { is_expected.to contain_file('/opt/mailman3-web/djangoproject').with(
+ 'owner' => 'mailman3-web',
+ 'group' => 'mailman3-web',
+ ).that_requires('User[mailman3-web]') }
+
+ it { is_expected.to contain_python__virtualenv('/opt/mailman3-web/virtualenv').with(
+ 'owner' => 'mailman3-web',
+ 'group' => 'mailman3-web',
+ 'cwd' => '/opt/mailman3-web/virtualenv',
+ ).that_requires([ 'User[mailman3-web]', 'Class[python]' ] ) }
+
+ it { is_expected.to contain_python__pip('Django').with(
+ 'ensure' => '1.7',
+ 'virtualenv' => '/opt/mailman3-web/virtualenv',
+ ) }
+
+ it { is_expected.to contain_python__pip('postorius').with(
+ 'ensure' => 'present',
+ 'virtualenv' => '/opt/mailman3-web/virtualenv',
+ ) }
+
+ it { is_expected.to contain_python__pip('hyperkitty').with(
+ 'ensure' => 'present',
+ 'virtualenv' => '/opt/mailman3-web/virtualenv',
+ ) }
+
+ it { is_expected.to contain_python__pip('whoosh').with(
+ 'ensure' => 'present',
+ 'virtualenv' => '/opt/mailman3-web/virtualenv',
+ ) }
+
+ it { is_expected.to contain_python__pip('beautifulsoup').with(
+ 'ensure' => 'present',
+ 'virtualenv' => '/opt/mailman3-web/virtualenv',
+ ) }
+
+ it { is_expected.to contain_class('mailman3::repo') }
+
+ it { is_expected.to contain_package('nodejs-less') }
+
+ end
+
+ context 'with install_web flag set to false' do
+
+ let(:params) {
+ {
+ 'django_version' => '',
+ 'hyperkitty_version' => '',
+ 'install_web' => false,
+ 'manage_django_packages' => true,
+ 'manage_webserver' => true,
+ 'postorius_version' => '',
+ 'web_homedir' => '/',
+ 'web_user' => 'test',
+ 'options' => {
+ 'paths' => {
+ 'var_dir' => '/',
+ 'static_dir' => '/',
+ 'log_file' => '/',
+ },
+ },
+ }
+ }
+
+ it { is_expected.to contain_class('uwsgi') }
+ it { is_expected.to_not contain_package('nodejs-less') }
+ it { is_expected.to_not contain_class('mailman3::repo') }
+ it { is_expected.to_not contain_class('python') }
+ it { is_expected.to_not contain_user('test') }
+ it { is_expected.to_not contain_file('/') }
+ it { is_expected.to_not contain_file('//djangoproject') }
+ it { is_expected.to_not contain_python__virtualenv('//virtualenv') }
+ it { is_expected.to_not contain_python__pip('Django') }
+ it { is_expected.to_not contain_python__pip('postorius') }
+ it { is_expected.to_not contain_python__pip('hyperkitty') }
+ it { is_expected.to_not contain_python__pip('whoosh') }
+ it { is_expected.to_not contain_python__pip('beautifulsoup') }
+
+ end
+
+ context 'with manage flags set to false' do
+
+ let(:params) {
+ {
+ 'django_version' => '1.7',
+ 'hyperkitty_version' => 'present',
+ 'install_web' => true,
+ 'manage_django_packages' => false,
+ 'manage_webserver' => false,
+ 'postorius_version' => 'present',
+ 'web_homedir' => '/opt/mailman3-web',
+ 'web_user' => 'mailman3-web',
+ 'options' => {
+ 'paths' => {
+ 'var_dir' => '/opt/mailman3-web/data',
+ 'static_dir' => '/opt/mailman3-web/static',
+ 'log_file' => '/opt/mailman3-web/mailman3-web.log',
+ },
+ },
+ }
+ }
+
+ it { is_expected.to_not contain_class('uwsgi') }
+ it { is_expected.to_not contain_python__pip('Django') }
+
+ it { is_expected.to contain_python__pip('postorius') }
+
+ end
+
+ context 'with bad values for paths' do
+
+ let(:params) {
+ {
+ 'django_version' => '1.7',
+ 'hyperkitty_version' => 'present',
+ 'install_web' => true,
+ 'manage_django_packages' => false,
+ 'manage_webserver' => false,
+ 'postorius_version' => 'present',
+ 'web_homedir' => '/opt/mailman3-web',
+ 'web_user' => 'mailman3-web',
+ 'options' => {
+ 'paths' => {
+ 'var_dir' => 'not a path',
+ 'static_dir' => 'not a path',
+ 'log_file' => 'not a path',
+ },
+ },
+ }
+ }
+
+ it do
+ expect {
+ should compile
+ }.to raise_error(/"not a path" is not an absolute path. /)
+ end
+ end
+
+ context 'with no keys in paths hash' do
+
+ let(:params) {
+ {
+ 'django_version' => '1.7',
+ 'hyperkitty_version' => 'present',
+ 'install_web' => true,
+ 'manage_django_packages' => false,
+ 'manage_webserver' => false,
+ 'postorius_version' => 'present',
+ 'web_homedir' => '/opt/mailman3-web',
+ 'web_user' => 'mailman3-web',
+ 'options' => {
+ 'paths' => {},
+ },
+ }
+ }
+
+ it do
+ expect {
+ should compile
+ }.to raise_error(/No valid var_dir /)
+ end
+ end
+
+ context 'with no keys in options hash' do
+
+ let(:params) {
+ {
+ 'django_version' => '1.7',
+ 'hyperkitty_version' => 'present',
+ 'install_web' => true,
+ 'manage_django_packages' => false,
+ 'manage_webserver' => false,
+ 'postorius_version' => 'present',
+ 'web_homedir' => '/opt/mailman3-web',
+ 'web_user' => 'mailman3-web',
+ 'options' => {},
+ }
+ }
+
+ it do
+ expect {
+ should compile
+ }.to raise_error(/No valid 'paths' /)
+ end
+ end
+
+end
require 'spec_helper'
describe 'mailman3::web', :type => :class do
+ # uwsgi class freaks out on my machine unless we overwrite facts.
+
+ # We're pretending to be Debian to avoid rspec failures from epel module,
+ # which is a dependency of the python module we're using.
+ let(:facts) { {
+ :fdqn => 'my.test.com',
+ :ipaddress => '10.0.0.42',
+ :osfamily => 'Debian',
+ :operatingsystem => '8.0',
+ } }
context 'with defaults for all parameters' do
it { is_expected.to contain_class('mailman3::web') }