From: Lorin Hochstein Date: Sun, 15 Jan 2017 22:46:09 +0000 (-0800) Subject: Don't symlink roles X-Git-Url: https://git.halfball.org/?a=commitdiff_plain;h=b3c5b000929697994ed4845207db7eb971b5bc7d;p=ansiblebook.git Don't symlink roles We can't symlink roles because they need to be mounted into a container. --- diff --git a/ch13/ansible/roles/database b/ch13/ansible/roles/database deleted file mode 120000 index bfd2c38..0000000 --- a/ch13/ansible/roles/database +++ /dev/null @@ -1 +0,0 @@ -../../../ch08/playbooks/roles/database \ No newline at end of file diff --git a/ch13/ansible/roles/mezzanine b/ch13/ansible/roles/mezzanine deleted file mode 120000 index 0fb1595..0000000 --- a/ch13/ansible/roles/mezzanine +++ /dev/null @@ -1 +0,0 @@ -../../../ch08/playbooks/roles/mezzanine \ No newline at end of file diff --git a/ch13/ansible/roles/mezzanine/defaults/main.yml b/ch13/ansible/roles/mezzanine/defaults/main.yml new file mode 100644 index 0000000..1de786e --- /dev/null +++ b/ch13/ansible/roles/mezzanine/defaults/main.yml @@ -0,0 +1,2 @@ +--- +tls_enabled: True diff --git a/ch13/ansible/roles/mezzanine/handlers/main.yml b/ch13/ansible/roles/mezzanine/handlers/main.yml new file mode 100644 index 0000000..0913020 --- /dev/null +++ b/ch13/ansible/roles/mezzanine/handlers/main.yml @@ -0,0 +1,7 @@ +--- +- name: restart supervisor + supervisorctl: name=gunicorn_mezzanine state=restarted + become: True +- name: restart nginx + service: name=nginx state=restarted + become: True diff --git a/ch13/ansible/roles/mezzanine/tasks/django.yml b/ch13/ansible/roles/mezzanine/tasks/django.yml new file mode 100644 index 0000000..8a0c685 --- /dev/null +++ b/ch13/ansible/roles/mezzanine/tasks/django.yml @@ -0,0 +1,61 @@ +- name: create a logs directory + file: path="{{ ansible_env.HOME }}/logs" state=directory +- name: check out the repository on the host + git: repo={{ mezzanine_repo_url }} dest={{ mezzanine_proj_path }} accept_hostkey=yes +- name: install Python requirements globally via pip + pip: name={{ item }} state=latest + with_items: + - pip + - virtualenv + - virtualenvwrapper + become: True +- name: install required python packages + pip: name={{ item }} virtualenv={{ mezzanine_venv_path }} + with_items: + - gunicorn + - setproctitle + - 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_settings_path }}/local_settings.py +- name: apply migrations to create the database, collect static content + django_manage: + command: "{{ item }}" + app_path: "{{ mezzanine_proj_path }}" + virtualenv: "{{ mezzanine_venv_path }}" + with_items: + - migrate + - collectstatic +- name: set the site id + script: scripts/setsite.py + environment: + PATH: "{{ mezzanine_venv_path }}/bin" + PROJECT_DIR: "{{ mezzanine_proj_path }}" + PROJECT_APP: "{{ mezzanine_proj_app }}" + WEBSITE_DOMAIN: "{{ live_hostname }}" +- name: set the admin password + script: scripts/setadmin.py + environment: + PATH: "{{ mezzanine_venv_path }}/bin" + PROJECT_DIR: "{{ mezzanine_proj_path }}" + PROJECT_APP: "{{ mezzanine_proj_app }}" + 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 + become: True + notify: restart supervisor +- name: ensure config path exists + file: path={{ mezzanine_conf_path }} state=directory + become: True + when: tls_enabled +- name: install poll twitter cron job + cron: > + name="poll twitter" minute="*/5" user={{ mezzanine_user }} + job="{{ mezzanine_manage }} poll_twitter" diff --git a/ch13/ansible/roles/mezzanine/tasks/main.yml b/ch13/ansible/roles/mezzanine/tasks/main.yml new file mode 100644 index 0000000..975a15e --- /dev/null +++ b/ch13/ansible/roles/mezzanine/tasks/main.yml @@ -0,0 +1,18 @@ +--- +- name: install apt packages + apt: pkg={{ item }} update_cache=yes cache_valid_time=3600 + become: 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/ch13/ansible/roles/mezzanine/tasks/nginx.yml b/ch13/ansible/roles/mezzanine/tasks/nginx.yml new file mode 100644 index 0000000..1852181 --- /dev/null +++ b/ch13/ansible/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 + become: 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 + become: True +- name: remove the default nginx config file + file: path=/etc/nginx/sites-enabled/default state=absent + notify: restart nginx + become: 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 + become: True + when: tls_enabled + notify: restart nginx diff --git a/ch13/ansible/roles/mezzanine/templates/gunicorn.conf.py.j2 b/ch13/ansible/roles/mezzanine/templates/gunicorn.conf.py.j2 new file mode 100644 index 0000000..c12307c --- /dev/null +++ b/ch13/ansible/roles/mezzanine/templates/gunicorn.conf.py.j2 @@ -0,0 +1,8 @@ +from __future__ import unicode_literals +import multiprocessing + +bind = "unix:{{ mezzanine_proj_path }}/gunicorn.sock" +workers = {{ mezzanine_num_workers }} +errorlog = "/home/{{ mezzanine_user }}/logs/{{ mezzanine_proj_name }}_error.log" +loglevel = "error" +proc_name = "{{ mezzanine_proj_name }}" diff --git a/ch13/ansible/roles/mezzanine/templates/local_settings.py.filters.j2 b/ch13/ansible/roles/mezzanine/templates/local_settings.py.filters.j2 new file mode 100644 index 0000000..69a0697 --- /dev/null +++ b/ch13/ansible/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/ch13/ansible/roles/mezzanine/templates/local_settings.py.j2 b/ch13/ansible/roles/mezzanine/templates/local_settings.py.j2 new file mode 100644 index 0000000..47cb458 --- /dev/null +++ b/ch13/ansible/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/ch13/ansible/roles/mezzanine/templates/nginx.conf.j2 b/ch13/ansible/roles/mezzanine/templates/nginx.conf.j2 new file mode 100644 index 0000000..ed85645 --- /dev/null +++ b/ch13/ansible/roles/mezzanine/templates/nginx.conf.j2 @@ -0,0 +1,51 @@ +upstream {{ mezzanine_proj_name }} { + server unix:{{ mezzanine_proj_path }}/gunicorn.sock fail_timeout=0; +} + +server { + + listen 80; + + {% if tls_enabled %} + listen 443 ssl; + {% endif %} + server_name {{ domains|join(", ") }}; + client_max_body_size 10M; + keepalive_timeout 15; + + {% if tls_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/ch13/ansible/roles/mezzanine/templates/supervisor.conf.j2 b/ch13/ansible/roles/mezzanine/templates/supervisor.conf.j2 new file mode 100644 index 0000000..a5f766f --- /dev/null +++ b/ch13/ansible/roles/mezzanine/templates/supervisor.conf.j2 @@ -0,0 +1,9 @@ +[program:{{ mezzanine_gunicorn_procname }}] +command={{ mezzanine_venv_path }}/bin/gunicorn -c gunicorn.conf.py -p gunicorn.pid {{ mezzanine_proj_app }}.wsgi:application +directory={{ mezzanine_proj_path }} +user={{ mezzanine_user }} +autostart=true +stdout_logfile=/home/{{ mezzanine_user }}/logs/{{ mezzanine_proj_name }}_supervisor +autorestart=true +redirect_stderr=true +environment=LANG="{{ locale }}",LC_ALL="{{ locale }}",LC_LANG="{{ locale }}" diff --git a/ch13/ansible/roles/mezzanine/vars/main.yml b/ch13/ansible/roles/mezzanine/vars/main.yml new file mode 100644 index 0000000..24c0bc6 --- /dev/null +++ b/ch13/ansible/roles/mezzanine/vars/main.yml @@ -0,0 +1,14 @@ +--- +# vars file for mezzanine +mezzanine_user: "{{ ansible_user }}" +mezzanine_venv_home: "{{ ansible_env.HOME }}/.virtualenvs" +mezzanine_venv_path: "{{ mezzanine_venv_home }}/{{ mezzanine_proj_name }}" +mezzanine_repo_url: git@github.com:ansiblebook/mezzanine_example.git +mezzanine_proj_path: "{{ ansible_env.HOME }}/mezzanine/{{ mezzanine_proj_name }}" +mezzanine_settings_path: "{{ mezzanine_proj_path }}/{{ mezzanine_proj_name }}" +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_num_workers: "multiprocessing.cpu_count() * 2 + 1" +mezzanine_gunicorn_procname: gunicorn_mezzanine