Created web::install class 81/181/2
authorJosh Farwell <jfarwell@linuxfoundation.org>
Fri, 19 Jun 2015 04:26:38 +0000 (21:26 -0700)
committerJosh Farwell <jfarwell@linuxfoundation.org>
Fri, 19 Jun 2015 16:12:53 +0000 (09:12 -0700)
Mailman3::web::install creates a service user, creates needed files and
directories, and installs Postorius and Hyperkitty to a virtualenv with
their dependencies. We are installing the Django project files from
mailman-bundler and including them in the module.

Change-Id: I88eda2d7d6ffe81a0a874c16fb3b82edabe0e904
Signed-off-by: Josh Farwell <jfarwell@linuxfoundation.org>
.fixtures.yml
files/djangoproject/mailman_web/__init__.py [new file with mode: 0644]
files/djangoproject/mailman_web/production.py [new file with mode: 0644]
files/djangoproject/mailman_web/urls.py [new file with mode: 0644]
files/djangoproject/mailman_web/wsgi.py [new file with mode: 0644]
files/djangoproject/manage.py [new file with mode: 0755]
manifests/params.pp
manifests/web/install.pp
spec/classes/web__install_spec.rb [new file with mode: 0644]
spec/classes/web_spec.rb

index 1615b00..df2e0f8 100644 (file)
@@ -3,8 +3,13 @@ fixtures:
   #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}"
diff --git a/files/djangoproject/mailman_web/__init__.py b/files/djangoproject/mailman_web/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/files/djangoproject/mailman_web/production.py b/files/djangoproject/mailman_web/production.py
new file mode 100644 (file)
index 0000000..90184a9
--- /dev/null
@@ -0,0 +1,372 @@
+#-*- 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
diff --git a/files/djangoproject/mailman_web/urls.py b/files/djangoproject/mailman_web/urls.py
new file mode 100644 (file)
index 0000000..0eeb212
--- /dev/null
@@ -0,0 +1,15 @@
+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}),
+)
diff --git a/files/djangoproject/mailman_web/wsgi.py b/files/djangoproject/mailman_web/wsgi.py
new file mode 100644 (file)
index 0000000..dbb21d7
--- /dev/null
@@ -0,0 +1,14 @@
+"""
+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()
diff --git a/files/djangoproject/manage.py b/files/djangoproject/manage.py
new file mode 100755 (executable)
index 0000000..170285d
--- /dev/null
@@ -0,0 +1,10 @@
+#!/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)
index 51c4838..f9c9fee 100644 (file)
@@ -88,12 +88,15 @@ class mailman3::params {
   $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 = {
@@ -132,14 +135,23 @@ class mailman3::params {
 
   # 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,
       },
     },
   }
index 7cb55e1..d5e8bbd 100644 (file)
@@ -46,4 +46,151 @@ class mailman3::web::install (
   $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'],
+    }
+
+  }
+
 }
diff --git a/spec/classes/web__install_spec.rb b/spec/classes/web__install_spec.rb
new file mode 100644 (file)
index 0000000..2c72e6d
--- /dev/null
@@ -0,0 +1,259 @@
+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
index 422cf7a..8fc5789 100644 (file)
@@ -1,6 +1,16 @@
 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') }