├── .gitignore ├── README.md ├── group_vars └── webservers ├── main.yml ├── roles ├── app │ ├── defaults │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── get_application.yml │ │ ├── install_additional_packages.yml │ │ ├── main.yml │ │ ├── setup_django.yml │ │ ├── setup_gunicorn.yml │ │ └── setup_virtualenv.yml │ └── templates │ │ ├── gunicorn_start.j2 │ │ └── virtualenv_postactivate.j2 ├── common │ ├── defaults │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── git.yml │ │ ├── main.yml │ │ └── zsh.yml │ └── templates │ │ └── home-zshrc.j2 ├── configuration │ └── defaults │ │ └── main.yml ├── nginx │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ ├── configuration.yml │ │ ├── installation.packages.yml │ │ ├── main.yml │ │ ├── nginx-official-repo.yml │ │ ├── remove-defaults.yml │ │ ├── remove-extras.yml │ │ └── remove-unwanted.yml │ ├── templates │ │ ├── auth_basic.j2 │ │ ├── config.conf.j2 │ │ ├── nginx.conf.j2 │ │ └── site.conf.j2 │ └── vars │ │ └── main.yml ├── postgresql │ ├── defaults │ │ └── main.yml │ └── tasks │ │ ├── database.yml │ │ ├── install.yml │ │ └── main.yml └── supervisor │ ├── defaults │ └── main.yml │ ├── handlers │ └── main.yml │ ├── tasks │ ├── configure.yml │ ├── groups.yml │ ├── install.yml │ ├── main.yml │ └── programs.yml │ ├── templates │ └── etc │ │ ├── init.d │ │ └── supervisor.j2 │ │ └── supervisor │ │ ├── conf.d │ │ ├── group.conf.j2 │ │ └── program.conf.j2 │ │ └── supervisord.conf.j2 │ └── vars │ └── main.yml └── server.ini /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | 55 | # Sphinx documentation 56 | docs/_build/ 57 | 58 | # PyBuilder 59 | target/ 60 | 61 | #Ipython Notebook 62 | .ipynb_checkpoints 63 | 64 | local.ini 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansible playbook for deploying Django. 2 | 3 | Ansible Playbook for setting up a Django app. This playbook installs and configures a Django application with the following technologies: 4 | 5 | - Nginx 6 | - Gunicorn 7 | - Supervisor 8 | - Virtualenv 9 | - PostgreSQL 10 | 11 | **OS:** Ubuntu, Debian 12 | 13 | **Tested with Cloud Providers:** [Digital Ocean](https://www.digitalocean.com/), [Amazon](https://aws.amazon.com) 14 | 15 | Usage 16 | ----- 17 | 18 | First, create an inventory file for the environment, for example: 19 | 20 | ```yml 21 | [webservers] 22 | django_test ansible_ssh_user=test 23 | ``` 24 | 25 | Next, define variables 26 | 27 | ```yml 28 | - git_repo: "https://github.com/myarik/demo_django_ansible_setup.git" 29 | 30 | ``` 31 | 32 | Run the playbook: 33 | 34 | ``` 35 | ansible-playbook main.yml -i server.ini 36 | ``` 37 | 38 | When doing deployments, you can simply use the `--tags` option to only run those tasks with these tags. 39 | 40 | 41 | Role Variables 42 | -------------- 43 | 44 | The user can specify parameters they wish to apply. 45 | 46 | **Configuration** 47 | 48 | * `application_name`: Application name. Defaults is `django_test` 49 | * `application_path`: Application path. Defaults is `/opt/{{application_name}}` 50 | * `application_static_path`: A static path. Defaults is `/opt/{{application_name}}/staticfiles` 51 | * `application_media_path`: A media path. Defaults is `/opt/{{application_name}}/media` 52 | * `virtualenv_path`: Application virtualenv. Defaults is `/opt/{{application_name}}/.env` 53 | * `setup_nginx`: Install and configure nginx. Default is True 54 | * `setup_postgresql`: Install PostgreSQL. Default is False 55 | 56 | **Common settings** 57 | 58 | * `main_pkg`: List of main pkgs 59 | * `setup_zsh`: Setup zsh. Defaults is `true`. 60 | * `git_user_name`: Git username. Defaults is django_test 61 | * `git_email`: Git user email. Defaults is `git@django_test` 62 | 63 | 64 | **Application settings** 65 | 66 | * `add_pkgs`: List of additional packeges. 67 | * `git_repo`: Git Repository 68 | * `git_branch`: Git branch. Defaults is master 69 | * `gunicorn_num_workers`: The number of worker processes for handling requests. Default is 2 70 | * `gunicorn_max_requests`: The maximum number of requests a worker will process. Default is 0 71 | 72 | **Django settings** 73 | 74 | * `django_environment`: Django Environment variables 75 | * `requirements_file`: Django requirement file. Default is `{{application_path}}/requirements.txt` 76 | * `django_settings_file`: Django settings file. Default is `{{application_path}}/config/settings/production` 77 | * `django_wsgi`: Django wsgi file. Default is config.wsgi 78 | * `django_manage_commands`: List of django manage commands. Default is `migrate` and `collectstatic` 79 | 80 | 81 | **PostgreSQL settings** 82 | * `postgresql_pgtune`: Install pgtune. Default is False 83 | * `postgresql_encoding`: Default is UTF-8 84 | * `database_name`: Database name 85 | * `database_user`: Database user 86 | * `database_password`: Database password 87 | 88 | 89 | Examples 90 | ======== 91 | 92 | For creating demo project, I used a [cookiecutter template for Django](https://github.com/pydanny/cookiecutter-django) 93 | 94 | 1) Install and configre enviroment with PostgreSQL database. *(Setup enviroment in Digital Ocean)* 95 | 96 | `server.ini` 97 | 98 | ```yaml 99 | [webservers] 100 | digital_ocean_test ansible_ssh_user=root 101 | ``` 102 | 103 | ```yml 104 | vars: 105 | - git_repo: "https://github.com/myarik/demo_django_ansible_setup.git" 106 | - setup_postgresql: true 107 | - database_name: "demo_test" 108 | - database_user: "demo" 109 | - database_password: "demo" 110 | - django_environment: 111 | DEBUG: False 112 | DATABASE_URL: "postgres://demo:demo@localhost:5432/demo_test" 113 | DJANGO_SECRET_KEY: be&9u)d64q^@a__^1oswsezz((%li@j^5#=f!lm32n+21x!*2@ 114 | DJANGO_ALLOWED_HOSTS: "*" 115 | ``` 116 | 117 | 2) Install and configre enviroment with Sqlite database. *(Setup enviroment in AWS)* 118 | 119 | `server.ini` 120 | 121 | ```yaml 122 | [webservers] 123 | aws_test ansible_ssh_user=ubuntu 124 | ``` 125 | 126 | ```yml 127 | vars: 128 | - git_repo: "https://github.com/myarik/demo_django_ansible_setup.git" 129 | - application_name: my_project 130 | - application_path: /home/ubuntu/{{application_name}} 131 | - django_environment: 132 | DEBUG: False 133 | DATABASE_URL: sqlite:////tmp/my-tmp-sqlite.db 134 | DJANGO_SECRET_KEY: be&9u)d64q^@a__^1oswsezz((%li@j^5#=f!lm32n+21x!*2@ 135 | DJANGO_ALLOWED_HOSTS: "*" 136 | ``` 137 | -------------------------------------------------------------------------------- /group_vars/webservers: -------------------------------------------------------------------------------- 1 | --- 2 | git_repo: "https://github.com/myarik/demo_django_ansible_setup.git" 3 | -------------------------------------------------------------------------------- /main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: webservers 3 | become: yes 4 | roles: 5 | - { role: common, 6 | tags: [setup_common_pkg] 7 | } 8 | - { role: postgresql, 9 | when: setup_postgresql is defined and setup_postgresql, 10 | tags: [setup_postgresql] 11 | } 12 | - { role: app, 13 | tags: [setup_app] 14 | } 15 | - { role: nginx, 16 | when: setup_nginx is defined and setup_nginx, 17 | tags: [setup_nginx] 18 | } 19 | - { role: supervisor, 20 | tags: [setup_supervisor] 21 | } 22 | -------------------------------------------------------------------------------- /roles/app/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | add_pkgs: 3 | - build-essential 4 | - gettext 5 | - python-dev 6 | - zlib1g-dev 7 | - libpq-dev 8 | - libtiff4-dev 9 | - libjpeg8-dev 10 | - libfreetype6-dev 11 | - liblcms1-dev 12 | - libwebp-dev 13 | - graphviz-dev 14 | - python-setuptools 15 | - python3-dev 16 | - python-virtualenv 17 | - python-pip 18 | - automake 19 | - libtool 20 | - libreadline6 21 | - libreadline6-dev 22 | - libreadline-dev 23 | - libsqlite3-dev 24 | - libxml2 25 | - libxml2-dev 26 | - libssl-dev 27 | - libbz2-dev 28 | - wget 29 | - curl 30 | - llvm 31 | 32 | git_branch: master 33 | 34 | # Gunicorn 35 | gunicorn_num_workers: 2 36 | gunicorn_max_requests: 0 37 | 38 | # Django Environment variables 39 | requirements_file: "{{application_path}}/requirements.txt" 40 | django_environment: 41 | DEBUG: False 42 | DATABASE_URL: sqlite:////tmp/my-tmp-sqlite.db 43 | DJANGO_SECRET_KEY: be&9u)d64q^@a__^1oswsezz((%li@j^5#=f!lm32n+21x!*2@ 44 | DJANGO_ALLOWED_HOSTS: "*" 45 | 46 | django_settings_file: "{{application_path}}/config/settings/production" 47 | django_wsgi: "config.wsgi" 48 | 49 | django_manage_commands: 50 | - migrate 51 | - collectstatic 52 | -------------------------------------------------------------------------------- /roles/app/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependencies: 3 | - { role: configuration} 4 | -------------------------------------------------------------------------------- /roles/app/tasks/get_application.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create the application direcotry 3 | file: path={{application_path}} state=directory owner={{ansible_ssh_user}} group={{ansible_ssh_user}} 4 | 5 | - name: Get application from the repository 6 | git: > 7 | repo={{git_repo}} 8 | dest={{application_path}} 9 | version={{git_branch}} 10 | accept_hostkey=yes 11 | become: no 12 | -------------------------------------------------------------------------------- /roles/app/tasks/install_additional_packages.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install Additional Packages 3 | apt: name={{ item }} state=installed update_cache=true 4 | with_items: add_pkgs 5 | -------------------------------------------------------------------------------- /roles/app/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include: install_additional_packages.yml 3 | when: add_pkgs is defined 4 | 5 | - include: get_application.yml 6 | - include: setup_virtualenv.yml 7 | - include: setup_gunicorn.yml 8 | - include: setup_django.yml 9 | -------------------------------------------------------------------------------- /roles/app/tasks/setup_django.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install application required by the Django app inside virtualenv 3 | pip: virtualenv={{ virtualenv_path }} requirements={{ requirements_file }} 4 | become: no 5 | 6 | - name: Run Django database migrations 7 | django_manage: 8 | command: "{{ item }}" 9 | app_path: "{{ application_path }}" 10 | virtualenv: "{{ virtualenv_path }}" 11 | environment: "{{ django_environment }}" 12 | when: django_manage_commands is defined and django_manage_commands 13 | with_items: "{{django_manage_commands}}" 14 | become: no 15 | 16 | -------------------------------------------------------------------------------- /roles/app/tasks/setup_gunicorn.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure gunicorn is installed 3 | pip: virtualenv={{ virtualenv_path }} name=gunicorn 4 | 5 | - name: Create the Gunicorn script file 6 | template: 7 | src: gunicorn_start.j2 8 | dest: "{{ virtualenv_path }}/bin/gunicorn_start" 9 | mode: 0755 10 | backup: yes 11 | become: no 12 | -------------------------------------------------------------------------------- /roles/app/tasks/setup_virtualenv.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install virtualenv 3 | pip: name=virtualenv 4 | 5 | - name: Create the virtualenv 6 | command: virtualenv {{ virtualenv_path }} --no-site-packages 7 | creates={{ virtualenv_path }}/bin/activate 8 | become: no 9 | 10 | - name: Create the virtualenv postactivate script to set environment variables 11 | template: 12 | src: virtualenv_postactivate.j2 13 | dest: "{{ virtualenv_path }}/bin/postactivate" 14 | mode: 0640 15 | backup: yes 16 | become: no 17 | -------------------------------------------------------------------------------- /roles/app/templates/gunicorn_start.j2: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | NAME="{{ application_name }}" 4 | DJANGODIR="{{ application_path }}" 5 | SOCKFILE={{ virtualenv_path }}/run/gunicorn.sock 6 | USER={{ ansible_ssh_user }} 7 | GROUP={{ ansible_ssh_user }} 8 | NUM_WORKERS={{ gunicorn_num_workers }} 9 | 10 | # Set this to 0 for unlimited requests. During development, you might want to 11 | # set this to 1 to automatically restart the process on each request (i.e. your 12 | # code will be reloaded on every request). 13 | MAX_REQUESTS={{ gunicorn_max_requests }} 14 | 15 | echo "Starting $NAME as `whoami`" 16 | 17 | # Activate the virtual environment. 18 | cd $DJANGODIR 19 | . {{ virtualenv_path }}/bin/activate 20 | 21 | # Set additional environment variables. 22 | . {{ virtualenv_path }}/bin/postactivate 23 | 24 | # Create the run directory if it doesn't exist. 25 | RUNDIR=$(dirname $SOCKFILE) 26 | test -d $RUNDIR || mkdir -p $RUNDIR 27 | 28 | # Programs meant to be run under supervisor should not daemonize themselves 29 | # (do not use --daemon). 30 | exec gunicorn {{django_wsgi}}\ 31 | --name $NAME \ 32 | --workers $NUM_WORKERS \ 33 | --max-requests $MAX_REQUESTS \ 34 | --timeout {{ gunicorn_timeout_seconds|default(30) }} \ 35 | --user $USER --group $GROUP \ 36 | --log-level info \ 37 | --bind unix:$SOCKFILE \ 38 | --chdir={{application_path}} \ 39 | --log-file=- 40 | -------------------------------------------------------------------------------- /roles/app/templates/virtualenv_postactivate.j2: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | {% for variable_name, value in django_environment.iteritems() %} 4 | export {{ variable_name }}="{{ value }}" 5 | {% endfor %} 6 | -------------------------------------------------------------------------------- /roles/common/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | main_pkg: 3 | - mc 4 | - wget 5 | - vim 6 | - gcc 7 | - unzip 8 | - htop 9 | - tmux 10 | - curl 11 | - pkg-config 12 | - python-pip 13 | - python-dev 14 | - libpq-dev 15 | - build-essential 16 | - python-pycurl 17 | 18 | setup_zsh: True 19 | git_user_name: "{{application_name}}" 20 | git_email: git@{{application_name}} 21 | -------------------------------------------------------------------------------- /roles/common/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependencies: 3 | - { role: configuration} 4 | -------------------------------------------------------------------------------- /roles/common/tasks/git.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: install git 3 | apt: name={{ item }} state=installed update_cache=true 4 | with_items: 5 | - git 6 | - git-core 7 | register: gitinstalled 8 | 9 | - name: setup_git 10 | when: gitinstalled | success 11 | shell: git config --global {{ item.command }} "{{item.value}}" 12 | with_items: 13 | - {command: user.name, value: "{{git_user_name}}" } 14 | - {command: user.email, value: "{{git_email}}" } 15 | become: no 16 | -------------------------------------------------------------------------------- /roles/common/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Perform Safe Upgrade 3 | apt: upgrade=safe update_cache=yes 4 | 5 | - name: Install Pkg 6 | apt: name={{ item }} state=installed update_cache=true 7 | with_items: main_pkg 8 | 9 | - name: update ntp 10 | shell: ntpdate pool.ntp.org 11 | 12 | - include: git.yml 13 | 14 | - include: zsh.yml 15 | when: setup_zsh == True 16 | -------------------------------------------------------------------------------- /roles/common/tasks/zsh.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install Zsh 3 | apt: name=zsh state=installed 4 | register: installation 5 | 6 | - name: Cloning oh-my-zsh 7 | git: 8 | repo=https://github.com/robbyrussell/oh-my-zsh 9 | dest=~/.oh-my-zsh 10 | when: installation|success 11 | register: cloning 12 | become: no 13 | 14 | - name: Creating new ~/.zshrc 15 | copy: 16 | src=~/.oh-my-zsh/templates/zshrc.zsh-template 17 | dest=~/.zshrc 18 | when: cloning|success 19 | become: no 20 | -------------------------------------------------------------------------------- /roles/common/templates/home-zshrc.j2: -------------------------------------------------------------------------------- 1 | # Path to your oh-my-zsh installation. 2 | export ZSH=$HOME/.oh-my-zsh 3 | 4 | # Set name of the theme to load. 5 | # Look in ~/.oh-my-zsh/themes/ 6 | # Optionally, if you set this to "random", it'll load a random theme each 7 | # time that oh-my-zsh is loaded. 8 | ZSH_THEME="robbyrussell" 9 | 10 | # Uncomment the following line to use case-sensitive completion. 11 | CASE_SENSITIVE="true" 12 | 13 | # Uncomment the following line to disable bi-weekly auto-update checks. 14 | # DISABLE_AUTO_UPDATE="true" 15 | 16 | # Uncomment the following line to change how often to auto-update (in days). 17 | # export UPDATE_ZSH_DAYS=13 18 | 19 | # Uncomment the following line to disable colors in ls. 20 | # DISABLE_LS_COLORS="true" 21 | 22 | # Uncomment the following line to disable auto-setting terminal title. 23 | # DISABLE_AUTO_TITLE="true" 24 | 25 | # Uncomment the following line to enable command auto-correction. 26 | # ENABLE_CORRECTION="true" 27 | 28 | # Uncomment the following line to display red dots whilst waiting for completion. 29 | # COMPLETION_WAITING_DOTS="true" 30 | 31 | # Uncomment the following line if you want to disable marking untracked files 32 | # under VCS as dirty. This makes repository status check for large repositories 33 | # much, much faster. 34 | # DISABLE_UNTRACKED_FILES_DIRTY="true" 35 | 36 | # Uncomment the following line if you want to change the command execution time 37 | # stamp shown in the history command output. 38 | # The optional three formats: "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd" 39 | HIST_STAMPS="mm/dd/yyyy" 40 | 41 | # Would you like to use another custom folder than $ZSH/custom? 42 | # ZSH_CUSTOM=/path/to/new-custom-folder 43 | 44 | # Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*) 45 | # Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/ 46 | # Example format: plugins=(rails git textmate ruby lighthouse) 47 | # Add wisely, as too many plugins slow down shell startup. 48 | plugins=(git) 49 | 50 | source $ZSH/oh-my-zsh.sh 51 | 52 | # User configuration 53 | 54 | # export MANPATH="/usr/local/man:$MANPATH" 55 | 56 | # You may need to manually set your language environment 57 | # export LANG=en_US.UTF-8 58 | 59 | # Preferred editor for local and remote sessions 60 | # if [[ -n $SSH_CONNECTION ]]; then 61 | # export EDITOR='vim' 62 | # else 63 | # export EDITOR='mvim' 64 | # fi 65 | 66 | # Compilation flags 67 | # export ARCHFLAGS="-arch x86_64" 68 | 69 | # ssh 70 | # export SSH_KEY_PATH="~/.ssh/dsa_id" 71 | 72 | # Set personal aliases, overriding those provided by oh-my-zsh libs, 73 | # plugins, and themes. Aliases can be placed here, though oh-my-zsh 74 | # users are encouraged to define aliases within the ZSH_CUSTOM folder. 75 | # For a full list of active aliases, run `alias`. 76 | # 77 | # Example aliases 78 | # alias zshconfig="mate ~/.zshrc" 79 | # alias ohmyzsh="mate ~/.oh-my-zsh" 80 | -------------------------------------------------------------------------------- /roles/configuration/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: "Yaroslav Muravsky" 4 | license: BSD 5 | description: Set up the enviroment for Django application in Ubuntu systems 6 | min_ansible_version: 1.4 7 | platforms: 8 | - name: Ubuntu 9 | versions: 10 | - precise 11 | - quantal 12 | - raring 13 | - saucy 14 | - trusty 15 | categories: 16 | - web 17 | allow_duplicates: yes 18 | 19 | application_name: django_test 20 | application_path: /opt/{{application_name}} 21 | application_static_path: "{{application_path}}/staticfiles" 22 | application_media_path: "{{application_path}}/media" 23 | virtualenv_path: "{{application_path}}/.env" 24 | setup_nginx: true 25 | setup_postgresql: false 26 | -------------------------------------------------------------------------------- /roles/nginx/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | nginx_ubuntu_pkg: 3 | - python-selinux 4 | - nginx 5 | 6 | nginx_official_repo: False 7 | 8 | keep_only_specified: False 9 | 10 | nginx_installation_type: "packages" 11 | nginx_binary_name: "nginx" 12 | nginx_service_name: "{{nginx_binary_name}}" 13 | nginx_conf_dir: "/etc/nginx" 14 | 15 | nginx_user: "www-data" 16 | nginx_group: "{{nginx_user}}" 17 | 18 | nginx_pid_file: '/var/run/{{nginx_service_name}}.pid' 19 | 20 | nginx_worker_processes: "{{ ansible_processor_vcpus }}" 21 | nginx_worker_rlimit_nofile: 1024 22 | nginx_log_dir: "/var/log/nginx" 23 | 24 | nginx_events_params: 25 | - worker_connections {% if nginx_max_clients is defined %}{{nginx_max_clients}}{% else %}512{% endif %} 26 | 27 | nginx_http_params: 28 | - sendfile "on" 29 | - tcp_nopush "on" 30 | - tcp_nodelay "on" 31 | - keepalive_timeout "65" 32 | - access_log "{{nginx_log_dir}}/access.log" 33 | - error_log "{{nginx_log_dir}}/error.log" 34 | - server_tokens off 35 | - types_hash_max_size 2048 36 | 37 | nginx_sites: 38 | default: 39 | - listen 80 default_server 40 | - server_name _ 41 | - location /static/ { gzip_static on; gzip_http_version 1.1; gzip_proxied expired no-cache no-store private auth; gzip_disable "MSIE [1-6]\."; gzip_vary on; alias {{application_static_path}}; expires 30d;} 42 | - location /media/ { gzip_static on; gzip_http_version 1.1; gzip_proxied expired no-cache no-store private auth; gzip_disable "MSIE [1-6]\."; gzip_vary on; alias {{application_media_path}}; expires 30d;} 43 | - location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_pass http://unix:{{ virtualenv_path }}/run/gunicorn.sock;} 44 | nginx_remove_sites: [] 45 | 46 | nginx_configs: {} 47 | nginx_remove_configs: [] 48 | 49 | nginx_auth_basic_files: {} 50 | nginx_remove_auth_basic_files: [] 51 | 52 | nginx_daemon_mode: "on" 53 | -------------------------------------------------------------------------------- /roles/nginx/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart nginx 3 | debug: msg="checking config first" 4 | changed_when: True 5 | notify: 6 | - check nginx configuration 7 | - restart nginx - after config check 8 | 9 | - name: reload nginx 10 | debug: msg="checking config first" 11 | changed_when: True 12 | notify: 13 | - check nginx configuration 14 | - reload nginx - after config check 15 | 16 | - name: check nginx configuration 17 | shell: "{{ nginx_binary_name }} -t" 18 | register: result 19 | changed_when: "result.rc != 0" 20 | always_run: yes 21 | when: nginx_installation_type in nginx_installation_types_using_service 22 | 23 | - name: restart nginx - after config check 24 | service: name={{ nginx_service_name }} state=restarted 25 | when: nginx_installation_type in nginx_installation_types_using_service and nginx_daemon_mode == "on" 26 | 27 | - name: reload nginx - after config check 28 | service: name={{ nginx_service_name }} state=reloaded 29 | when: nginx_installation_type in nginx_installation_types_using_service and nginx_daemon_mode == "on" 30 | -------------------------------------------------------------------------------- /roles/nginx/tasks/configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create the directories for site specific configurations 3 | file: path={{nginx_conf_dir}}/{{ item }} state=directory owner=root group={{nginx_group}} mode=0755 4 | with_items: 5 | - "sites-available" 6 | - "sites-enabled" 7 | - "auth_basic" 8 | - "conf.d" 9 | - "ssl" 10 | tags: [configuration,nginx] 11 | 12 | - name: Ensure log directory exist 13 | file: path={{ nginx_log_dir }} state=directory owner={{nginx_user}} group={{nginx_group}} mode=0755 14 | tags: [configuration,nginx] 15 | 16 | - name: Copy the nginx configuration file 17 | template: src=nginx.conf.j2 dest={{nginx_conf_dir}}/nginx.conf 18 | notify: 19 | - restart nginx 20 | tags: [configuration,nginx] 21 | 22 | - name: Ensure auth_basic files created 23 | template: src=auth_basic.j2 dest={{nginx_conf_dir}}/auth_basic/{{ item }} owner=root group={{nginx_group}} mode=0750 24 | with_items: nginx_auth_basic_files.keys() 25 | tags: [configuration,nginx] 26 | 27 | - name: Create the configurations for sites 28 | template: src=site.conf.j2 dest={{nginx_conf_dir}}/sites-available/{{ item }}.conf 29 | with_items: nginx_sites.keys() | difference(nginx_remove_sites) 30 | notify: 31 | - reload nginx 32 | tags: [configuration,nginx] 33 | 34 | - name: Create links for sites-enabled 35 | file: state=link src={{nginx_conf_dir}}/sites-available/{{ item }}.conf dest={{nginx_conf_dir}}/sites-enabled/{{ item }}.conf 36 | with_items: nginx_sites.keys() | difference(nginx_remove_sites) 37 | notify: 38 | - reload nginx 39 | tags: [configuration,nginx] 40 | 41 | - name: Create the configurations for independent config file 42 | template: src=config.conf.j2 dest={{nginx_conf_dir}}/conf.d/{{ item }}.conf 43 | with_items: nginx_configs.keys() 44 | notify: 45 | - reload nginx 46 | tags: [configuration,nginx] 47 | -------------------------------------------------------------------------------- /roles/nginx/tasks/installation.packages.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install the nginx packages 3 | apt: name={{ item }} state=present 4 | with_items: nginx_ubuntu_pkg 5 | environment: "{{ nginx_env }}" 6 | tags: [packages,nginx] 7 | -------------------------------------------------------------------------------- /roles/nginx/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include: nginx-official-repo.yml 3 | when: nginx_official_repo == True 4 | 5 | - include: installation.packages.yml 6 | when: nginx_installation_type == "packages" 7 | 8 | - include: remove-defaults.yml 9 | when: not keep_only_specified 10 | 11 | - include: remove-extras.yml 12 | when: keep_only_specified 13 | 14 | - include: remove-unwanted.yml 15 | 16 | - include: configuration.yml 17 | 18 | - name: Start the nginx service 19 | service: name={{ nginx_service_name }} state=started enabled=yes 20 | when: nginx_installation_type in nginx_installation_types_using_service and nginx_daemon_mode == "on" 21 | tags: [service,nginx] 22 | -------------------------------------------------------------------------------- /roles/nginx/tasks/nginx-official-repo.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure APT official nginx key 3 | apt_key: url=http://nginx.org/keys/nginx_signing.key 4 | tags: [packages,nginx] 5 | 6 | - name: Ensure APT official nginx repository 7 | apt_repository: repo="deb http://nginx.org/packages/{{ ansible_distribution_release|lower }}/ {{ ansible_distribution_release }} nginx" 8 | tags: [packages,nginx] 9 | -------------------------------------------------------------------------------- /roles/nginx/tasks/remove-defaults.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Disable the default site 3 | file: path={{nginx_conf_dir}}/sites-enabled/default state=absent 4 | notify: 5 | - reload nginx 6 | tags: [configuration,nginx] 7 | 8 | - name: Remove the default configuration 9 | file: path={{nginx_conf_dir}}/conf.d/default.conf state=absent 10 | when: > 11 | 'default' not in nginx_configs.keys() 12 | notify: 13 | - reload nginx 14 | tags: [configuration,nginx] 15 | 16 | -------------------------------------------------------------------------------- /roles/nginx/tasks/remove-extras.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Find enabled sites 3 | shell: ls -1 {{nginx_conf_dir}}/sites-enabled 4 | register: enabled_sites 5 | changed_when: False 6 | tags: [configuration,nginx] 7 | 8 | - name: Disable unmanaged sites 9 | file: path={{nginx_conf_dir}}/sites-enabled/{{ item }} state=absent 10 | with_items: enabled_sites.stdout_lines 11 | # 'item.conf' => 'item' 12 | when: item[:-5] not in nginx_sites.keys() 13 | notify: 14 | - reload nginx 15 | tags: [configuration,nginx] 16 | 17 | - name: Find config files 18 | shell: ls -1 {{nginx_conf_dir}}/conf.d 19 | register: config_files 20 | changed_when: False 21 | tags: [configuration,nginx] 22 | 23 | - name: Remove unmanaged config files 24 | file: name={{nginx_conf_dir}}/conf.d/{{ item }} state=absent 25 | with_items: config_files.stdout_lines 26 | # 'item.conf' => 'item' 27 | when: item[:-5] not in nginx_configs.keys() 28 | notify: 29 | - reload nginx 30 | tags: [configuration,nginx] 31 | 32 | -------------------------------------------------------------------------------- /roles/nginx/tasks/remove-unwanted.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Remove unwanted sites 3 | file: path={{nginx_conf_dir}}/{{ item[0] }}/{{ item[1] }}.conf state=absent 4 | with_nested: 5 | - [ 'sites-enabled', 'sites-available'] 6 | - nginx_remove_sites 7 | notify: 8 | - reload nginx 9 | tags: [configuration,nginx] 10 | 11 | - name: Remove unwanted conf 12 | file: path={{nginx_conf_dir}}/conf.d/{{ item[1] }}.conf state=absent 13 | with_items: nginx_remove_configs 14 | notify: 15 | - reload nginx 16 | tags: [configuration,nginx] 17 | 18 | - name: Remove unwanted auth_basic_files 19 | file: path={{nginx_conf_dir}}/auth_basic/{{ item[1] }} state=absent 20 | with_items: nginx_remove_auth_basic_files 21 | notify: 22 | - reload nginx 23 | tags: [configuration,nginx] 24 | -------------------------------------------------------------------------------- /roles/nginx/templates/auth_basic.j2: -------------------------------------------------------------------------------- 1 | 2 | {% for v in nginx_auth_basic_files[item] %} 3 | {{ v }} 4 | {% endfor %} 5 | -------------------------------------------------------------------------------- /roles/nginx/templates/config.conf.j2: -------------------------------------------------------------------------------- 1 | {% for v in nginx_configs[item] %} 2 | {% if v.find('\n') != -1 %} 3 | {{v}} 4 | {% else %} 5 | {% if v != "" %}{{ v.replace(";",";\n ").replace(" {"," {\n ").replace(" }"," \n}\n") }}{% if v.find('{') == -1%}; 6 | {% endif %}{% endif %}{% endif %} 7 | {% endfor %} 8 | -------------------------------------------------------------------------------- /roles/nginx/templates/nginx.conf.j2: -------------------------------------------------------------------------------- 1 | user {{ nginx_user }} {{ nginx_group }}; 2 | 3 | worker_processes {{ nginx_worker_processes }}; 4 | 5 | {% if nginx_pid_file %} 6 | pid {{ nginx_pid_file }}; 7 | {% endif %} 8 | 9 | worker_rlimit_nofile {{ nginx_worker_rlimit_nofile }}; 10 | 11 | events { 12 | {% for v in nginx_events_params %} 13 | {{ v }}; 14 | {% endfor %} 15 | } 16 | 17 | 18 | http { 19 | 20 | include {{ nginx_conf_dir }}/mime.types; 21 | default_type application/octet-stream; 22 | 23 | log_format main '$remote_addr - $remote_user [$time_local] $status ' 24 | '"$request" $body_bytes_sent "$http_referer" ' 25 | '"$http_user_agent" "$http_x_forwarded_for"'; 26 | {% for v in nginx_http_params %} 27 | {{ v }}; 28 | {% endfor %} 29 | 30 | include {{ nginx_conf_dir }}/conf.d/*.conf; 31 | include {{ nginx_conf_dir }}/sites-enabled/*; 32 | } 33 | 34 | {% if nginx_daemon_mode == "off" %} 35 | daemon off; 36 | {% endif %} 37 | -------------------------------------------------------------------------------- /roles/nginx/templates/site.conf.j2: -------------------------------------------------------------------------------- 1 | server { 2 | {% for v in nginx_sites[item] %} 3 | {% if v.find('\n') != -1 %} 4 | {{v.replace("\n","\n ")}} 5 | {% else %} 6 | {% if v != "" %}{{ v.replace(";",";\n ").replace(" {"," {\n ").replace(" }"," \n }\n") }}{% if v.find('{') == -1%}; 7 | {% endif %}{% endif %}{% endif %} 8 | {% endfor %} 9 | } 10 | -------------------------------------------------------------------------------- /roles/nginx/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | nginx_env: 4 | RUNLEVEL: 1 5 | 6 | nginx_installation_types_using_service: ["packages", "configuration-only"] 7 | 8 | -------------------------------------------------------------------------------- /roles/postgresql/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | postgresql_pgtune: false 3 | postgresql_encoding: 'UTF-8' 4 | postgresql_locale_parts: 5 | - 'en_US' # Locale 6 | - 'UTF-8' # Encoding 7 | postgresql_locale: "{{ postgresql_locale_parts | join('.') }}" 8 | postgresql_admin_user: "postgres" 9 | -------------------------------------------------------------------------------- /roles/postgresql/tasks/database.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # file: postgresql/tasks/databases.yml 3 | 4 | - name: PostgreSQL | Ensure PostgreSQL is running 5 | service: 6 | name: postgresql 7 | state: started 8 | 9 | - name: PostgreSQL | Make sure the PostgreSQL databases are present 10 | postgresql_db: 11 | name: "{{database_name}}" 12 | encoding: "{{postgresql_encoding}}" 13 | lc_collate: "{{postgresql_locale}}" 14 | lc_ctype: "{{postgresql_locale}}" 15 | template: "template0" 16 | state: present 17 | sudo_user: "{{postgresql_admin_user}}" 18 | 19 | - name: PostgreSQL | Ensure user has access to the database 20 | postgresql_user: 21 | db: "{{ database_name }}" 22 | name: "{{ database_user }}" 23 | password: "{{ database_password }}" 24 | priv: ALL 25 | state: present 26 | login_user: "{{postgresql_admin_user}}" 27 | sudo_user: "{{postgresql_admin_user}}" 28 | 29 | - name: PostgreSQL | Ensure user does not have unnecessary privileges 30 | sudo_user: postgres 31 | postgresql_user: 32 | name: "{{ database_user }}" 33 | role_attr_flags: NOSUPERUSER,NOCREATEDB 34 | state: present 35 | sudo_user: "{{postgresql_admin_user}}" 36 | -------------------------------------------------------------------------------- /roles/postgresql/tasks/install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: PostgreSQL | Make sure the dependencies are installed 3 | apt: 4 | pkg: "{{item}}" 5 | state: present 6 | update_cache: yes 7 | cache_valid_time: "{{apt_cache_valid_time | default (3600)}}" 8 | with_items: ["python-psycopg2", "python-pycurl", "locales"] 9 | 10 | - name: PostgreSQL | Install PostgreSQL 11 | apt: 12 | name: "{{item}}" 13 | state: present 14 | update_cache: yes 15 | cache_valid_time: "{{apt_cache_valid_time | default (3600)}}" 16 | with_items: 17 | - "postgresql" 18 | - "postgresql-client" 19 | - "postgresql-contrib" 20 | 21 | - name: PostgreSQL | PGTune 22 | apt: 23 | name: pgtune 24 | state: present 25 | update_cache: yes 26 | cache_valid_time: "{{apt_cache_valid_time | default (3600)}}" 27 | when: postgresql_pgtune 28 | -------------------------------------------------------------------------------- /roles/postgresql/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include: install.yml 3 | - include: database.yml 4 | -------------------------------------------------------------------------------- /roles/supervisor/defaults/main.yml: -------------------------------------------------------------------------------- 1 | # defaults file for supervisor 2 | --- 3 | supervisor_version: latest 4 | supervisor_state: started 5 | supervisor_unix_http_server_file: /var/run/supervisor.sock 6 | supervisor_unix_http_server_chmod: '0700' 7 | 8 | supervisor_inet_http_server_enabled: false 9 | supervisor_inet_http_server_port: 9001 10 | supervisor_inet_http_server_username: admin 11 | supervisor_inet_http_server_password: 'T42GdDZPiGWe' 12 | 13 | supervisor_supervisord_logfile: /var/log/supervisor/supervisord.log 14 | supervisor_supervisord_pidfile: /var/run/supervisord.pid 15 | supervisor_supervisord_childlogdir: /var/log/supervisor 16 | 17 | supervisor_supervisorctl_serverurl: "unix://{{ supervisor_unix_http_server_file }}" 18 | 19 | supervisor_include: '/etc/supervisor/conf.d/*.conf' 20 | 21 | supervisor_programs_present: 22 | app: 23 | command: "{{ virtualenv_path }}/bin/gunicorn_start" 24 | directory: "{{application_path}}" 25 | autostart: true 26 | autorestart: true 27 | startretries: 3 28 | stdout_logfile: /var/log/supervisor/app.log 29 | stdout_logfile_maxbytes: 150MB 30 | stderr_logfile: /var/log/supervisor/error_app.log 31 | stderr_logfile_maxbytes: 150MB 32 | user: "{{ansible_ssh_user}}" 33 | 34 | supervisor_programs_absent: {} 35 | supervisor_groups_present: {} 36 | supervisor_groups_absent: {} 37 | 38 | -------------------------------------------------------------------------------- /roles/supervisor/handlers/main.yml: -------------------------------------------------------------------------------- 1 | # handlers file for supervisor 2 | --- 3 | - name: restart supervisor 4 | service: 5 | name: supervisor 6 | sleep: 3 7 | state: restarted 8 | -------------------------------------------------------------------------------- /roles/supervisor/tasks/configure.yml: -------------------------------------------------------------------------------- 1 | # tasks file for supervisor 2 | --- 3 | - name: configure | stat directories 4 | stat: 5 | path: "{{ item }}/" 6 | register: stat_directories 7 | with_items: 8 | - "{{ supervisor_configuration_file | dirname }}" 9 | - "{{ supervisor_unix_http_server_file | dirname }}" 10 | - "{{ supervisor_supervisord_logfile | dirname }}" 11 | - "{{ supervisor_supervisord_pidfile | dirname }}" 12 | - "{{ supervisor_supervisord_childlogdir }}" 13 | - "{{ supervisor_include | dirname }}" 14 | tags: 15 | - supervisor-configure-directories 16 | - supervisor-configure-directories-stat 17 | 18 | - name: configure | create directories 19 | file: 20 | path: "{{ item.item }}" 21 | state: directory 22 | owner: root 23 | group: root 24 | mode: 0755 25 | with_items: stat_directories.results 26 | when: item.stat.exists == false 27 | tags: 28 | - supervisor-configure-directories 29 | - supervisor-configure-directories-create 30 | 31 | - name: configure | update configuration file - /etc/supervisord.conf 32 | template: 33 | src: etc/supervisor/supervisord.conf.j2 34 | dest: "{{ supervisor_configuration_file }}" 35 | owner: root 36 | group: root 37 | mode: 0640 38 | notify: restart supervisor 39 | tags: 40 | - supervisor-configure-configuration 41 | - supervisor-configure-configuration-supervisord-conf 42 | 43 | - name: configure | update init script - /etc/init.d/supervisor 44 | template: 45 | src: etc/init.d/supervisor.j2 46 | dest: /etc/init.d/supervisor 47 | owner: root 48 | group: root 49 | mode: 0755 50 | notify: restart supervisor 51 | tags: 52 | - supervisor-configure-configuration 53 | - supervisor-configure-configuration-init 54 | -------------------------------------------------------------------------------- /roles/supervisor/tasks/groups.yml: -------------------------------------------------------------------------------- 1 | # tasks file for supervisor 2 | --- 3 | - name: groups | update group configuration files (present) 4 | template: 5 | src: etc/supervisor/conf.d/group.conf.j2 6 | dest: "/etc/supervisor/conf.d/{{ item.key }}.conf" 7 | owner: root 8 | group: root 9 | mode: 0640 10 | with_dict: supervisor_groups_present 11 | notify: restart supervisor 12 | tags: 13 | - supervisor-groups-present 14 | 15 | - name: groups | update group configuration files (absent) 16 | file: 17 | path: "/etc/supervisor/conf.d/{{ item.key }}.conf" 18 | state: absent 19 | with_dict: supervisor_groups_absent 20 | notify: restart supervisor 21 | tags: 22 | - supervisor-groups-absent 23 | -------------------------------------------------------------------------------- /roles/supervisor/tasks/install.yml: -------------------------------------------------------------------------------- 1 | # tasks file for supervisor 2 | --- 3 | - name: install | dependencies 4 | apt: 5 | name: "{{ item }}" 6 | state: latest 7 | update_cache: true 8 | cache_valid_time: "{{ apt_update_cache_valid_time | default(3600) }}" 9 | with_items: supervisor_dependencies 10 | tags: 11 | - supervisor-install-dependencies 12 | 13 | - name: install | supervisor (specific version) 14 | pip: 15 | name: supervisor 16 | version: "{{ supervisor_version }}" 17 | when: "supervisor_version != 'latest'" 18 | tags: 19 | - supervisor-install-specific 20 | 21 | - name: install | supervisor (latest version) 22 | pip: 23 | name: supervisor 24 | state: "{{ supervisor_version }}" 25 | when: "supervisor_version == 'latest'" 26 | tags: 27 | - supervisor-install-latest 28 | -------------------------------------------------------------------------------- /roles/supervisor/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # tasks file for supervisor 2 | --- 3 | - include: install.yml 4 | tags: 5 | - packages 6 | - supervisor 7 | 8 | - include: configure.yml 9 | tags: 10 | - packages 11 | - supervisor 12 | 13 | - include: programs.yml 14 | tags: 15 | - packages 16 | - supervisor 17 | 18 | - include: groups.yml 19 | tags: 20 | - packages 21 | - supervisor 22 | 23 | 24 | - name: Enabled the supervisor service 25 | service: name=supervisor enabled=yes 26 | tags: [packages,supervisor] 27 | 28 | - name: Start the supervisor service 29 | service: name=supervisor state=started 30 | tags: [packages,supervisor] 31 | -------------------------------------------------------------------------------- /roles/supervisor/tasks/programs.yml: -------------------------------------------------------------------------------- 1 | # tasks file for supervisor 2 | --- 3 | - name: programs | update program configuration files (present) 4 | template: 5 | src: etc/supervisor/conf.d/program.conf.j2 6 | dest: "/etc/supervisor/conf.d/{{ item.key }}.conf" 7 | owner: root 8 | group: root 9 | mode: 0640 10 | with_dict: supervisor_programs_present 11 | notify: restart supervisor 12 | tags: 13 | - supervisor-programs-present 14 | 15 | - name: programs | update program configuration files (absent) 16 | file: 17 | path: "/etc/supervisor/conf.d/{{ item.key }}.conf" 18 | state: absent 19 | with_dict: supervisor_programs_absent 20 | notify: restart supervisor 21 | tags: 22 | - supervisor-programs-absent 23 | -------------------------------------------------------------------------------- /roles/supervisor/templates/etc/init.d/supervisor.j2: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # 3 | # {{ ansible_managed }} 4 | # 5 | # Downloaded from: 6 | # http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/trusty/supervisor/trusty/view/head:/debian/supervisor.init 7 | # 8 | # skeleton example file to build /etc/init.d/ scripts. 9 | # This file should be used to construct scripts for /etc/init.d. 10 | # 11 | # Written by Miquel van Smoorenburg . 12 | # Modified for Debian 13 | # by Ian Murdock . 14 | # Further changes by Javier Fernandez-Sanguino 15 | # Modified by sbilly Added supervisorctl to status 16 | # 17 | # Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl 18 | # 19 | ### BEGIN INIT INFO 20 | # Provides: supervisor 21 | # Required-Start: $remote_fs $network $named 22 | # Required-Stop: $remote_fs $network $named 23 | # Default-Start: 2 3 4 5 24 | # Default-Stop: 0 1 6 25 | # Short-Description: Start/stop supervisor 26 | # Description: Start/stop supervisor daemon and its configured 27 | # subprocesses. 28 | ### END INIT INFO 29 | 30 | . /lib/lsb/init-functions 31 | 32 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 33 | DAEMON=/usr/local/bin/supervisord 34 | SUPERVISORCTL=/usr/local/bin/supervisorctl 35 | NAME=supervisord 36 | DESC=supervisor 37 | 38 | test -x $DAEMON || exit 0 39 | 40 | LOGDIR={{ supervisor_supervisord_logfile | dirname }} 41 | PIDFILE={{ supervisor_supervisord_pidfile }} 42 | DODTIME=5 # Time to wait for the server to die, in seconds 43 | # If this value is set too low you might not 44 | # let some servers to die gracefully and 45 | # 'restart' will not work 46 | 47 | # Include supervisor defaults if available 48 | if [ -f /etc/default/supervisor ] ; then 49 | . /etc/default/supervisor 50 | fi 51 | DAEMON_OPTS="-c {{ supervisor_configuration_file }} $DAEMON_OPTS" 52 | 53 | set -e 54 | 55 | running_pid() 56 | { 57 | # Check if a given process pid's cmdline matches a given name 58 | pid=$1 59 | name=$2 60 | [ -z "$pid" ] && return 1 61 | [ ! -d /proc/$pid ] && return 1 62 | (cat /proc/$pid/cmdline | tr "\000" "\n"|grep -q $name) || return 1 63 | return 0 64 | } 65 | 66 | running() 67 | { 68 | # Check if the process is running looking at /proc 69 | # (works for all users) 70 | 71 | # No pidfile, probably no daemon present 72 | [ ! -f "$PIDFILE" ] && return 1 73 | # Obtain the pid and check it against the binary name 74 | pid=`cat $PIDFILE` 75 | running_pid $pid $DAEMON || return 1 76 | return 0 77 | } 78 | 79 | force_stop() { 80 | # Forcefully kill the process 81 | [ ! -f "$PIDFILE" ] && return 82 | if running ; then 83 | kill -15 $pid 84 | # Is it really dead? 85 | [ -n "$DODTIME" ] && sleep "$DODTIME"s 86 | if running ; then 87 | kill -9 $pid 88 | [ -n "$DODTIME" ] && sleep "$DODTIME"s 89 | if running ; then 90 | echo "Cannot kill $NAME (pid=$pid)!" 91 | exit 1 92 | fi 93 | fi 94 | fi 95 | rm -f $PIDFILE 96 | return 0 97 | } 98 | 99 | case "$1" in 100 | start) 101 | echo -n "Starting $DESC: " 102 | start-stop-daemon --start --quiet --pidfile $PIDFILE \ 103 | --startas $DAEMON -- $DAEMON_OPTS 104 | test -f $PIDFILE || sleep 1 105 | if running ; then 106 | echo "$NAME." 107 | else 108 | echo " ERROR." 109 | fi 110 | ;; 111 | stop) 112 | echo -n "Stopping $DESC: " 113 | start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE 114 | echo "$NAME." 115 | ;; 116 | force-stop) 117 | echo -n "Forcefully stopping $DESC: " 118 | force_stop 119 | if ! running ; then 120 | echo "$NAME." 121 | else 122 | echo " ERROR." 123 | fi 124 | ;; 125 | #reload) 126 | # 127 | # If the daemon can reload its config files on the fly 128 | # for example by sending it SIGHUP, do it here. 129 | # 130 | # If the daemon responds to changes in its config file 131 | # directly anyway, make this a do-nothing entry. 132 | # 133 | # echo "Reloading $DESC configuration files." 134 | # start-stop-daemon --stop --signal 1 --quiet --pidfile \ 135 | # /var/run/$NAME.pid --exec $DAEMON 136 | #;; 137 | force-reload) 138 | # 139 | # If the "reload" option is implemented, move the "force-reload" 140 | # option to the "reload" entry above. If not, "force-reload" is 141 | # just the same as "restart" except that it does nothing if the 142 | # daemon isn't already running. 143 | # check wether $DAEMON is running. If so, restart 144 | start-stop-daemon --stop --test --quiet --pidfile $PIDFILE \ 145 | --startas $DAEMON \ 146 | && $0 restart \ 147 | || exit 0 148 | ;; 149 | restart) 150 | echo -n "Restarting $DESC: " 151 | start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE 152 | [ -n "$DODTIME" ] && sleep $DODTIME 153 | start-stop-daemon --start --quiet --pidfile $PIDFILE \ 154 | --startas $DAEMON -- $DAEMON_OPTS 155 | echo "$NAME." 156 | ;; 157 | status) 158 | echo -n "$NAME is " 159 | if running ; then 160 | echo "running" 161 | else 162 | echo " not running." 163 | exit 1 164 | fi 165 | $SUPERVISORCTL $DAEMON_OPTS status 166 | ;; 167 | *) 168 | N=/etc/init.d/$NAME 169 | # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 170 | echo "Usage: $N {start|stop|restart|force-reload|status|force-stop}" >&2 171 | exit 1 172 | ;; 173 | esac 174 | 175 | exit 0 176 | -------------------------------------------------------------------------------- /roles/supervisor/templates/etc/supervisor/conf.d/group.conf.j2: -------------------------------------------------------------------------------- 1 | [group:{{ item.key }}] 2 | programs={{ item.value.programs | join(',') }} 3 | {% if item.value.priority is defined %} 4 | priority={{ item.value.priority }} 5 | {% endif %} 6 | -------------------------------------------------------------------------------- /roles/supervisor/templates/etc/supervisor/conf.d/program.conf.j2: -------------------------------------------------------------------------------- 1 | [program:{{ item.key }}] 2 | command={{ item.value.command }} 3 | {% if item.value.directory is defined %} 4 | directory={{ item.value.directory }} 5 | {% endif %} 6 | {% if item.value.environment is defined %} 7 | environment={{ item.value.environment }} 8 | {% endif %} 9 | {% if item.value.autostart is defined %} 10 | autostart={{ 'true' if item.value.autostart | bool else 'false' }} 11 | {% endif %} 12 | {% if item.value.autorestart is defined %} 13 | autorestart={{ 'true' if item.value.autorestart | bool else 'false'}} 14 | {% endif %} 15 | {% if item.value.startretries is defined %} 16 | startretries={{ item.value.startretries }} 17 | {% endif %} 18 | {% if item.value.stdout_logfile is defined %} 19 | stdout_logfile={{ item.value.stdout_logfile }} 20 | {% endif %} 21 | {% if item.value.stdout_logfile_maxbytes is defined %} 22 | stdout_logfile_maxbytes={{ item.value.stdout_logfile_maxbytes }} 23 | {% endif %} 24 | {% if item.value.stderr_logfile is defined %} 25 | stderr_logfile={{ item.value.stderr_logfile }} 26 | {% endif %} 27 | {% if item.value.stderr_logfile_maxbytes is defined %} 28 | stderr_logfile_maxbytes={{ item.value.stderr_logfile_maxbytes }} 29 | {% endif %} 30 | {% if item.value.user is defined %} 31 | user={{ item.value.user }} 32 | {% endif %} 33 | {% if item.value.numprocs is defined %} 34 | numprocs={{ item.value.numprocs }} 35 | {% endif %} 36 | {% if item.value.process_name is defined %} 37 | process_name={{ item.value.process_name }} 38 | {% elif item.value.numprocs | default(1) > 1 %} 39 | process_name=%(program_name)s-%(process_num)s 40 | {% endif %} 41 | -------------------------------------------------------------------------------- /roles/supervisor/templates/etc/supervisor/supervisord.conf.j2: -------------------------------------------------------------------------------- 1 | ; supervisor config file 2 | 3 | [unix_http_server] 4 | file={{ supervisor_unix_http_server_file }} ; (the path to the socket file) 5 | chmod={{ supervisor_unix_http_server_chmod }} ; sockef file mode (default 0700) 6 | 7 | {% if supervisor_inet_http_server_enabled %} 8 | [inet_http_server] 9 | port = {{ supervisor_inet_http_server_port }} 10 | username = {{ supervisor_inet_http_server_username }} 11 | password = {{ supervisor_inet_http_server_password }} 12 | {% endif %} 13 | 14 | [supervisord] 15 | logfile={{ supervisor_supervisord_logfile }} ; (main log file;default $CWD/supervisord.log) 16 | pidfile={{ supervisor_supervisord_pidfile }} ; (supervisord pidfile;default supervisord.pid) 17 | childlogdir={{ supervisor_supervisord_childlogdir }} ; ('AUTO' child log dir, default $TEMP) 18 | 19 | ; the below section must remain in the config file for RPC 20 | ; (supervisorctl/web interface) to work, additional interfaces may be 21 | ; added by defining them in separate rpcinterface: sections 22 | [rpcinterface:supervisor] 23 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 24 | 25 | [supervisorctl] 26 | serverurl={{ supervisor_supervisorctl_serverurl }} ; use a unix:// URL for a unix socket 27 | 28 | ; The [include] section can just contain the "files" setting. This 29 | ; setting can list multiple files (separated by whitespace or 30 | ; newlines). It can also contain wildcards. The filenames are 31 | ; interpreted as relative to this file. Included files *cannot* 32 | ; include files themselves. 33 | 34 | [include] 35 | files = {{ supervisor_include }} 36 | -------------------------------------------------------------------------------- /roles/supervisor/vars/main.yml: -------------------------------------------------------------------------------- 1 | # vars file for supervisor 2 | --- 3 | supervisor_dependencies: 4 | - python 5 | 6 | supervisor_configuration_file: /etc/supervisord.conf 7 | -------------------------------------------------------------------------------- /server.ini: -------------------------------------------------------------------------------- 1 | [webservers] 2 | webserver1.example.com 3 | --------------------------------------------------------------------------------