Finished provision

This commit is contained in:
Felipe Martín 2015-06-15 22:17:07 +02:00
parent 29ed348886
commit 6e94220d95
53 changed files with 577 additions and 60 deletions

2
Vagrantfile vendored
View File

@ -4,7 +4,7 @@
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.define "globalwishlist-backend" do |web|
config.vm.define "amiibofindr-web" do |web|
web.vm.box = "ubuntu/trusty64"
#web.vm.network "private_network", type: "dhcp"

View File

@ -0,0 +1,14 @@
# coding: utf-8
from .base import *
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'amiibofindr',
'USER': 'vagrant',
'PASS': 'vagrant',
'HOST': '127.0.0.1',
}
}

49
deploy.py Normal file
View File

@ -0,0 +1,49 @@
# coding: utf-8
# 3rd party
import click
from fabric.api import local
@click.command()
@click.option('--branch', '-b', default='stable',
help='Branch to git clone from')
@click.option('--inventory', '-i', default='hosts',
help='Inventory file for ansible to use')
@click.option('--host', '-h', default=None,
help='Host to deploy to')
@click.option('--tag', '-t', default='deploy',
help='Ansible tags to run')
@click.option('--tasks', count=True,
help='List tasks instead of executing them')
@click.option('--hosts', count=True,
help='List hosts instead of executing tasks')
@click.option('--verbose', count=True,
help='Appends -vvvv to ansible')
def deploy(branch, inventory, host, tag, tasks, hosts, verbose):
cmd = 'ansible-playbook -i provision/{}'.format(inventory)
if host:
cmd += ' -l {}'.format(host)
cmd += ' -t {}'.format(tag)
if tasks:
cmd += ' --list-tasks'
if hosts:
cmd += ' --list-hosts'
cmd += ' -e git_branch={}'.format(branch)
cmd += ' provision/playbook.yml'
if verbose:
cmd += ' -vvvv'
local(cmd)
# Let's do this
if __name__ == '__main__':
deploy()

View File

@ -1,4 +0,0 @@
# PostgreSQL config
postgresql_version: 9.3
postgresql_database_name: amiibofindr
postgresql_database_user: amiibofindr

View File

@ -0,0 +1,6 @@
# Remote user that will execute the app
app_user: amiibofindr
# Git repository
git_repository: git@github.org:fmartingr/amiibofindr.git
git_branch: master

View File

@ -0,0 +1,2 @@
# Nginx
enable_ssl: false

View File

@ -1,4 +0,0 @@
---
postgresql_version: 9.3
postgresql_database_name: amiibofindr
postgresql_database_user: amiibofindr

View File

@ -0,0 +1,7 @@
# Nginx
site_hostname: amiibofindr.com
site_media_hostname: media.amiibofindr.com
site_static_hostname: static.amiibofindr.com
enable_ssl: false

View File

@ -1,4 +1,8 @@
default ansible_ssh_host=127.0.0.1 ansible_ssh_user=vagrant ansible_ssh_port=2201
default ansible_ssh_host=127.0.0.1 ansible_ssh_user=vagrant ansible_ssh_port=2222
[localdev]
default
[development]
[deploy]

View File

@ -2,18 +2,42 @@
- name: Common Tasks
hosts: all
roles:
- system
- base
- python
- nodejs
- postgresql
- role: system
tags: ["provision", "system"]
- role: base
tags: ["provision", "base"]
- role: python
tags: ["provision", "python"]
- role: nodejs
tags: ["provision", "nodejs"]
- role: redis
tags: ["provision", "redis"]
- role: postgresql
tags: ["provision", "postgresql"]
- role: nginx
tags: ["provision", "nginx"]
- role: supervisor
tags: ["provision", "supervisor"]
- role: deploy_user
tags: ["provision", "deploy_user"]
- name: LocalDev Tasks
hosts: localdev
roles:
- app_localdev
- role: app_localdev
tags: ["app_localdev"]
- name: Production Tasks
hosts: production
- name: Deploy Tasks
hosts:
- deploy
vars:
- ansible_ssh_user: "{{ app_user }}"
roles:
- app_production
- role: app_deploy
tags: ["deploy"]
- name: Automation tasks
hosts: all
roles:
- role: add_user_deploy
tags: ["add_user_deploy"]

View File

@ -0,0 +1,7 @@
---
- name: Ensure deployers group is present
group: name=deployers state=present
sudo: true
- name: Ensure user is present and member of the deployers group
user: name={{ app_user }} generate_ssh_key=yes ssh_key_bits={{ app_user_key_bits }} ssh_key_file=.ssh/id_rsa group={{ app_deploy_group }}
sudo: true

View File

@ -0,0 +1,5 @@
deploy_backend: true
deploy_migrate: true
deploy_collecstatic: true

View File

@ -0,0 +1,6 @@
---
- name: Ensure config is symlinked
file: src=/home/{{ app_user }}/conf/local.py
dest={{ deploy_path.stdout }}/git/src/backend/settings/local.py
state=link
force=true

View File

@ -0,0 +1,14 @@
---
- name: Performs manage.py syncdb
when: deploy_migrate
django_manage: >
command=syncdb
app_path={{ deploy_path.stdout }}/git/src/backend
virtualenv={{ deploy_path.stdout }}/.virtualenv
- name: Performs manage.py migrate
when: deploy_migrate
django_manage: >
command=migrate
app_path={{ deploy_path.stdout }}/git/src/backend
virtualenv={{ deploy_path.stdout }}/.virtualenv

View File

@ -0,0 +1,5 @@
---
- name: Performs initial syncdb
shell: "{{ app_scripts_folder }}/initial_syncdb.sh"
args:
chdir: /home/{{ app_user }}/builds/{{ deploy_date.stdout }}

View File

@ -0,0 +1,6 @@
---
- name: Create deploy folder
file: path={{ app_builds_folder }}/{{ deploy_date.stdout }} state=directory
- action: shell echo {{ app_builds_folder }}/{{ deploy_date.stdout }}
register: deploy_path

View File

@ -0,0 +1,14 @@
---
- name: Clone git repository
git: repo={{ git_repository }}
dest={{ app_git_folder }}
version={{ git_branch }}
accept_hostkey=true
- name: Create build git directory
file: path={{ deploy_path.stdout }}/git state=directory
sudo: true
sudo_user: "{{ app_user }}"
- name: Copy repository to build folder
command: cp -r {{ app_git_folder }} {{ deploy_path.stdout }}

View File

@ -0,0 +1,58 @@
---
- include_vars: ../../deploy_user/defaults/main.yml
# Register date as variable to use it in deploy steps
- action: shell date '+%Y%m%d_%H%M%S'
register: deploy_date
remote_user: "{{ app_user }}"
- stat: path=/home/{{ app_user }}/.initial_syncdb
register: initial_syncdb
ignore_errors: true
- include: folder.yml
remote_user: "{{ app_user }}"
- include: git.yml
remote_user: "{{ app_user }}"
- include: virtualenv.yml
remote_user: "{{ app_user }}"
#- include: node.yml
# remote_user: "{{ app_user }}"
- include: config.yml
remote_user: "{{ app_user }}"
- include: django_initial.yml
remote_user: "{{ app_user }}"
when: initial_syncdb.stat.exists == False
- include: django.yml
remote_user: "{{ app_user }}"
when: initial_syncdb.stat.exists
- name: Mark as finished
file: path=/home/{{ app_user }}/builds/{{ deploy_date.stdout }}/.finished
state=touch
remote_user: "{{ app_user }}"
- name: Remove old current symlink
file: path=/home/{{ app_user }}/current
state=absent
remote_user: "{{ app_user }}"
- name: Symlink new release
file: src={{ deploy_path.stdout }}/git/src
dest=/home/{{ app_user }}/current
state=link
force=true
remote_user: "{{ app_user }}"
- name: Restart supervisor
sudo: true
command: supervisorctl restart {{ item }}
with_items:
- django
- celery

View File

@ -0,0 +1,3 @@
#---
#- name: Install node requirements
# npm: path={{ deploy_path.stdout }}/git/src/backend

View File

@ -0,0 +1,9 @@
---
- name: Ensure virtualenv requirements installed
pip: requirements={{ deploy_path.stdout }}/git/src/backend/requirements-prod.txt
virtualenv={{ deploy_path.stdout }}/.virtualenv
- name: Symlink virtualenv to git src folder
file: src={{ deploy_path.stdout }}/.virtualenv
dest=/home/{{ app_user }}/git/src/.virtualenv
state=link

View File

@ -1,9 +0,0 @@
---
- name: Ensure (runserver) alias
lineinfile: dest=~/.bash_profile state=present line='alias runserver="python /vagrant/manage.py runserver 0.0.0.0:8000"'
- name: Ensure (runserver_plus) alias
lineinfile: dest=~/.bash_profile state=present line='alias runserver_plus="python /vagrant/manage.py runserver_plus 0.0.0.0:8000"'
- name: Ensure (shell) alias
lineinfile: dest=~/.bash_profile state=present line='alias shell="python /vagrant/manage.py shell"'
- name: Ensure (shell_plus) alias
lineinfile: dest=~/.bash_profile state=present line='alias shell_plus="python /vagrant/manage.py shell_plus"'

View File

@ -1,15 +1,13 @@
---
- name: Install requirements
pip: requirements=/vagrant/requirements/local.txt virtualenv=~/.virtualenv
pip: requirements=/vagrant/requirements/devel.txt virtualenv=/vagrant/.virtualenv
sudo: yes
sudo_user: vagrant
# - name: Install nodejs requirements
# npm: path=/vagrant
# sudo: yes
# sudo_user: vagrant
- name: Ensure vagrant user have a .bash_profile
file: path=~/.bash_profile state=touch
- name: Ensure directory is changed on login
lineinfile: dest=~/.bash_profile state=present line='cd /vagrant'
- name: Ensure DJANGO_SETTINGS_MODULE environment variable
lineinfile: dest=~/.bash_profile state=present line='export DJANGO_SETTINGS_MODULE="local_settings"'
- name: Performs manage.py migrate
django_manage: command=migrate
virtualenv=/vagrant/.virtualenv
app_path=/vagrant

View File

@ -1,5 +1,7 @@
---
- include_vars: ../../postgresql/defaults/main.yml
- include: python.yml
- include: postgresql.yml
- include: deploy.yml
- include: aliases.yml
- name: Ensure directory is changed on login
lineinfile: dest=~/.bash_profile state=present line='cd /vagrant'

View File

@ -3,14 +3,14 @@
postgresql_user: name=vagrant role_attr_flags=SUPERUSER
sudo_user: postgres
sudo: true
- name: Ensure vagrant database user is created
postgresql_user: db={{ postgresql_database_name }} name=vagrant password=vagrant priv=ALL state=present
sudo_user: postgres
sudo: true
- name: Ensure vagrant user can access
lineinfile: dest=/etc/postgresql/9.3/main/pg_hba.conf state=present line='local all postgres trust'
sudo: true
- name: Ensure database is present
postgresql_db: name={{ postgresql_database_name }} owner=vagrant
sudo: true
sudo_user: postgres
- name: Ensure vagrant database user is created
postgresql_user: db={{ postgresql_database_name }} name=vagrant password=NULL priv=ALL state=present
sudo_user: postgres
sudo: true
- name: Ensure vagrant user can access
lineinfile: dest=/etc/postgresql/{{ postgresql_version }}/main/pg_hba.conf state=present line='local all postgres trust'
sudo: true

View File

@ -3,20 +3,12 @@
- shell: if [ -e .virtualenv ]; then echo yes; else echo no; fi;
register: virtualenv_exists
always_run: True
sudo: true
sudo_user: vagrant
# Create virtualenv
- name: Ensure virtualenv is created
when: virtualenv_exists.stdout == 'no'
command: 'virtualenv .virtualenv'
sudo: true
sudo_user: vagrant
# Auto activate on ssh
- name: Ensure vagrant user have a .bash_profile
file: path=~/.bash_profile state=touch
sudo: true
sudo_user: vagrant
- name: Ensure virtualenv is enabled on login
lineinfile: dest=~/.bash_profile state=present line='. ~/.virtualenv/bin/activate'
sudo: true
sudo_user: vagrant

View File

@ -0,0 +1,4 @@
---
- name: Create user and generate shh-key file
user: name={{ app_user }} generate_ssh_key=yes ssh_key_bits={{ app_user_key_bits }} ssh_key_file=.ssh/id_rsa
sudo: true

View File

@ -0,0 +1,13 @@
app_user: amiibofindr
app_user_key_bits: 2048
app_deploy_group: deployers
app_static_folder: /home/{{ app_user }}/files/static
app_media_folder: /home/{{ app_user }}/files/media
app_conf_folder: /home/{{ app_user }}/conf
app_builds_folder: /home/{{ app_user }}/builds
app_logs_folder: /home/{{ app_user }}/logs
app_public_files_folder: /home/{{ app_user }}/public_files
app_git_folder: /home/{{ app_user }}/git
app_scripts_folder: /home/{{ app_user }}/scripts

View File

@ -0,0 +1,9 @@
#!/bin/bash
# Assumes we are chdir'ed to last build dir...
source .virtualenv/bin/activate
python manage.py migrate --noinput
touch $HOME/.initial_syncdb

View File

@ -0,0 +1 @@
{{ app_user }} ALL=NOPASSWD: {{ supervisorctl_path.stdout }}

View File

@ -0,0 +1,29 @@
---
- name: Ensure folder - static
file: path={{ app_static_folder }} state=directory
sudo: true
sudo_user: "{{ app_user }}"
- name: Ensure folder - media
file: path={{ app_media_folder }} state=directory
sudo: true
sudo_user: "{{ app_user }}"
- name: Ensure folder - conf
file: path={{ app_conf_folder }} state=directory
sudo: true
sudo_user: "{{ app_user }}"
- name: Ensure builds folder
file: path={{ app_builds_folder }} state=directory
sudo: true
sudo_user: "{{ app_user }}"
- name: Ensure logs folder
file: path={{ app_logs_folder }} state=directory
sudo: true
sudo_user: "{{ app_user }}"
- name: Ensure git repo folder
file: path={{ app_git_folder }} state=directory
sudo: true
sudo_user: "{{ app_user }}"
- name: Ensure scripts folder
file: path={{ app_scripts_folder }} state=directory
sudo: true
sudo_user: "{{ app_user }}"

View File

@ -0,0 +1,13 @@
---
- name: Create user and generate shh-key file
user: name={{ app_user }} generate_ssh_key=yes ssh_key_bits={{ app_user_key_bits }} ssh_key_file=.ssh/id_rsa shell=/bin/bash
sudo: true
- include: folders.yml
- include: sudoer.yml
- name: Add initial_syncdb.sh script
template: src=roles/deploy_user/files/initial_syncdb.sh
dest={{ app_scripts_folder }}/initial_syncdb.sh
mode=0644
sudo: true
sudo_user: "{{ app_user }}"

View File

@ -0,0 +1,8 @@
---
- action: shell which supervisorctl
register: supervisorctl_path
- name: Add sudoer file to allow supervisor without password
template: src=roles/deploy_user/files/sudoerfile
dest=/etc/sudoers.d/{{ app_user }}
sudo: true

View File

@ -0,0 +1,6 @@
site_hostname: amiibofindr.com
site_media_hostname: media.amiibofindr.com
site_static_hostname: static.amiibofindr.com
enable_ssl: true

View File

@ -0,0 +1,115 @@
# Redirect non-www to www
server {
listen 80;
{% if enable_ssl %}listen 443 ssl;{% endif %}
server_name www.{{ site_hostname }};
return 301 $scheme://{{ site_hostname }}$request_uri;
{% if enable_ssl %}
ssl_certificate /etc/nginx/ssl/certificate.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
{% endif %}
}
# Main server
server {
listen 80 default_server;
{% if enable_ssl %}listen 443 ssl default_server;{% endif %}
server_name {{ site_hostname }};
server_tokens off;
client_max_body_size 50M;
charset utf-8;
access_log {{ app_logs_folder }}/nginx-ecommerce.access.log;
error_log {{ app_logs_folder }}/nginx-ecommerce.error.log;
{% if enable_ssl %}
ssl_certificate /etc/nginx/ssl/certificate.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
if ($scheme = "http") {
return 301 https://$host$request_uri;
}
{% endif %}
location /archivos {
autoindex off;
alias {{ app_public_files_folder }};
}
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8000/;
proxy_redirect off;
expires -1;
}
}
server {
listen 80;
{% if enable_ssl %}listen 443 ssl;{% endif %}
server_name {{ site_media_hostname }};
charset utf-8;
access_log {{ app_logs_folder }}/nginx-media.access.log;
error_log {{ app_logs_folder }}/nginx-media.error.log;
{% if enable_ssl %}
ssl_certificate /etc/nginx/ssl/certificate.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
if ($scheme = "http") {
return 301 https://$host$request_uri;
}
{% endif %}
location / {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Content-Type,Accept';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
root {{ app_media_folder }};
autoindex off;
expires 1h;
}
}
server {
listen 80;
{% if enable_ssl %}
listen 443 ssl;
{% endif %}
server_name {{ site_static_hostname }};
charset utf-8;
access_log {{ app_logs_folder }}/nginx-static.access.log;
error_log {{ app_logs_folder }}/nginx-static.error.log;
{% if enable_ssl %}
ssl_certificate /etc/nginx/ssl/certificate.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
if ($scheme = "http") {
return 301 https://$host$request_uri;
}
{% endif %}
location / {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Content-Type,Accept';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
root {{ app_static_folder }};
autoindex off;
expires 1h;
}
}

View File

@ -0,0 +1,21 @@
---
- include_vars: ../../deploy_user/defaults/main.yml
- name: Ensure nginx installed
apt: pkg=nginx state=latest
sudo: true
- name: Ensure default hostfile is deleted
file: path=/etc/nginx/sites-enabled/default state=absent
sudo: true
- name: Ensure our hostfile is into sites-available
template: src=roles/nginx/files/host.conf dest=/etc/nginx/sites-available/{{ app_user }}
sudo: true
- name: Ensure hostfile is linked into sites-enabled
file: src=/etc/nginx/sites-available/{{ app_user }} dest=/etc/nginx/sites-enabled/{{ app_user }} state=link
sudo: true
- name: Restart nginx
service: name=nginx state=restarted
sudo: true

View File

@ -3,5 +3,4 @@
npm: name={{ item }} global=yes
sudo: true
with_items:
- grunt-cli
- bower
- gulp

View File

@ -1,3 +1,2 @@
postgresql_database_name: amiibofindr
postgresql_database_user: amiibofindr
postgresql_database_port: 5432
postgresql_user: djangoapp
postgresql_database_name: djangoapp

View File

@ -0,0 +1,13 @@
#!/bin/bash
psql template1 << EOF
CREATE EXTENSION hstore;
CREATE OR REPLACE FUNCTION idx(anyarray, anyelement)
RETURNS int AS
$$
SELECT i FROM (
SELECT generate_series(array_lower($1,1),array_upper($1,1))
) g(i)
WHERE $1[i] = $2
LIMIT 1;
$$ LANGUAGE sql IMMUTABLE;
EOF

View File

@ -0,0 +1,5 @@
---
- name: Config HSTORE into template1
sudo: true
sudo_user: postgres
script: hstore.sh

View File

@ -3,5 +3,5 @@
postgresql_db: name={{ postgresql_database_name }}
encoding='UTF-8'
state=present
sudo_user: postgres
sudo: true
sudo_user: postgres

View File

@ -1,9 +1,9 @@
---
- name: Ensure the database user is present
postgresql_user: db={{ postgresql_database_name }} name={{ postgresql_database_user }} password=NULL priv=ALL state=present
postgresql_user: db={{ postgresql_database_name }} name={{ app_user }} password=NULL priv=ALL state=present
sudo_user: postgres
sudo: true
- name: Ensure user dont have unnecesary privileges
postgresql_user: name={{ postgresql_database_user }} role_attr_flags=NOSUPERUSER,CREATEDB
postgresql_user: name=={{ app_user }} role_attr_flags=NOSUPERUSER,CREATEDB
sudo_user: postgres
sudo: true

View File

@ -1,5 +1,7 @@
---
- include_vars: ../../deploy_user/defaults/main.yml
- include: libs.yml
- include: postgresql.yml
- include: config_hstore.yml
- include: create_db.yml
- include: create_user.yml

View File

@ -1,6 +1,10 @@
---
- name: Ensure debug tools are installed
- name: Ensure pip tools
pip: name={{ item }}
sudo: true
with_items:
- ipdb
- name: Upgrade pip to last version
pip: name=pip state=latest
sudo: true

View File

@ -0,0 +1,2 @@
redis_bind: 0.0.0.0
redis_port: 6379

View File

@ -0,0 +1,4 @@
---
- name: start redis
service: name=redis-server state=started
sudo: yes

View File

@ -0,0 +1,2 @@
---
- include: redis.yml

View File

@ -0,0 +1,8 @@
---
- name: Install redis
apt: pkg={{ item }} state=latest
with_items:
- redis-server
sudo: true
notify:
- start redis

View File

@ -0,0 +1,3 @@
app_worker_num: 1
celery_worker_num: 1

View File

@ -0,0 +1,31 @@
[program:django]
command=/home/{{ app_user }}/current/.virtualenv/bin/gunicorn_django -w 3 -t 60 --settings=settings --pythonpath=.
directory=/home/{{ app_user }}/current/backend
numprocs={{ app_worker_num }}
autostart=true
autorestart=false
stopsignal=INT
stopwaitsecs=2
startsecs=2
redirect_stderr=true
stdout_logfile={{ app_logs_folder }}/gunicorn.log
stdout_logfile_backups=20
stdout_logfile_maxbytes=20MB
user={{ app_user }}
environment=LANG="en_US.UTF-8",USER="{{ app_user }}",HOME="/home/{{ app_user }}"
[program:celery]
command=/home/{{ app_user }}/current/.virtualenv/bin/python manage.py celery worker -l INFO -E
directory=/home/{{ app_user }}/current/backend
numprocs={{ celery_worker_num }}
autostart=true
autorestart=false
stopsignal=INT
stopwaitsecs=2
startsecs=2
redirect_stderr=true
stdout_logfile={{ app_logs_folder }}/celery.log
stdout_logfile_backups=20
stdout_logfile_maxbytes=20MB
user={{ app_user }}
environment=LANG="en_US.UTF-8",USER="{{ app_user }}",HOME="/home/{{ app_user }}"

View File

@ -0,0 +1,14 @@
---
- include_vars: ../../deploy_user/defaults/main.yml
- name: Ensure supervisor installed
apt: pkg=supervisor state=latest
sudo: true
- name: Ensure our config file is enabled
template: src=roles/supervisor/files/config.ini dest=/etc/supervisor/conf.d/{{ app_user }}.conf
sudo: true
- name: Restart supervisor
command: service supervisor restart
sudo: true
ignore_errors: true

View File

@ -3,3 +3,7 @@
lineinfile: dest=/etc/environment line=LANG=en_US.utf-8
lineinfile: dest=/etc/environment line=LC_ALL=en_US.utf-8
sudo: true
- name: Ensure git is installed
apt: pkg=git state=latest
sudo: true