commit a6b16394ed4979ae3d43f80145e7bd1be810cd6f Author: phil Date: Wed Jul 28 18:28:22 2021 +0200 Zammad-Rolle diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..241f238 --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,22 @@ +--- +debian_version: buster + +ruby_path: "{{ zammad_user_home }}/.rbenv" +ruby_bin_path: "{{ ruby_path }}/versions/{{ ruby_version }}/bin" +ruby_build_repo: https://github.com/rbenv/ruby-build.git +ruby_version: 2.6.6 + +zammad_database_name: zammad +zammad_database_password: "{{ lookup('password', '/tmp/zammad_database_pwd length=42 chars=ascii_letters,digits') }}" +zammad_database_user: zammad +zammad_database_configuration: "{{ zammad_home }}/config/database.yml" +zammad_home: /opt/zammad +zammad_host: support.sao +zammad_log_file: zammad.log +zammad_log_name: zammad +zammad_log_path: /var/log/zammad +zammad_repo: https://github.com/zammad/zammad.git +zammad_user: zammad +zammad_user_home: "/home/{{ zammad_user }}" +zammad_version: 4.1.0 +zammad_webserver_configuration: "/etc/nginx/sites-available/{{ zammad_domain }}" diff --git a/files/plain-text.patch b/files/plain-text.patch new file mode 100644 index 0000000..c821a8e --- /dev/null +++ b/files/plain-text.patch @@ -0,0 +1,10 @@ +--- app/models/channel/email_build.rb.orig 2021-07-27 18:03:57.295467567 +0200 ++++ app/models/channel/email_build.rb 2021-07-27 18:04:20.705471697 +0200 +@@ -62,6 +62,7 @@ + + # generate plain part + attr[:body] = attr[:body].html2text ++ html_alternative = false + end + + # add plain text part diff --git a/files/zammad.env b/files/zammad.env new file mode 100644 index 0000000..a09da44 --- /dev/null +++ b/files/zammad.env @@ -0,0 +1,6 @@ +BUNDLE_BINARY="rbenv exec bundle" +RAILS_ENV=production +RAILS_SERVE_STATIC_FILES=true +ZAMMAD_BIND_IP=127.0.0.1 +ZAMMAD_RAILS_PORT=3000 +ZAMMAD_WEBSOCKET_PORT=6042 diff --git a/files/zammad.service b/files/zammad.service new file mode 100644 index 0000000..d27f3e3 --- /dev/null +++ b/files/zammad.service @@ -0,0 +1,18 @@ +[Unit] +Description=Zammad +After=syslog.target +After=network.target +StopWhenUnneeded=true +Wants=zammad-rails.service +Wants=zammad-scheduler.service +Wants=zammad-websocket.service + +[Service] +EnvironmentFile=/etc/zammad/zammad.env +User=zammad +Group=zammad +Restart=always +ExecStart=/bin/sleep infinity + +[Install] +WantedBy=multi-user.target diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..f502aec --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,21 @@ +--- +- name: reload monit + service: + name: monit + state: reloaded + +- name: reload nginx + service: + name: nginx + state: reloaded + +- name: reload reverse_proxy + service: + name: nginx + state: reloaded + delegate_to: "{{ gateway_host }}" + +- name: reload rsyslog + service: + name: rsyslog + state: reloaded diff --git a/meta/main.yml b/meta/main.yml new file mode 100644 index 0000000..aaa796e --- /dev/null +++ b/meta/main.yml @@ -0,0 +1,10 @@ +galaxy_info: + author: systemausfall.org + description: Install Zammad ticket system from source + company: Sense.Lab e.V. + license: GPLv3 + min_ansible_version: 2.9 + platforms: + - name: Debian + versions: + - Buster diff --git a/tasks/database.yml b/tasks/database.yml new file mode 100644 index 0000000..0f22f98 --- /dev/null +++ b/tasks/database.yml @@ -0,0 +1,52 @@ +--- +- name: "database: Datenbank anlegen" + postgresql_db: + name: "{{ zammad_database_name }}" + encoding: UTF8 + template: template0 + become: true + become_user: postgres + delegate_to: "{{ database_host }}" + +- name: "database: Benutzer einrichten" + postgresql_user: + name: "{{ zammad_database_user }}" + password: "{{ zammad_database_password }}" + db: "{{ zammad_database_name }}" + become: true + become_user: postgres + delegate_to: "{{ database_host }}" + +- name: "database: Konfiguration kopieren" + template: + src: database.yml.j2 + dest: "{{ zammad_database_configuration }}" + +- name: "database: Stoppe Service" + service: + name: zammad + state: stopped + register: unused_disable + failed_when: "unused_disable is failed and ('find' not in unused_disable.msg and 'found' not in unused_disable.msg)" + +- name: "database: Führe Migrationen aus" + shell: "RAILS_ENV=production rbenv exec bundle exec rake db:migrate" + args: + chdir: "{{ zammad_home }}" + become: true + become_user: "{{ zammad_user }}" + +- name: "database: Führe Seeds aus" + shell: "RAILS_ENV=production rbenv exec bundle exec rake db:seed" + args: + chdir: "{{ zammad_home }}" + become: true + become_user: "{{ zammad_user }}" + when: zammad_database_configured.stat.exists == False + +- name: "database: Precompile Assets" + shell: "RAILS_ENV=production rbenv exec bundle exec rake assets:precompile" + args: + chdir: "{{ zammad_home }}" + become: true + become_user: "{{ zammad_user }}" diff --git a/tasks/gateway.yml b/tasks/gateway.yml new file mode 100644 index 0000000..e2c18ff --- /dev/null +++ b/tasks/gateway.yml @@ -0,0 +1,29 @@ +--- +- name: "gateway: Domain zur Zertifikatsliste hinzufügen" + lineinfile: + path: /etc/dehydrated/domains.txt + insertafter: "^### systemausfall" + line: "{{ zammad_domain }}" + when: "'dehydrated' in ansible_facts.packages" + register: add_certificate + delegate_to: "{{ gateway_host }}" + +- name: "gateway: Zertifikat erstellen" + command: dehydrated --cron -g + when: add_certificate.changed + delegate_to: "{{ gateway_host }}" + +- name: "gateway: Proxy einrichten" + template: + src: nginx-rp-site.j2 + dest: "/etc/nginx/sites-available/{{ zammad_domain }}" + force: no + delegate_to: "{{ gateway_host }}" + +- name: "gateway: Seite aktivieren" + file: + src: "/etc/nginx/sites-available/{{ zammad_domain }}" + dest: "/etc/nginx/sites-enabled/{{ zammad_domain }}" + state: link + notify: reload reverse_proxy + delegate_to: "{{ gateway_host }}" diff --git a/tasks/locales.yml b/tasks/locales.yml new file mode 100644 index 0000000..f65d06c --- /dev/null +++ b/tasks/locales.yml @@ -0,0 +1,4 @@ +- name: "locales: Richte locales ein" + locale_gen: + name: en_US.UTF-8 + state: present diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..442b1a1 --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,17 @@ +- name: "Prüfe vorhandene Datenbank-Konfiguration" + stat: + path: "{{ zammad_database_configuration }}" + register: zammad_database_configured + +- import_tasks: packages.yml +- import_tasks: locales.yml +- import_tasks: user.yml +- import_tasks: zammad.yml +- import_tasks: ruby.yml +- import_tasks: database.yml +- import_tasks: syslog.yml +- import_tasks: webserver.yml +- import_tasks: systemd.yml +- import_tasks: monit.yml + tags: monit +- import_tasks: gateway.yml diff --git a/tasks/monit.yml b/tasks/monit.yml new file mode 100644 index 0000000..77b6689 --- /dev/null +++ b/tasks/monit.yml @@ -0,0 +1,5 @@ +- name: "monit: Kopiere Konfiguration" + template: + src: monit.j2 + dest: /etc/monit/conf-enabled/zammad + notify: reload monit diff --git a/tasks/packages.yml b/tasks/packages.yml new file mode 100644 index 0000000..a730698 --- /dev/null +++ b/tasks/packages.yml @@ -0,0 +1,37 @@ +--- +- name: "packages: Fakten sammeln" + package_facts: + manager: apt + +- name: "packages: Abhängigkeiten installieren" + apt: + default_release: "{{ debian_version }}" + pkg: + - autoconf + - automake + - autotools-dev + - bison + - build-essential + - curl + - gawk + - git + - libffi-dev + - libgdbm-dev + - libgmp-dev + - libimlib2-dev + - libncurses5-dev + - libpq-dev + - libreadline-dev + - libssl-dev + - libtool + - libxml2-dev + - libxslt1-dev + - libyaml-0-2 + - libyaml-dev + - locales + - nginx-light + - patch + - pkg-config + - rbenv + - sudo + - zlib1g-dev diff --git a/tasks/ruby.yml b/tasks/ruby.yml new file mode 100644 index 0000000..6a71317 --- /dev/null +++ b/tasks/ruby.yml @@ -0,0 +1,50 @@ +- name: "ruby: rbenv einrichten" + lineinfile: + path: "{{ zammad_user_home }}/.bashrc" + line: eval "$(rbenv init -)" + +- name: "ruby: rbenv plugin-verzeichnis erstellen" + file: + path: "{{ ruby_path }}/plugins" + state: directory + owner: "{{ zammad_user }}" + group: "{{ zammad_user }}" + +- name: "ruby: ruby-build installieren" + git: + repo: "{{ ruby_build_repo }}" + dest: "{{ ruby_path }}/plugins/ruby-build" + +- name: "ruby: Version prüfen" + stat: + path: "{{ ruby_path }}/versions/{{ ruby_version }}" + register: ruby_installed + +- name: "ruby installieren" + command: + cmd: "rbenv install {{ ruby_version }}" + chdir: "{{ zammad_user_home }}" + become: true + become_user: "{{ zammad_user }}" + when: ruby_installed.stat.exists == False + +- name: "ruby aktivieren" + shell: "rbenv local {{ ruby_version }}" + args: + chdir: "{{ zammad_home }}" + become: true + become_user: "{{ zammad_user }}" + +- name: "ruby: Bundler installieren" + command: + cmd: rbenv exec gem install bundler + chdir: "{{ zammad_home }}" + become: true + become_user: "{{ zammad_user }}" + +- name: "ruby: Ruby-Abhängigkeiten installieren" + shell: "RAILS_ENV=production {{ ruby_bin_path }}/bundle install --without test development mysql" + args: + chdir: "{{ zammad_home }}" + become: true + become_user: "{{ zammad_user }}" diff --git a/tasks/syslog.yml b/tasks/syslog.yml new file mode 100644 index 0000000..d3e21a8 --- /dev/null +++ b/tasks/syslog.yml @@ -0,0 +1,10 @@ +- name: "syslog: Erstelle Verzeichnis" + file: + src: "{{ zammad_home }}/log" + dest: "{{ zammad_log_path }}" + state: link + +- name: "syslog: Konfiguriere logrotate" + template: + src: logrotate.j2 + dest: /etc/logrotate.d/zammad diff --git a/tasks/systemd.yml b/tasks/systemd.yml new file mode 100644 index 0000000..88f6bcc --- /dev/null +++ b/tasks/systemd.yml @@ -0,0 +1,32 @@ +- name: "systemd: Kopiere Services" + template: + src: "systemd/{{ item }}.j2" + dest: "/etc/systemd/system/{{ item }}" + loop: + - zammad-rails.service + - zammad-scheduler.service + - zammad-websocket.service + +- name: "systemd: Kopiere Zammad-Service" + copy: + src: zammad.service + dest: /etc/systemd/system/zammad.service + +- name: "systemd: Erstelle Konfigurationsverzeichnis" + file: + path: /etc/zammad + state: directory + +- name: "systemd: Kopiere Konfiguration" + copy: + src: zammad.env + dest: /etc/zammad/zammad.env + force: no + +- name: "systemd: Aktiviere Service" + systemd: + enabled: yes + daemon_reload: yes + state: started + name: zammad + diff --git a/tasks/user.yml b/tasks/user.yml new file mode 100644 index 0000000..f8231f8 --- /dev/null +++ b/tasks/user.yml @@ -0,0 +1,6 @@ +--- +- name: "user: Systemkonto anlegen" + user: + name: "{{ zammad_user }}" + shell: /bin/bash + password_lock: yes diff --git a/tasks/webserver.yml b/tasks/webserver.yml new file mode 100644 index 0000000..9dce030 --- /dev/null +++ b/tasks/webserver.yml @@ -0,0 +1,12 @@ +- name: "webserver: Konfiguration kopieren" + template: + src: nginx-site.j2 + dest: "{{ zammad_webserver_configuration }}" + +- name: "webserver: Kofiguration aktivieren" + file: + src: "{{ zammad_webserver_configuration }}" + dest: "/etc/nginx/sites-enabled/{{ zammad_domain }}" + state: link + + diff --git a/tasks/zammad.yml b/tasks/zammad.yml new file mode 100644 index 0000000..75965a2 --- /dev/null +++ b/tasks/zammad.yml @@ -0,0 +1,20 @@ +- name: "zammad: Hole Zammad Repo" + git: + repo: "{{ zammad_repo }}" + dest: "{{ zammad_home }}" + version: "{{ zammad_version }}" + force: yes + +- name: "zammad: Ändere Besitzrechte" + file: + path: "{{ zammad_home }}" + state: directory + recurse: yes + owner: "{{ zammad_user }}" + group: "{{ zammad_user }}" + +# https://github.com/zammad/zammad/issues/325 +- name: "zammad: Wende plain-Text-Patch an" + patch: + src: plain-text.patch + dest: "{{ zammad_home }}/app/models/channel/email_build.rb" diff --git a/templates/database.yml.j2 b/templates/database.yml.j2 new file mode 100644 index 0000000..7363e47 --- /dev/null +++ b/templates/database.yml.j2 @@ -0,0 +1,44 @@ +# this is a database config sample for zammad ready to use with a postgresql db +# copy or symlink this file to config/database.yml to use it + +default: &default + # For details on connection pooling, see Rails configuration guide + # http://guides.rubyonrails.org/configuring.html#database-pooling + pool: 50 + timeout: 5000 + encoding: utf8 + + ##### postgresql config ##### + + adapter: postgresql + username: {{ zammad_database_user }} + password: {{ zammad_database_password }} + + # If the database server is not on localhost, you can set hostname and port: + host: {{ database_host }} + # port: + + #### mysql config ##### + + # adapter: mysql2 + # username: zammad + # password: + + # If the database server is not on localhost, you can set hostname and port: + # host: + # port: + +production: + <<: *default + database: {{ zammad_database_name }} + +development: + <<: *default + database: zammad_development + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + <<: *default + database: zammad_test diff --git a/templates/logrotate.j2 b/templates/logrotate.j2 new file mode 100644 index 0000000..2d793e7 --- /dev/null +++ b/templates/logrotate.j2 @@ -0,0 +1,9 @@ +{{ zammad_log_path }}/*.log { + daily + missingok + rotate 2 + compress + delaycompress + notifempty + copytruncate +} diff --git a/templates/monit.j2 b/templates/monit.j2 new file mode 100644 index 0000000..18c6d5f --- /dev/null +++ b/templates/monit.j2 @@ -0,0 +1,23 @@ +check process zammad-rails with pidfile {{ zammad_home }}/tmp/pids/server.pid + start program = "/usr/sbin/service zammad-rails start" + stop program = "/usr/sbin/service zammad-rails stop" + if 2 restarts within 3 cycles then timeout + if cpu usage > 95% for 3 cycles then restart + if failed host 127.0.0.1 port 3000 for 3 cycles then restart + if 5 restarts within 5 cycles then timeout + +check process zammad-websocket + matching "script/websocket-server.rb -b 127.0.0.1 -p 6042 start" + start program = "/usr/sbin/service zammad-websocket start" + stop program = "/usr/sbin/service zammad-websocket stop" + if 2 restarts within 3 cycles then timeout + if cpu usage > 95% for 3 cycles then restart + if failed host 127.0.0.1 port 6042 for 3 cycles then restart + if 5 restarts within 5 cycles then timeout + +check process zammad-scheduler with pidfile {{ zammad_home }}/tmp/pids/scheduler.pid + start program = "/usr/sbin/service zammad-scheduler start" + stop program = "/usr/sbin/service zammad-scheduler stop" + if 2 restarts within 3 cycles then timeout + if cpu usage > 95% for 3 cycles then restart + if 5 restarts within 5 cycles then timeout diff --git a/templates/nginx-rp-site.j2 b/templates/nginx-rp-site.j2 new file mode 100644 index 0000000..f155d0c --- /dev/null +++ b/templates/nginx-rp-site.j2 @@ -0,0 +1,21 @@ +server { + listen 80; + server_name {{ zammad_domain }}; + include snippets/letsencrypt.conf; + location / { return 301 https://$http_host$request_uri; } +} + +server { + listen 443 ssl http2; + server_name {{ zammad_domain }}; + ssl_certificate /var/lib/dehydrated/certs/{{ zammad_domain }}/fullchain.pem; + ssl_certificate_key /var/lib/dehydrated/certs/{{ zammad_domain }}/privkey.pem; + include /etc/nginx/snippets/add_headers.conf; + location /ws { + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + proxy_pass http://{{ zammad_host }}:80; + } + location / { proxy_pass http://{{ zammad_host }}:80; } +} diff --git a/templates/nginx-site.j2 b/templates/nginx-site.j2 new file mode 100644 index 0000000..90ebff2 --- /dev/null +++ b/templates/nginx-site.j2 @@ -0,0 +1,35 @@ +server { + listen 80; + server_name {{ zammad_domain }}; + + root {{ zammad_home }}/public; + error_log /var/log/nginx/{{ zammad_domain }}.error.log; + + client_max_body_size 50M; + + location ~ ^/(assets/|robots.txt|humans.txt|favicon.ico|apple-touch-icon.png) { + expires max; + } + + location /ws { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header CLIENT_IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 86400; + proxy_pass http://127.0.0.1:6042; + } + + location / { + proxy_set_header Host $http_host; + proxy_set_header CLIENT_IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + # Change this line in an SSO setup + proxy_set_header X-Forwarded-User ""; + proxy_read_timeout 300; + proxy_pass http://127.0.0.1:3000; + } +} diff --git a/templates/syslog.j2 b/templates/syslog.j2 new file mode 100644 index 0000000..026c65e --- /dev/null +++ b/templates/syslog.j2 @@ -0,0 +1 @@ +if $programname == '{{ zammad_log_name }}' then { action(type="omfile" file="{{ zammad_log_path }}/{{ zammad_log_file }}") stop } diff --git a/templates/systemd/zammad-rails.service.j2 b/templates/systemd/zammad-rails.service.j2 new file mode 100644 index 0000000..2f065e9 --- /dev/null +++ b/templates/systemd/zammad-rails.service.j2 @@ -0,0 +1,19 @@ +[Unit] +Description=Zammad rails server +After=syslog.target +After=network.target +After=zammad.service +Requires=zammad.service + +[Service] +EnvironmentFile=/etc/zammad/zammad.env +User=zammad +Group=zammad +Restart=always + +WorkingDirectory={{ zammad_home }} + +ExecStart=/bin/bash -l -c "${BUNDLE_BINARY} exec script/rails server -b ${ZAMMAD_BIND_IP} -p ${ZAMMAD_RAILS_PORT}" + +[Install] +WantedBy=zammad.service diff --git a/templates/systemd/zammad-scheduler.service.j2 b/templates/systemd/zammad-scheduler.service.j2 new file mode 100644 index 0000000..dd643bf --- /dev/null +++ b/templates/systemd/zammad-scheduler.service.j2 @@ -0,0 +1,20 @@ +[Unit] +Description=Zammad scheduler +After=syslog.target +After=network.target +After=zammad.service +Requires=zammad.service + +[Service] +Type=forking +EnvironmentFile=/etc/zammad/zammad.env +User=zammad +Group=zammad +Restart=always + +WorkingDirectory={{ zammad_home }} + +ExecStart=/bin/bash -l -c "${BUNDLE_BINARY} exec script/scheduler.rb start" + +[Install] +WantedBy=zammad.service diff --git a/templates/systemd/zammad-websocket.service.j2 b/templates/systemd/zammad-websocket.service.j2 new file mode 100644 index 0000000..2535eb1 --- /dev/null +++ b/templates/systemd/zammad-websocket.service.j2 @@ -0,0 +1,19 @@ +[Unit] +Description=Zammad websocket +After=syslog.target +After=network.target +After=zammad.service +Requires=zammad.service + +[Service] +EnvironmentFile=/etc/zammad/zammad.env +User=zammad +Group=zammad +Restart=always + +WorkingDirectory={{ zammad_home }} + +ExecStart=/bin/bash -l -c "${BUNDLE_BINARY} exec script/websocket-server.rb -b ${ZAMMAD_BIND_IP} -p ${ZAMMAD_WEBSOCKET_PORT} start" + +[Install] +WantedBy=zammad.service