@@ -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" |