@@ -0,0 +1,22 @@ | |||||
--- | |||||
openproject_user: openproject | |||||
openproject_group: openproject | |||||
openproject_path: /srv/openproject | |||||
openproject_locale: en | |||||
plugins: {} | |||||
unicorn: | |||||
socket: unix | |||||
path: '{{openproject_path}}/unicorn.sock' | |||||
host: 0.0.0.0 | |||||
port: 8042 | |||||
secret_key_base: e7fc3c2c8bec7b789b1ddbac5425c680055aadd3a3015e93f58fd5914dfebbaef30249414ea5813db5df619ebab246e96cf5b4f38d58b42452de85f5af6cf242 | |||||
memcached: | |||||
host: localhost | |||||
port: 11211 |
@@ -0,0 +1,2 @@ | |||||
require 'rails/all' | |||||
ActiveSupport::Deprecation.silenced = true |
@@ -0,0 +1 @@ | |||||
ActiveSupport::Deprecation.silenced = true |
@@ -0,0 +1,15 @@ | |||||
--- | |||||
- name: reload systemd unit files | |||||
command: systemctl daemon-reload | |||||
- name: reload nginx | |||||
service: | |||||
name: nginx | |||||
state: reloaded | |||||
- name: restart openproject | |||||
service: | |||||
name: openproject | |||||
state: restarted | |||||
listen: reload systemd unit files |
@@ -0,0 +1,91 @@ | |||||
--- | |||||
- name: create openproject environment configuration | |||||
template: | |||||
src: '{{item}}.yml.j2' | |||||
dest: '{{openproject_path}}/openproject/config/{{item}}.yml' | |||||
with_items: | |||||
- database | |||||
#- configuration | |||||
notify: restart openproject | |||||
# https://community.openproject.com/projects/openproject/work_packages/26147/activity | |||||
# - name: fix openproject bug \#26147 | |||||
# copy: | |||||
# src: "{{ item }}.rb" | |||||
# dest: '{{openproject_path}}/openproject/config/{{item}}.rb' | |||||
# with_items: | |||||
# - additional_environment | |||||
# - additional_boot | |||||
- name: set up database | |||||
command: ./bin/rake db:create | |||||
args: | |||||
chdir: '{{openproject_path}}/openproject' | |||||
become: yes | |||||
become_user: '{{openproject_user}}' | |||||
become_method: su | |||||
register: rake_db_create_all | |||||
changed_when: '"already exists" not in rake_db_create_all.stderr' | |||||
environment: | |||||
PATH: "{{openproject_env_path}}:{{ ansible_env.PATH }}" | |||||
RAILS_ENV: production | |||||
notify: restart openproject | |||||
- name: generate secret token | |||||
command: ./bin/rake generate_secret_token | |||||
args: | |||||
chdir: '{{openproject_path}}/openproject' | |||||
creates: '{{openproject_path}}/openproject/config/secret_token.yml' | |||||
become: yes | |||||
become_user: '{{openproject_user}}' | |||||
become_method: su | |||||
environment: | |||||
PATH: "{{openproject_env_path}}:{{ ansible_env.PATH }}" | |||||
RAILS_ENV: production | |||||
notify: restart openproject | |||||
- name: migrate database | |||||
command: ./bin/rake db:migrate | |||||
args: | |||||
chdir: '{{openproject_path}}/openproject' | |||||
become: yes | |||||
become_user: '{{openproject_user}}' | |||||
become_method: su | |||||
register: generate_migration | |||||
changed_when: generate_migration.stdout != "" | |||||
environment: | |||||
PATH: "{{openproject_env_path}}:{{ ansible_env.PATH }}" | |||||
RAILS_ENV: production | |||||
notify: restart openproject | |||||
- name: seed database | |||||
command: ./bin/rake db:seed | |||||
args: | |||||
chdir: '{{openproject_path}}/openproject' | |||||
become: yes | |||||
become_user: '{{openproject_user}}' | |||||
become_method: su | |||||
register: seed_database | |||||
changed_when: '"Skipping" not in seed_database.stdout' | |||||
environment: | |||||
PATH: "{{openproject_env_path}}:{{ ansible_env.PATH }}" | |||||
RAILS_ENV: production | |||||
LOCALE: "{{openproject_locale}}" | |||||
notify: restart openproject | |||||
- name: precompile assets | |||||
command: ./bin/rake assets:precompile | |||||
args: | |||||
chdir: '{{openproject_path}}/openproject' | |||||
become: yes | |||||
become_user: '{{openproject_user}}' | |||||
become_method: su | |||||
async: 3600 | |||||
poll: 1 | |||||
register: precompile_assets | |||||
changed_when: '"Writing" in seed_database.stdout' | |||||
environment: | |||||
PATH: "{{openproject_env_path}}:{{ ansible_env.PATH }}" | |||||
RAILS_ENV: production | |||||
notify: restart openproject |
@@ -0,0 +1,7 @@ | |||||
--- | |||||
- name: disable upsale block on homepage | |||||
copy: | |||||
content: "" | |||||
dest: "{{openproject_path}}/openproject/app/views/homescreen/blocks/_upsale.html.erb" | |||||
notify: restart openproject |
@@ -0,0 +1,23 @@ | |||||
--- | |||||
- name: mysql user | |||||
mysql_user: | |||||
name: "{{ openproject_database_user }}" | |||||
host: "{{ ssh_ip }}" | |||||
password: "{{ openproject_database_password }}" | |||||
priv: "{{ openproject_database_name }}.*:ALL" | |||||
delegate_to: "{{ openproject_database_host }}" | |||||
# - name: mysql database absent | |||||
# mysql_db: | |||||
# name: "{{ openproject_database_name }}" | |||||
# state: absent | |||||
# delegate_to: "{{ openproject_database_host }}" | |||||
- name: mysql database | |||||
mysql_db: | |||||
name: "{{ openproject_database_name }}" | |||||
encoding: utf8 | |||||
collation: utf8_unicode_ci | |||||
state: present | |||||
delegate_to: "{{ openproject_database_host }}" |
@@ -0,0 +1,79 @@ | |||||
--- | |||||
- name: install openproject dependencies | |||||
apt: | |||||
name: '{{item}}' | |||||
with_items: | |||||
- memcached | |||||
- default-libmysqlclient-dev | |||||
- zlib1g-dev | |||||
- build-essential | |||||
- libssl-dev | |||||
- libreadline-dev | |||||
- libyaml-dev | |||||
- libgdbm-dev | |||||
- libncurses5-dev | |||||
- automake | |||||
- imagemagick | |||||
- libmagickcore-dev | |||||
- libmagickwand-dev | |||||
- libtool | |||||
- bison | |||||
- libffi-dev | |||||
- git | |||||
- curl | |||||
- libxml2 | |||||
- libxml2-dev | |||||
- libxslt1-dev | |||||
- name: clone openproject | |||||
git: | |||||
repo: https://github.com/opf/openproject-ce.git | |||||
dest: '{{openproject_path}}/openproject' | |||||
version: stable/7 | |||||
force: yes | |||||
async: 3600 | |||||
poll: 1 | |||||
register: cloned_openproject | |||||
notify: restart openproject | |||||
# do not run this as a handler but as a task here because we will need this before | |||||
# end of playbook execution. | |||||
- name: change ownership of openproject | |||||
file: | |||||
path: '{{openproject_path}}/openproject' | |||||
owner: '{{openproject_user}}' | |||||
group: '{{openproject_group}}' | |||||
recurse: yes | |||||
- name: install bundler | |||||
gem: | |||||
name: bundler | |||||
state: present | |||||
executable: ~{{openproject_user}}/.rbenv/shims/gem | |||||
user_install: no | |||||
become: yes | |||||
become_user: '{{openproject_user}}' | |||||
become_method: su | |||||
- name: install openproject ruby dependencies | |||||
bundler: | |||||
chdir: '{{openproject_path}}/openproject' | |||||
deployment_mode: yes | |||||
extra_args: '--without postgres sqlite rmagick development test therubyracer' | |||||
executable: ~{{openproject_user}}/.rbenv/shims/bundler | |||||
become: yes | |||||
become_user: '{{openproject_user}}' | |||||
become_method: su | |||||
async: 3600 | |||||
poll: 1 | |||||
- name: install openproject node dependencies | |||||
npm: | |||||
path: '{{openproject_path}}/openproject' | |||||
executable: ~{{openproject_user}}/.nodenv/shims/npm | |||||
become: yes | |||||
become_user: '{{openproject_user}}' | |||||
become_method: su | |||||
async: 3600 | |||||
poll: 1 |
@@ -0,0 +1,46 @@ | |||||
--- | |||||
# shamelessly copied from https://github.com/fabianfreyer/ansible-openproject | |||||
- include: user.yml | |||||
- include: rbenv.yml | |||||
vars: | |||||
ruby_version: 2.4.2 | |||||
rbenv_directory: "{{openproject_path}}/.rbenv" | |||||
rbenv_user: '{{openproject_user}}' | |||||
rbenv_group: '{{openproject_group}}' | |||||
tags: ruby | |||||
- include: nodenv.yml | |||||
vars: | |||||
node_version: 6.11.5 | |||||
nodenv_directory: "{{openproject_path}}/.nodenv" | |||||
nodenv_user: '{{openproject_user}}' | |||||
nodenv_group: '{{openproject_group}}' | |||||
tags: node | |||||
- debug: | |||||
msg: RAILS_ENV=production PATH={{openproject_env_path}}:$PATH | |||||
- include: install.yml | |||||
- include: database.yml | |||||
tags: mysql | |||||
- include: memcached.yml | |||||
- include: customize.yml | |||||
- include: configure.yml | |||||
- include: unicorn.yml | |||||
- include: nginx.yml | |||||
tags: nginx | |||||
#- include: cron.yml | |||||
# tags: cron | |||||
- name: flush handlers | |||||
meta: flush_handlers |
@@ -0,0 +1,14 @@ | |||||
--- | |||||
# FIXME: the installation of memcached should probably be moved to a diferent role. | |||||
- name: install memcached | |||||
apt: | |||||
name: memcached | |||||
- name: enable memcached | |||||
service: | |||||
name: memcached | |||||
state: started | |||||
enabled: yes | |||||
# FIXME: configure memcached ports etc... |
@@ -0,0 +1,12 @@ | |||||
--- | |||||
- name: install nginx | |||||
apt: | |||||
pkg: nginx-light | |||||
- name: nginx vhost configuration | |||||
template: | |||||
src: nginx.conf.j2 | |||||
dest: /etc/nginx/nginx.conf | |||||
notify: | |||||
- reload nginx |
@@ -0,0 +1,76 @@ | |||||
--- | |||||
- name: clone nodenv | |||||
git: | |||||
repo: https://github.com/nodenv/nodenv.git | |||||
dest: "{{nodenv_directory}}" | |||||
depth: 1 | |||||
register: cloned_nodenv | |||||
- name: setup nodenv | |||||
lineinfile: | |||||
dest: ~{{nodenv_user}}/.profile | |||||
line: '{{item}}' | |||||
with_items: | |||||
- 'export PATH="{{nodenv_directory}}/bin:$PATH"' | |||||
- 'eval "$(nodenv init -)"' | |||||
- name: setup node-build | |||||
git: | |||||
repo: https://github.com/nodenv/node-build.git | |||||
dest: "{{nodenv_directory}}/plugins/node-build" | |||||
depth: 1 | |||||
register: cloned_node_build | |||||
# do not run this as a handler but as a task here because we will need this before | |||||
# end of playbook execution. | |||||
- name: change ownership of nodenv | |||||
file: | |||||
path: "{{nodenv_directory}}" | |||||
owner: '{{nodenv_user}}' | |||||
group: '{{nodenv_group}}' | |||||
recurse: yes | |||||
when: cloned_node_build.changed or cloned_nodenv.changed | |||||
- name: get installed node versions | |||||
command: nodenv versions | |||||
register: nodenv_versions | |||||
changed_when: False | |||||
failed_when: False | |||||
become: yes | |||||
become_user: '{{nodenv_user}}' | |||||
become_method: su | |||||
environment: | |||||
PATH: "{{nodenv_directory}}/bin:{{ ansible_env.PATH }}" | |||||
- name: install node | |||||
command: nodenv install {{node_version}} | |||||
when: node_version not in nodenv_versions.stdout | |||||
async: 3600 | |||||
poll: 5 | |||||
become: yes | |||||
become_user: '{{nodenv_user}}' | |||||
become_method: su | |||||
environment: | |||||
PATH: "{{nodenv_directory}}/bin:{{ ansible_env.PATH }}" | |||||
# no need to nodenv rehash here since su -c will re-source .profile anyways | |||||
- name: get selected nodenv node version | |||||
command: nodenv version | |||||
register: nodenv_version | |||||
changed_when: False | |||||
become: yes | |||||
become_user: '{{nodenv_user}}' | |||||
become_method: su | |||||
environment: | |||||
PATH: "{{nodenv_directory}}/bin:{{ ansible_env.PATH }}" | |||||
- name: select node version | |||||
command: nodenv global {{node_version}} | |||||
when: node_version not in nodenv_version.stdout | |||||
become: yes | |||||
become_user: '{{nodenv_user}}' | |||||
become_method: su | |||||
environment: | |||||
PATH: "{{nodenv_directory}}/bin:{{ ansible_env.PATH }}" |
@@ -0,0 +1,96 @@ | |||||
--- | |||||
- name: install dependencies | |||||
apt: name={{item}} | |||||
with_items: | |||||
- zlib1g-dev | |||||
- build-essential | |||||
- libssl-dev | |||||
- libreadline-dev | |||||
- libyaml-dev | |||||
- libgdbm-dev | |||||
- libncurses5-dev | |||||
- automake | |||||
- libtool | |||||
- bison | |||||
- libffi-dev | |||||
- git | |||||
- curl | |||||
- libxml2 | |||||
- libxml2-dev | |||||
- libxslt1-dev | |||||
- name: clone rbenv | |||||
git: | |||||
repo: https://github.com/rbenv/rbenv.git | |||||
dest: "{{rbenv_directory}}" | |||||
depth: 1 | |||||
register: cloned_rbenv | |||||
- name: setup rbenv | |||||
lineinfile: | |||||
dest: ~{{rbenv_user}}/.profile | |||||
line: '{{item}}' | |||||
with_items: | |||||
- 'export PATH="{{rbenv_directory}}/bin:$PATH"' | |||||
- 'eval "$(rbenv init -)"' | |||||
- name: setup ruby-build | |||||
git: | |||||
repo: https://github.com/rbenv/ruby-build.git | |||||
dest: "{{rbenv_directory}}/plugins/ruby-build" | |||||
depth: 1 | |||||
register: cloned_ruby_build | |||||
# do not run this as a handler but as a task here because we will need this before | |||||
# end of playbook execution. | |||||
- name: change ownership of rbenv | |||||
file: | |||||
path: "{{rbenv_directory}}" | |||||
owner: '{{rbenv_user}}' | |||||
group: '{{rbenv_group}}' | |||||
recurse: yes | |||||
when: cloned_ruby_build.changed or cloned_rbenv.changed | |||||
- name: get installed ruby versions | |||||
command: rbenv versions | |||||
register: rbenv_versions | |||||
changed_when: False | |||||
failed_when: False | |||||
become: yes | |||||
become_user: '{{rbenv_user}}' | |||||
become_method: su | |||||
environment: | |||||
PATH: "{{rbenv_directory}}/bin:{{ ansible_env.PATH }}" | |||||
- name: install ruby | |||||
command: rbenv install {{ruby_version}} | |||||
when: ruby_version not in rbenv_versions.stdout | |||||
async: 3600 | |||||
poll: 5 | |||||
become: yes | |||||
become_user: '{{rbenv_user}}' | |||||
become_method: su | |||||
environment: | |||||
PATH: "{{rbenv_directory}}/bin:{{ ansible_env.PATH }}" | |||||
# no need to rbenv rehash here since su -c will re-source .profile anyways | |||||
- name: get selected rbenv ruby version | |||||
command: rbenv version | |||||
register: rbenv_version | |||||
changed_when: False | |||||
become: yes | |||||
become_user: '{{rbenv_user}}' | |||||
become_method: su | |||||
environment: | |||||
PATH: "{{rbenv_directory}}/bin:{{ ansible_env.PATH }}" | |||||
- name: select ruby version | |||||
command: rbenv global {{ruby_version}} | |||||
when: ruby_version not in rbenv_version.stdout | |||||
become: yes | |||||
become_user: '{{rbenv_user}}' | |||||
become_method: su | |||||
environment: | |||||
PATH: "{{rbenv_directory}}/bin:{{ ansible_env.PATH }}" |
@@ -0,0 +1,14 @@ | |||||
--- | |||||
- name: install openproject | |||||
template: | |||||
src: openproject.service.j2 | |||||
dest: /etc/systemd/system/openproject.service | |||||
notify: | |||||
- reload systemd unit files | |||||
- name: enable openproject | |||||
service: | |||||
name: openproject | |||||
enabled: yes | |||||
state: started |
@@ -0,0 +1,22 @@ | |||||
--- | |||||
- name: create openproject group | |||||
group: | |||||
name: '{{openproject_group}}' | |||||
system: yes | |||||
- name: create openproject user | |||||
user: | |||||
name: '{{openproject_user}}' | |||||
group: '{{openproject_group}}' | |||||
home: '{{openproject_path}}' | |||||
system: yes | |||||
shell: /bin/bash | |||||
- name: openproject user directory | |||||
file: | |||||
path: '{{openproject_path}}' | |||||
owner: '{{openproject_user}}' | |||||
group: '{{openproject_group}}' | |||||
recurse: yes | |||||
state: directory |
@@ -0,0 +1,21 @@ | |||||
--- | |||||
{# | |||||
default: | |||||
{% if mail_method == "sendmail" %} | |||||
email_delivery_method: :sendmail | |||||
{% elif mail_method == "smtp" %} | |||||
email_delivery_method: :{{mail_method}} | |||||
smtp_address: {{smtp_host}} | |||||
smtp_port: {{smtp_port}} | |||||
smtp_domain: {{smtp_domain}} | |||||
smtp_user_name: {{smtp_user}} | |||||
smtp_password: {{smtp_password}} | |||||
smtp_enable_starttls_auto: true | |||||
smtp_authentication: {{smtp_auth}} | |||||
rails_force_ssl: false | |||||
rails_cache_store: :memcache | |||||
{%endif%} | |||||
#} |
@@ -0,0 +1,41 @@ | |||||
production: | |||||
adapter: mysql2 | |||||
database: {{ openproject_database_name }} | |||||
host: {{ openproject_database_host }} | |||||
username: {{ openproject_database_user }} | |||||
password: {{ openproject_database_password }} | |||||
encoding: utf8 | |||||
variables: | |||||
# These are the default MySql Modes for rails 5.0 only excluding | |||||
# ONLY_FULL_GROUP_BY which would interfere with the current implementation | |||||
# of the query grouping by custom fields. | |||||
sql_mode: | |||||
"no_auto_value_on_zero,\ | |||||
strict_trans_tables,\ | |||||
no_zero_date,\ | |||||
strict_all_tables,\ | |||||
no_zero_in_date,\ | |||||
error_for_division_by_zero,\ | |||||
no_auto_create_user,\ | |||||
no_engine_substitution" | |||||
development: | |||||
adapter: mysql2 | |||||
database: {{ openproject_database_name }} | |||||
host: {{ openproject_database_host }} | |||||
username: {{ openproject_database_user }} | |||||
password: {{ openproject_database_password }} | |||||
encoding: utf8 | |||||
variables: | |||||
# These are the default MySql Modes for rails 5.0 only excluding | |||||
# ONLY_FULL_GROUP_BY which would interfere with the current implementation | |||||
# of the query grouping by custom fields. | |||||
sql_mode: | |||||
"no_auto_value_on_zero,\ | |||||
strict_trans_tables,\ | |||||
no_zero_date,\ | |||||
strict_all_tables,\ | |||||
no_zero_in_date,\ | |||||
error_for_division_by_zero,\ | |||||
no_auto_create_user,\ | |||||
no_engine_substitution" |
@@ -0,0 +1,111 @@ | |||||
user www-data; | |||||
worker_processes auto; | |||||
pid /run/nginx.pid; | |||||
include /etc/nginx/modules-enabled/*.conf; | |||||
events { | |||||
worker_connections 768; | |||||
# multi_accept on; | |||||
} | |||||
http { | |||||
## | |||||
# Basic Settings | |||||
## | |||||
sendfile on; | |||||
tcp_nopush on; | |||||
tcp_nodelay on; | |||||
keepalive_timeout 65; | |||||
types_hash_max_size 2048; | |||||
# server_tokens off; | |||||
server_names_hash_bucket_size 64; | |||||
# server_name_in_redirect off; | |||||
include /etc/nginx/mime.types; | |||||
default_type application/octet-stream; | |||||
## | |||||
# SSL Settings | |||||
## | |||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE | |||||
ssl_prefer_server_ciphers on; | |||||
## | |||||
# Logging Settings | |||||
## | |||||
access_log /var/log/nginx/access.log; | |||||
error_log /var/log/nginx/error.log; | |||||
## | |||||
# Gzip Settings | |||||
## | |||||
gzip on; | |||||
gzip_disable "msie6"; | |||||
# gzip_vary on; | |||||
# gzip_proxied any; | |||||
# gzip_comp_level 6; | |||||
# gzip_buffers 16 8k; | |||||
# gzip_http_version 1.1; | |||||
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; | |||||
## | |||||
# Virtual Host Configs | |||||
## | |||||
include /etc/nginx/conf.d/*.conf; | |||||
upstream openproject { | |||||
{% if unicorn.socket == "unix" %} | |||||
server unix:{{unicorn.path}} fail_timeout=0; | |||||
{% elif unicorn.socket == "tcp" %} | |||||
server {{unicorn.host}}:{{unicorn.port}} fail_timeout=0; | |||||
{% endif %} | |||||
} | |||||
{% if false %} | |||||
server { | |||||
server_name {{inventory_hostname}}; | |||||
return 301 https://$server_name$request_uri; | |||||
} | |||||
{% endif %} | |||||
server { | |||||
server_name {{inventory_hostname}}; | |||||
{% if false %} | |||||
listen 443 ssl default_server; | |||||
listen [::]:443 ssl default_server; | |||||
ssl_certificate /etc/letsencrypt/live/{{hostname}}/fullchain.pem; | |||||
ssl_certificate_key /etc/letsencrypt/live/{{hostname}}/privkey.pem; | |||||
{% else %} | |||||
listen 80 default_server; | |||||
listen [::]:80 default_server; | |||||
{% endif %} | |||||
root {{openproject_path}}/openproject/public; | |||||
try_files $uri/index.html $uri @openproject; | |||||
location @openproject { | |||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |||||
proxy_set_header Host $http_host; | |||||
proxy_redirect off; | |||||
proxy_pass http://openproject; | |||||
} | |||||
error_page 500 502 503 504 /500.html; | |||||
error_page 422 /422.html; | |||||
error_page 404 /404.html; | |||||
#client_max_body_size 4G; | |||||
#keepalive_timeout 10; | |||||
} | |||||
} |
@@ -0,0 +1,22 @@ | |||||
[Unit] | |||||
Description=Openproject in a Unicorn | |||||
Requires=network.target | |||||
#Requires=nginx.service | |||||
Before=nginx.service | |||||
[Service] | |||||
Type=simple | |||||
{% if unicorn.socket == "tcp" %} | |||||
ExecStart=/bin/sh -l -c "bundle exec unicorn --port {{unicorn.port}} --host {{unicorn.host}} --env production" | |||||
{% elif unicorn.socket == "unix" %} | |||||
ExecStart=/bin/sh -l -c "bundle exec unicorn --listen {{unicorn.path}} --env production" | |||||
{% endif %} | |||||
PrivateTmp=yes | |||||
User={{openproject_user}} | |||||
Group={{openproject_group}} | |||||
WorkingDirectory={{openproject_path}}/openproject | |||||
Restart=always | |||||
Environment="SECRET_KEY_BASE={{secret_key_base}}" | |||||
[Install] | |||||
WantedBy=multiuser.target |
@@ -0,0 +1 @@ | |||||
openproject_env_path: "{{openproject_path}}/.rbenv/bin:{{openproject_path}}/.rbenv/shims:{{openproject_path}}/.nodenv/bin:{{openproject_path}}/.nodenv/shims" |