From: Lorin Hochstein Date: Sat, 7 Feb 2015 03:32:33 +0000 (-0500) Subject: ch08 samples X-Git-Url: https://git.halfball.org/?a=commitdiff_plain;h=5fb83be058d40e8084325e0a7d7fe6945cc2390f;p=ansiblebook.git ch08 samples --- diff --git a/.gitignore b/.gitignore index 8a7cdef..6fe3379 100644 --- a/.gitignore +++ b/.gitignore @@ -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 index 0000000..a19c912 --- /dev/null +++ b/ch08/playbooks/Vagrantfile @@ -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 index 0000000..cbd10f1 --- /dev/null +++ b/ch08/playbooks/mezzanine-across-servers.yml @@ -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 index 0000000..eb41c10 --- /dev/null +++ b/ch08/playbooks/mezzanine-one-server.yml @@ -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 index 0000000..1d58729 --- /dev/null +++ b/ch08/playbooks/roles/database/defaults/main.yml @@ -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 index 0000000..b13fa7e --- /dev/null +++ b/ch08/playbooks/roles/database/tasks/main.yml @@ -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 index 0000000..3c86a1b --- /dev/null +++ b/ch08/playbooks/roles/mezzanine/defaults/main.yml @@ -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 index 0000000..7cec415 --- /dev/null +++ b/ch08/playbooks/roles/mezzanine/tasks/django.yml @@ -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 index 0000000..7ac8e3a --- /dev/null +++ b/ch08/playbooks/roles/mezzanine/tasks/main.yml @@ -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 index 0000000..9e63f18 --- /dev/null +++ b/ch08/playbooks/roles/mezzanine/tasks/nginx.yml @@ -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 index 0000000..77f9872 --- /dev/null +++ b/ch08/playbooks/roles/mezzanine/templates/gunicorn.conf.py.j2 @@ -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 index 0000000..69a0697 --- /dev/null +++ b/ch08/playbooks/roles/mezzanine/templates/local_settings.py.filters.j2 @@ -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 index 0000000..47cb458 --- /dev/null +++ b/ch08/playbooks/roles/mezzanine/templates/local_settings.py.j2 @@ -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 index 0000000..9d12843 --- /dev/null +++ b/ch08/playbooks/roles/mezzanine/templates/nginx.conf.j2 @@ -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 index 0000000..f49cffb --- /dev/null +++ b/ch08/playbooks/roles/mezzanine/templates/supervisor.conf.j2 @@ -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 index 0000000..77eabea --- /dev/null +++ b/ch08/playbooks/roles/mezzanine/vars/main.yml @@ -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 index 0000000..55bde90 --- /dev/null +++ b/ch08/playbooks/secrets.yml.example @@ -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