ch08 samples
authorLorin Hochstein <lorin.hochstein@sendgrid.com>
Sat, 7 Feb 2015 03:32:33 +0000 (22:32 -0500)
committerLorin Hochstein <lorin.hochstein@sendgrid.com>
Sat, 7 Feb 2015 03:47:29 +0000 (22:47 -0500)
17 files changed:
.gitignore
ch08/playbooks/Vagrantfile [new file with mode: 0644]
ch08/playbooks/mezzanine-across-servers.yml [new file with mode: 0644]
ch08/playbooks/mezzanine-one-server.yml [new file with mode: 0644]
ch08/playbooks/roles/database/defaults/main.yml [new file with mode: 0644]
ch08/playbooks/roles/database/tasks/main.yml [new file with mode: 0644]
ch08/playbooks/roles/mezzanine/defaults/main.yml [new file with mode: 0644]
ch08/playbooks/roles/mezzanine/tasks/django.yml [new file with mode: 0644]
ch08/playbooks/roles/mezzanine/tasks/main.yml [new file with mode: 0644]
ch08/playbooks/roles/mezzanine/tasks/nginx.yml [new file with mode: 0644]
ch08/playbooks/roles/mezzanine/templates/gunicorn.conf.py.j2 [new file with mode: 0644]
ch08/playbooks/roles/mezzanine/templates/local_settings.py.filters.j2 [new file with mode: 0644]
ch08/playbooks/roles/mezzanine/templates/local_settings.py.j2 [new file with mode: 0644]
ch08/playbooks/roles/mezzanine/templates/nginx.conf.j2 [new file with mode: 0644]
ch08/playbooks/roles/mezzanine/templates/supervisor.conf.j2 [new file with mode: 0644]
ch08/playbooks/roles/mezzanine/vars/main.yml [new file with mode: 0644]
ch08/playbooks/secrets.yml.example [new file with mode: 0644]

index 8a7cdef..6fe3379 100644 (file)
@@ -2,3 +2,4 @@
 ch05/venv
 ch05/myproject
 ch06/playbooks/secrets.yml
+ch08/playbooks/secrets.yml
diff --git a/ch08/playbooks/Vagrantfile b/ch08/playbooks/Vagrantfile
new file mode 100644 (file)
index 0000000..a19c912
--- /dev/null
@@ -0,0 +1,53 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
+VAGRANTFILE_API_VERSION = "2"
+
+Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
+  # Use the same key for each machine
+  config.ssh.insert_key = false
+
+  config.vm.define 'db' do |db|
+
+    # Every Vagrant virtual environment requires a box to build off of.
+    db.vm.box = "ubuntu/trusty64"
+
+    # Create a private network, which allows host-only access to the machine
+    # using a specific IP.
+    db.vm.network "private_network", ip: "192.168.33.11"
+
+    # If true, then any SSH connections made will enable agent forwarding.
+    db.ssh.forward_agent = true
+
+    db.vm.provider "virtualbox" do |vb|
+      # Use VBoxManage to customize the VM. For example to change memory:
+      vb.customize ["modifyvm", :id, "--memory", "1024"]
+    end
+  end
+
+  config.vm.define 'web' do |web|
+
+    # Every Vagrant virtual environment requires a box to build off of.
+    web.vm.box = "ubuntu/trusty64"
+
+    # Create a private network, which allows host-only access to the machine
+    # using a specific IP.
+    web.vm.network "private_network", ip: "192.168.33.10"
+
+    # If true, then any SSH connections made will enable agent forwarding.
+    web.ssh.forward_agent = true
+
+    web.vm.provider "virtualbox" do |vb|
+      # Use VBoxManage to customize the VM. For example to change memory:
+      vb.customize ["modifyvm", :id, "--memory", "1024"]
+    end
+
+    web.vm.provision "ansible" do |ansible|
+      ansible.limit = 'all'
+      ansible.playbook = "mezzanine-across-servers.yml"
+    end
+
+  end
+
+end
diff --git a/ch08/playbooks/mezzanine-across-servers.yml b/ch08/playbooks/mezzanine-across-servers.yml
new file mode 100644 (file)
index 0000000..cbd10f1
--- /dev/null
@@ -0,0 +1,21 @@
+---
+- name: deploy postgres on vagrant
+  hosts: db
+  vars_files:
+    - secrets.yml
+  roles:
+    - role: database
+      database_name: "{{ mezzanine_proj_name }}"
+      database_user: "{{ mezzanine_proj_name }}"
+
+- name: deploy mezzanine on vagrant
+  hosts: web
+  vars_files:
+    - secrets.yml
+  roles:
+    - role: mezzanine
+      database_host: "{{ hostvars.db.ansible_eth1.ipv4.address }}"
+      live_hostname: 192.168.33.10.xip.io
+      domains:
+        - 192.168.33.10.xip.io
+        - www.192.168.33.10.xip.io
diff --git a/ch08/playbooks/mezzanine-one-server.yml b/ch08/playbooks/mezzanine-one-server.yml
new file mode 100644 (file)
index 0000000..eb41c10
--- /dev/null
@@ -0,0 +1,14 @@
+---
+- name: deploy mezzanine on vagrant
+  hosts: web
+  vars_files:
+    - secrets.yml
+  roles:
+    - role: database
+      database_name: "{{ mezzanine_proj_name }}"
+      database_user: "{{ mezzanine_proj_name }}"
+    - role: mezzanine
+      live_hostname: 192.168.33.10.xip.io
+      domains:
+        - 192.168.33.10.xip.io
+        - www.192.168.33.10.xip.io
diff --git a/ch08/playbooks/roles/database/defaults/main.yml b/ch08/playbooks/roles/database/defaults/main.yml
new file mode 100644 (file)
index 0000000..1d58729
--- /dev/null
@@ -0,0 +1,2 @@
+---
+database_port: 5432
diff --git a/ch08/playbooks/roles/database/tasks/main.yml b/ch08/playbooks/roles/database/tasks/main.yml
new file mode 100644 (file)
index 0000000..b13fa7e
--- /dev/null
@@ -0,0 +1,24 @@
+---
+- name: install apt packages
+  apt: pkg={{ item }} update_cache=yes cache_valid_time=3600
+  sudo: True
+  with_items:
+    - libpq-dev
+    - postgresql
+    - python-psycopg2
+- name: create a user
+  postgresql_user:
+    name: "{{ database_user }}"
+    password: "{{ db_pass }}"
+  sudo: True
+  sudo_user: postgres
+- name: create the database
+  postgresql_db:
+    name: "{{ database_name }}"
+    owner: "{{ database_user }}"
+    encoding: UTF8
+    lc_ctype: "{{ locale }}"
+    lc_collate: "{{ locale }}"
+    template: template0
+  sudo: True
+  sudo_user: postgres
diff --git a/ch08/playbooks/roles/mezzanine/defaults/main.yml b/ch08/playbooks/roles/mezzanine/defaults/main.yml
new file mode 100644 (file)
index 0000000..3c86a1b
--- /dev/null
@@ -0,0 +1,2 @@
+---
+ssl_enabled: True
diff --git a/ch08/playbooks/roles/mezzanine/tasks/django.yml b/ch08/playbooks/roles/mezzanine/tasks/django.yml
new file mode 100644 (file)
index 0000000..7cec415
--- /dev/null
@@ -0,0 +1,52 @@
+- name: check out the repository on the host
+  git: repo={{ mezzanine_repo_url }} dest={{ mezzanine_proj_path }} accept_hostkey=yes
+- name: install required python packages
+  pip: name={{ item }} virtualenv={{ mezzanine_venv_path }}
+  with_items:
+    - gunicorn
+    - setproctitle
+    - south
+    - psycopg2
+    - django-compressor
+    - python-memcached
+- name: install requirements.txt
+  pip: >
+    requirements={{ mezzanine_proj_path }}/{{ mezzanine_reqs_path }}
+    virtualenv={{ mezzanine_venv_path }}
+- name: generate the settings file
+  template: src=local_settings.py.j2 dest={{ mezzanine_proj_path }}/local_settings.py
+- name: sync the database, apply migrations, collect static content
+  django_manage:
+    command: "{{ item }}"
+    app_path: "{{ mezzanine_proj_path }}"
+    virtualenv: "{{ mezzanine_venv_path }}"
+  with_items:
+    - syncdb
+    - migrate
+    - collectstatic
+- name: set the site id
+  script: scripts/setsite.py
+  environment:
+    PATH: "{{ mezzanine_venv_path }}/bin"
+    PROJECT_DIR: "{{ mezzanine_proj_path }}"
+    WEBSITE_DOMAIN: "{{ live_hostname }}"
+- name: set the admin password
+  script: scripts/setadmin.py
+  environment:
+    PATH: "{{ mezzanine_venv_path }}/bin"
+    PROJECT_DIR: "{{ mezzanine_proj_path }}"
+    ADMIN_PASSWORD: "{{ admin_pass }}"
+- name: set the gunicorn config file
+  template: src=gunicorn.conf.py.j2 dest={{ mezzanine_proj_path }}/gunicorn.conf.py
+- name: set the supervisor config file
+  template: src=supervisor.conf.j2 dest=/etc/supervisor/conf.d/mezzanine.conf
+  sudo: True
+  notify: restart supervisor
+- name: ensure config path exists
+  file: path={{ mezzanine_conf_path }} state=directory
+  sudo: True
+  when: ssl_enabled
+- name: install poll twitter cron job
+  cron: >
+    name="poll twitter" minute="*/5" user={{ mezzanine_user }}
+    job="{{ mezzanine_manage }} poll_twitter"
diff --git a/ch08/playbooks/roles/mezzanine/tasks/main.yml b/ch08/playbooks/roles/mezzanine/tasks/main.yml
new file mode 100644 (file)
index 0000000..7ac8e3a
--- /dev/null
@@ -0,0 +1,18 @@
+---
+- name: install apt packages
+  apt: pkg={{ item }} update_cache=yes cache_valid_time=3600
+  sudo: True
+  with_items:
+    - git
+    - libjpeg-dev
+    - libpq-dev
+    - memcached
+    - nginx
+    - python-dev
+    - python-pip
+    - python-psycopg2
+    - python-setuptools
+    - python-virtualenv
+    - supervisor
+- include: django.yml
+- include: nginx.yml
diff --git a/ch08/playbooks/roles/mezzanine/tasks/nginx.yml b/ch08/playbooks/roles/mezzanine/tasks/nginx.yml
new file mode 100644 (file)
index 0000000..9e63f18
--- /dev/null
@@ -0,0 +1,24 @@
+- name: set the nginx config file
+  template: src=nginx.conf.j2 dest=/etc/nginx/sites-available/mezzanine.conf
+  notify: restart nginx
+  sudo: True
+- name: enable the nginx config file
+  file:
+    src: /etc/nginx/sites-available/mezzanine.conf
+    dest: /etc/nginx/sites-enabled/mezzanine.conf
+    state: link
+  notify: restart nginx
+  sudo: True
+- name: remove the default nginx config file
+  file: path=/etc/nginx/sites-enabled/default state=absent
+  notify: restart nginx
+  sudo: True
+- name: create ssl certificates
+  command: >
+    openssl req -new -x509 -nodes -out {{ mezzanine_proj_name }}.crt
+    -keyout {{ mezzanine_proj_name }}.key -subj '/CN={{ domains[0] }}' -days 3650
+    chdir={{ mezzanine_conf_path }}
+    creates={{ mezzanine_conf_path }}/{{ mezzanine_proj_name }}.crt
+  sudo: True
+  when: ssl_enabled
+  notify: restart nginx
diff --git a/ch08/playbooks/roles/mezzanine/templates/gunicorn.conf.py.j2 b/ch08/playbooks/roles/mezzanine/templates/gunicorn.conf.py.j2
new file mode 100644 (file)
index 0000000..77f9872
--- /dev/null
@@ -0,0 +1,7 @@
+from __future__ import unicode_literals
+import multiprocessing
+
+bind = "127.0.0.1:{{ mezzanine_gunicorn_port }}"
+workers = multiprocessing.cpu_count() * 2 + 1
+loglevel = "error"
+proc_name = "{{ mezzanine_proj_name }}"
diff --git a/ch08/playbooks/roles/mezzanine/templates/local_settings.py.filters.j2 b/ch08/playbooks/roles/mezzanine/templates/local_settings.py.filters.j2
new file mode 100644 (file)
index 0000000..69a0697
--- /dev/null
@@ -0,0 +1,43 @@
+from __future__ import unicode_literals
+
+SECRET_KEY = "{{ secret_key }}"
+NEVERCACHE_KEY = "{{ nevercache_key }}"
+ALLOWED_HOSTS = [{{ domains|surround_by_quote|join(", ") }}]
+
+DATABASES = {
+    "default": {
+        # Ends with "postgresql_psycopg2", "mysql", "sqlite3" or "oracle".
+        "ENGINE": "django.db.backends.postgresql_psycopg2",
+        # DB name or path to database file if using sqlite3.
+        "NAME": "{{ proj_name }}",
+        # Not used with sqlite3.
+        "USER": "{{ proj_name }}",
+        # Not used with sqlite3.
+        "PASSWORD": "{{ db_pass }}",
+        # Set to empty string for localhost. Not used with sqlite3.
+        "HOST": "127.0.0.1",
+        # Set to empty string for default. Not used with sqlite3.
+        "PORT": "",
+    }
+}
+
+SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTOCOL", "https")
+
+CACHE_MIDDLEWARE_SECONDS = 60
+
+CACHE_MIDDLEWARE_KEY_PREFIX = "{{ proj_name }}"
+
+CACHES = {
+    "default": {
+        "BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
+        "LOCATION": "127.0.0.1:11211",
+    }
+}
+
+SESSION_ENGINE = "django.contrib.sessions.backends.cache"
+
+TWITTER_ACCESS_TOKEN_KEY = "{{ twitter_access_token_key }}"
+TWITTER_ACCESS_TOKEN_SECRET = "{{ twitter_access_token_secret }}"
+TWITTER_CONSUMER_KEY = "{{ twitter_consumer_key }}"
+TWITTER_CONSUMER_SECRET = "{{ twitter_consumer_secret }}"
+TWITTER_DEFAULT_QUERY = "from:ansiblebook"
diff --git a/ch08/playbooks/roles/mezzanine/templates/local_settings.py.j2 b/ch08/playbooks/roles/mezzanine/templates/local_settings.py.j2
new file mode 100644 (file)
index 0000000..47cb458
--- /dev/null
@@ -0,0 +1,43 @@
+from __future__ import unicode_literals
+
+SECRET_KEY = "{{ secret_key }}"
+NEVERCACHE_KEY = "{{ nevercache_key }}"
+ALLOWED_HOSTS = [{% for domain in domains %}"{{ domain }}",{% endfor %}]
+
+DATABASES = {
+    "default": {
+        # Ends with "postgresql_psycopg2", "mysql", "sqlite3" or "oracle".
+        "ENGINE": "django.db.backends.postgresql_psycopg2",
+        # DB name or path to database file if using sqlite3.
+        "NAME": "{{ mezzanine_proj_name }}",
+        # Not used with sqlite3.
+        "USER": "{{ mezzanine_proj_name }}",
+        # Not used with sqlite3.
+        "PASSWORD": "{{ db_pass }}",
+        # Set to empty string for localhost. Not used with sqlite3.
+        "HOST": "{{ database_host | default("localhost") }}",
+        # Set to empty string for default. Not used with sqlite3.
+        "PORT": "{{ database_port }}",
+    }
+}
+
+SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTOCOL", "https")
+
+CACHE_MIDDLEWARE_SECONDS = 60
+
+CACHE_MIDDLEWARE_KEY_PREFIX = "{{ mezzanine_proj_name }}"
+
+CACHES = {
+    "default": {
+        "BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
+        "LOCATION": "127.0.0.1:11211",
+    }
+}
+
+SESSION_ENGINE = "django.contrib.sessions.backends.cache"
+
+TWITTER_ACCESS_TOKEN_KEY = "{{ twitter_access_token_key }}"
+TWITTER_ACCESS_TOKEN_SECRET = "{{ twitter_access_token_secret }}"
+TWITTER_CONSUMER_KEY = "{{ twitter_consumer_key }}"
+TWITTER_CONSUMER_SECRET = "{{ twitter_consumer_secret }}"
+TWITTER_DEFAULT_QUERY = "from:ansiblebook"
diff --git a/ch08/playbooks/roles/mezzanine/templates/nginx.conf.j2 b/ch08/playbooks/roles/mezzanine/templates/nginx.conf.j2
new file mode 100644 (file)
index 0000000..9d12843
--- /dev/null
@@ -0,0 +1,51 @@
+upstream {{ mezzanine_proj_name }} {
+    server 127.0.0.1:{{ mezzanine_gunicorn_port }};
+}
+
+server {
+
+    listen 80;
+
+    {% if ssl_enabled %}
+    listen 443 ssl;
+    {% endif %}
+    server_name {{ domains|join(", ") }};
+    client_max_body_size 10M;
+    keepalive_timeout    15;
+
+    {% if ssl_enabled %}
+    ssl_certificate      conf/{{ mezzanine_proj_name }}.crt;
+    ssl_certificate_key  conf/{{ mezzanine_proj_name }}.key;
+    ssl_session_cache    shared:SSL:10m;
+    ssl_session_timeout  10m;
+    ssl_ciphers CDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA;
+    ssl_prefer_server_ciphers on;
+    {% endif %}
+
+    location / {
+        proxy_redirect      off;
+        proxy_set_header    Host                    $host;
+        proxy_set_header    X-Real-IP               $remote_addr;
+        proxy_set_header    X-Forwarded-For         $proxy_add_x_forwarded_for;
+        proxy_set_header    X-Forwarded-Protocol    $scheme;
+        proxy_pass          http://{{ mezzanine_proj_name }};
+    }
+
+    location /static/ {
+        root            {{ mezzanine_proj_path }};
+        access_log      off;
+        log_not_found   off;
+    }
+
+    location /robots.txt {
+        root            {{ mezzanine_proj_path }}/static;
+        access_log      off;
+        log_not_found   off;
+    }
+
+    location /favicon.ico {
+        root            {{ mezzanine_proj_path }}/static/img;
+        access_log      off;
+        log_not_found   off;
+    }
+}
diff --git a/ch08/playbooks/roles/mezzanine/templates/supervisor.conf.j2 b/ch08/playbooks/roles/mezzanine/templates/supervisor.conf.j2
new file mode 100644 (file)
index 0000000..f49cffb
--- /dev/null
@@ -0,0 +1,11 @@
+[group: {{ mezzanine_proj_name }}]
+programs=gunicorn_{{ mezzanine_proj_name }}
+
+[program:gunicorn_{{ mezzanine_proj_name }}]
+command={{ mezzanine_venv_path }}/bin/gunicorn_django -c gunicorn.conf.py -p gunicorn.pid
+directory={{ mezzanine_proj_path }}
+user={{ mezzanine_user }}
+autostart=true
+autorestart=true
+redirect_stderr=true
+environment=LANG="{{ locale }}",LC_ALL="{{ locale }}",LC_LANG="{{ locale }}"
diff --git a/ch08/playbooks/roles/mezzanine/vars/main.yml b/ch08/playbooks/roles/mezzanine/vars/main.yml
new file mode 100644 (file)
index 0000000..77eabea
--- /dev/null
@@ -0,0 +1,13 @@
+---
+# vars file for mezzanine
+mezzanine_user: "{{ ansible_ssh_user }}"
+mezzanine_venv_home: "{{ ansible_env.HOME }}"
+mezzanine_venv_path: "{{ mezzanine_venv_home }}/{{ mezzanine_proj_name }}"
+mezzanine_repo_url: git@github.com:lorin/mezzanine-example.git
+mezzanine_proj_dirname: project
+mezzanine_proj_path: "{{ mezzanine_venv_path }}/{{ mezzanine_proj_dirname }}"
+mezzanine_reqs_path: requirements.txt
+mezzanine_conf_path: /etc/nginx/conf
+mezzanine_python: "{{ mezzanine_venv_path }}/bin/python"
+mezzanine_manage: "{{ mezzanine_python }} {{ mezzanine_proj_path }}/manage.py"
+mezzanine_gunicorn_port: 8000
diff --git a/ch08/playbooks/secrets.yml.example b/ch08/playbooks/secrets.yml.example
new file mode 100644 (file)
index 0000000..55bde90
--- /dev/null
@@ -0,0 +1,15 @@
+---
+db_pass: e79c9761d0b54698a83ff3f93769e309
+admin_pass: 46041386be534591ad24902bf72071B
+secret_key: b495a05c396843b6b47ac944a72c92ed
+nevercache_key: b5d87bb4e17c483093296fa321056bdc
+# You need to create a Twitter application at https://dev.twitter.com
+# in order to get the credentials required for Mezzanine's
+# twitter integration.
+#
+# See http://mezzanine.jupo.org/docs/twitter-integration.html
+# for details on Twitter integration
+twitter_access_token_key: 80b557a3a8d14cb7a2b91d60398fb8ce
+twitter_access_token_secret: 1974cf8419114bdd9d4ea3db7a210d90
+twitter_consumer_key: 1f1c627530b34bb58701ac81ac3fad51
+twitter_consumer_secret: 36515c2b60ee4ffb9d33d972a7ec350a