diff --git a/library/roles/shinyproxy/defaults/main.yml b/library/roles/shinyproxy/defaults/main.yml index d10211ea..f5f9fe01 100644 --- a/library/roles/shinyproxy/defaults/main.yml +++ b/library/roles/shinyproxy/defaults/main.yml @@ -1,19 +1,38 @@ --- +# https://shinyproxy.io/ shinyproxy_install: False -shinyproxy_version: 1.1.1 +shinyproxy_major_ver: 2 +shinyproxy_minor_ver: 3 +shinyproxy_patch_ver: 0 +#shinyproxy_version: 1.1.1 +shinyproxy_version: '{{ shinyproxy_major_ver }}.{{ shinyproxy_minor_ver }}.{{ shinyproxy_patch_ver }}' shinyproxy_file_name: 'shinyproxy-{{ shinyproxy_version }}.jar' shinyproxy_url: 'https://www.shinyproxy.io/downloads/{{ shinyproxy_file_name }}' shinyproxy_app_name: shinyproxy.jar shinyproxy_user: shinyproxy shinyproxy_install_dir: /opt/shinyproxy +shinyproxy_log_dir: /var/log/shinyproxy +shinyproxy_bind_address: 127.0.0.1 shinyproxy_http_port: 8080 # For logrotate. In days shinyproxy_log_retention: 10 shinyproxy_default_apps: True -shinyproxy_docker_url: 'http://localhost:2375' +# docker, docker-swarm, kubernetes +shinyproxy_container_backend: 'docker' +shinyproxy_docker_port: 2375 +shinyproxy_docker_host: 'localhost' +shinyproxy_docker_protocol: http +shinyproxy_docker_certs_dir: /etc/pki/shinyproxy +shinyproxy_docker_url: '{{ shinyproxy_docker_protocol }}://{{ shinyproxy_docker_host }}:{{ shinyproxy_docker_port }}' shinyproxy_docker_port_range_start: 20000 +shinyproxy_docker_cpu_limit: 1 +shinyproxy_docker_memory_request: '1g' +shinyproxy_docker_memory_limit: '2g' shinyproxy_container_wait_time: 60000 +shinyproxy_docker_loglevel: 'INFO' shinyproxy_hide_navbar: 'false' +shinyproxy_custom_template: False +shinyproxy_template_path: '{{ shinyproxy_install_dir }}/web_templates' shinyproxy_app_title: 'Open Analytics Shiny Proxy' shinyproxy_logo_url: 'http://www.openanalytics.eu/sites/www.openanalytics.eu/themes/oa/logo.png' @@ -32,3 +51,5 @@ shinyproxy_ldap_user_search_filter_enabled: True shinyproxy_ldap_user_search_filter: '(uid={0})' shinyproxy_ldap_group_search_base: '' shinyproxy_ldap_group_search_filter: '(uniqueMember={0})' + +shinyproxy_max_log_size: 20MB diff --git a/library/roles/shinyproxy/meta/main.yml b/library/roles/shinyproxy/meta/main.yml new file mode 100644 index 00000000..755ffdc7 --- /dev/null +++ b/library/roles/shinyproxy/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - { role: '../../library/roles/openjdk' } diff --git a/library/roles/shinyproxy/tasks/main.yml b/library/roles/shinyproxy/tasks/main.yml index 28e5ddd5..91841e6a 100644 --- a/library/roles/shinyproxy/tasks/main.yml +++ b/library/roles/shinyproxy/tasks/main.yml @@ -1,40 +1,124 @@ --- - block: - - name: Create the shinyproxy user - user: name={{ shinyproxy_user }} home={{ shinyproxy_install_dir }} createhome=yes system=yes shell=/usr/sbin/nologin + - name: Create the shinyproxy user + user: name={{ shinyproxy_user }} home={{ shinyproxy_install_dir }} createhome=yes system=yes shell=/usr/sbin/nologin - - name: Download the shinyproxy jar - become: True - become_user: '{{ shinyproxy_user }}' - get_url: url={{ shinyproxy_url }} dest={{ shinyproxy_install_dir }} + - name: Download the shinyproxy jar + become: True + become_user: '{{ shinyproxy_user }}' + get_url: url={{ shinyproxy_url }} dest={{ shinyproxy_install_dir }} - - name: Set up a symlink to an unversioned app name - become: True - become_user: '{{ shinyproxy_user }}' - file: src={{ shinyproxy_install_dir }}/{{ shinyproxy_file_name }} dest={{ shinyproxy_install_dir }}/{{ shinyproxy_app_name }} state=link + - name: Set up a symlink to an unversioned app name + become: True + become_user: '{{ shinyproxy_user }}' + file: src={{ shinyproxy_install_dir }}/{{ shinyproxy_file_name }} dest={{ shinyproxy_install_dir }}/{{ shinyproxy_app_name }} state=link - - name: Install the upstart init file - template: src=upstart-shinyproxy.conf.j2 dest=/etc/init/shinyproxy.conf owner=root group=root mode=0644 - when: is_trusty + - name: Install the shinyproxy configuration file when using version 1.x + template: src=shinyproxy-1-conf.yml.j2 dest={{ shinyproxy_install_dir }}/application.yml owner=root group={{ shinyproxy_user }} mode=0640 + notify: Restart shinyproxy + when: shinyproxy_major_ver == 1 + tags: [ 'shinyproxy', 'shinyproxy_conf', 'shinyproxy_images' ] - - name: Install the shinyproxy configuration file - template: src=shinyproxy-conf.yml.j2 dest={{ shinyproxy_install_dir }}/application.yml owner=root group={{ shinyproxy_user }} mode=0640 - notify: Restart shinyproxy - tags: [ 'shinyproxy', 'shinyproxy_conf', 'shinyproxy_images' ] + - name: Install the shinyproxy configuration file when using version 2.x + template: src=shinyproxy-2-conf.yml.j2 dest={{ shinyproxy_install_dir }}/application.yml owner=root group={{ shinyproxy_user }} mode=0640 + notify: Restart shinyproxy + when: shinyproxy_major_ver == 2 + tags: [ 'shinyproxy', 'shinyproxy_conf', 'shinyproxy_images' ] - - name: Install the shinyproxy logrotate configuration - template: src=shinyproxy-logrotate.j2 dest=/etc/logrotate.d/shinyproxy owner=root group=root mode=0444 - tags: [ 'shinyproxy', 'shinyproxy_conf' ] + - name: Install the shinyproxy logrotate configuration + template: src=shinyproxy-logrotate.j2 dest=/etc/logrotate.d/shinyproxy owner=root group=root mode=0444 + tags: [ 'shinyproxy', 'shinyproxy_conf' ] - - name: Ensure that the shinyproxy service is enabled and running - service: name=shinyproxy state=started enabled=yes + - name: Install the upstart init file + template: src=upstart-shinyproxy.conf.j2 dest=/etc/init/shinyproxy.conf owner=root group=root mode=0644 + when: ansible_service_mgr != 'systemd' - - name: Pull the Docker images of shiny apps - docker_image: name={{ item.docker_image }} pull=yes state={{ item.image_state | default('present') }} force=yes - with_items: '{{ shinyproxy_apps }}' - when: shinyproxy_apps is defined - tags: [ 'shinyproxy', 'shinyproxy_images' ] - - when: shinyproxy_install + when: + - ansible_distribution_major_version < '16' + - shinyproxy_install | bool + tags: shinyproxy + +- block: + - name: Install the shinyproxy deb package + apt: + deb: "https://www.shinyproxy.io/downloads/shinyproxy_{{ shinyproxy_version }}_amd64.deb" + state: present + + - name: Install the shinyproxy configuration file when using version 2.x + template: src=shinyproxy-2-conf.yml.j2 dest=/etc/shinyproxy/application.yml owner=root group={{ shinyproxy_user }} mode=0640 + notify: Restart shinyproxy + when: shinyproxy_major_ver == 2 + tags: [ 'shinyproxy', 'shinyproxy_conf', 'shinyproxy_images' ] + + when: + - ansible_distribution_file_variety == "Debian" + - ansible_distribution_major_version >= '16' + - shinyproxy_install | bool + tags: shinyproxy + +- block: + - name: Ensure that the shinyproxy service is enabled and running + service: name=shinyproxy state=started enabled=yes + + - name: Create the directory where to install the custom templates, if we want to use them + file: dest={{ shinyproxy_template_path }} state=directory + when: shinyproxy_custom_template | bool + + - name: Create shinyproxy log directory + file: dest={{ shinyproxy_log_dir }} state=directory owner=shinyproxy mode=0750 + + - name: Check if the Docker certs directory exists + stat: path=/var/lib/docker/swarm/certificates + register: certs_dir + + - name: Create the PKI directory + file: dest={{ shinyproxy_docker_certs_dir }} state=directory owner=root group=shinyproxy mode=0750 + when: certs_dir.stat.isdir is defined and certs_dir.stat.isdir | bool + + - name: Copy the TLS files + copy: src=/var/lib/docker/swarm/certificates/{{ item.src }} dest={{ shinyproxy_docker_certs_dir }}/{{ item.dest }} remote_src=yes force=yes + with_items: + - { src: swarm-root-ca.crt, dest: ca.pem } + - { src: swarm-node.crt, dest: cert.pem } + - { src: swarm-node.key, dest: key.pem } + when: certs_dir.stat.isdir is defined and certs_dir.stat.isdir | bool + + - name: Fix the TLS key file permissions + file: dest={{ shinyproxy_docker_certs_dir }}/key.pem owner=shinyproxy group=shinyproxy mode=0640 + when: certs_dir.stat.isdir is defined and certs_dir.stat.isdir | bool + + - name: Install a script that syncs the docker certificates + template: src=sync_docker_certificates.sh.j2 dest=/usr/local/bin/sync_docker_certificates + when: certs_dir.stat.isdir is defined and certs_dir.stat.isdir | bool + + - name: Install a cron job that hourly updates the certificates used by shinyproxy to talk with docker + cron: name="Fix the docker certificates for shinyproxy" special_time=hourly job="/usr/local/bin/sync_docker_certificates > /var/log/shinyproxy/docker_certs.log 2>&1" + when: certs_dir.stat.isdir is defined and certs_dir.stat.isdir | bool + + - name: Pull the Docker images for the Shiny apps, when using Docker standalone + docker_image: name={{ item.docker_image }} pull=yes state={{ item.image_state | default('present') }} force=yes + with_items: '{{ shinyproxy_apps }}' + when: + - shinyproxy_apps is defined + - shinyproxy_container_backend == 'docker' + tags: [ 'shinyproxy', 'shinyproxy_images' ] + + # - name: Pull the Docker images for the Shiny apps, when using Docker Swarm + # docker_swarm_service: + # name: "{{ item.docker_image | lower }}" + # image: '{{ item.docker_image }}' + # state: "{{ item.image_state | default('present') }}" + # force_update: yes + # reservations: + # cpus: '{{ shinyproxy_docker_cpu_limit }}' + # memory: '{{ shinyproxy_docker_memory_limit }}' + # with_items: '{{ shinyproxy_apps }}' + # delegate_to: '{{ shinyproxy_docker_host }}' + # when: + # - shinyproxy_apps is defined + # - shinyproxy_container_backend == 'docker-swarm' + # tags: [ 'shinyproxy', 'shinyproxy_images' ] + + when: shinyproxy_install | bool tags: shinyproxy diff --git a/library/roles/shinyproxy/templates/shinyproxy-1-conf.yml.j2 b/library/roles/shinyproxy/templates/shinyproxy-1-conf.yml.j2 new file mode 100644 index 00000000..c5f68a05 --- /dev/null +++ b/library/roles/shinyproxy/templates/shinyproxy-1-conf.yml.j2 @@ -0,0 +1,68 @@ +shiny: + proxy: + title: {{ shinyproxy_app_title }} + logo-url: {{ shinyproxy_logo_url }} + landing-page: / + heartbeat-rate: 10000 + heartbeat-timeout: 60000 + container-wait-time: {{ shinyproxy_container_wait_time }} + port: {{ shinyproxy_http_port }} + hide-navbar: {{ shinyproxy_hide_navbar }} + authentication: {{ shinyproxy_authentication }} + admin-groups: {{ shinyproxy_admin_group }} +{% if shinyproxy_ldap_enabled %} + # LDAP configuration + ldap: + url: {{ shinyproxy_ldap_server }} +{% if shinyproxy_ldap_user_dn_enabled %} + user-dn-pattern: {{ shinyproxy_ldap_user_dn_pattern }} +{% endif %} +{% if shinyproxy_ldap_user_search_base_enabled %} + user-search-base: {{ shinyproxy_ldap_user_search_base }} +{% endif %} +{% if shinyproxy_ldap_user_search_filter_enabled %} + user-search-filter: {{ shinyproxy_ldap_user_search_filter }} +{% endif %} + group-search-base: {{ shinyproxy_ldap_group_search_base }} + group-search-filter: {{ shinyproxy_ldap_group_search_filter }} + manager-dn: {{ shinyproxy_ldap_admin }} + manager-password: {{ shinyproxy_ldap_admin_pwd }} +{% endif %} +# Docker configuration + docker: + cert-path: /home/none + url: {{ shinyproxy_docker_url }} + port-range-start: {{ shinyproxy_docker_port_range_start }} + apps: +{% if shinyproxy_default_apps %} + - name: 01_hello + display-name: Hello Application + description: Application which demonstrates the basics of a Shiny app + docker-cmd: ["R", "-e shinyproxy::run_01_hello()"] + docker-image: openanalytics/shinyproxy-demo + - name: 06_tabsets + docker-cmd: ["R", "-e shinyproxy::run_06_tabsets()"] + docker-image: openanalytics/shinyproxy-demo +{% endif %} +{% if shinyproxy_apps is defined %} +{% for app in shinyproxy_apps %} + - name: {{ app.name }} + display-name: {{ app.display_name }} + description: {{ app.description }} + docker-cmd: ["R", "-e {{ app.cmd }}"] + docker-image: {{ app.docker_image }} + docker-memory: {{ app.docker_memory | default('2g') }} + {% if app.groups is defined %} + groups: {{ app.groups }} + {% endif %} + +{% endfor %} +{% endif %} + +security: + basic: + enabled: {{ shinyproxy_basic_auth }} + +logging: + file: {{ shinyproxy_log_dir }}/shinyproxy.log + diff --git a/library/roles/shinyproxy/templates/shinyproxy-2-conf.yml.j2 b/library/roles/shinyproxy/templates/shinyproxy-2-conf.yml.j2 new file mode 100644 index 00000000..8bde1de2 --- /dev/null +++ b/library/roles/shinyproxy/templates/shinyproxy-2-conf.yml.j2 @@ -0,0 +1,76 @@ +proxy: + title: {{ shinyproxy_app_title }} + logo-url: {{ shinyproxy_logo_url }} + landing-page: / + heartbeat-rate: 10000 + heartbeat-timeout: 60000 + container-wait-time: {{ shinyproxy_container_wait_time }} + bind-address: {{ shinyproxy_bind_address }} + port: {{ shinyproxy_http_port }} + hide-navbar: {{ shinyproxy_hide_navbar }} +{% if shinyproxy_custom_template %} + template-path: {{ shinyproxy_template_path }} +{% endif %} + authentication: {{ shinyproxy_authentication }} + admin-groups: {{ shinyproxy_admin_group }} +{% if shinyproxy_ldap_enabled %} + # LDAP configuration + ldap: + url: {{ shinyproxy_ldap_server }} +{% if shinyproxy_ldap_user_dn_enabled %} + user-dn-pattern: {{ shinyproxy_ldap_user_dn_pattern }} +{% endif %} +{% if shinyproxy_ldap_user_search_base_enabled %} + user-search-base: {{ shinyproxy_ldap_user_search_base }} +{% endif %} +{% if shinyproxy_ldap_user_search_filter_enabled %} + user-search-filter: {{ shinyproxy_ldap_user_search_filter }} +{% endif %} + group-search-base: {{ shinyproxy_ldap_group_search_base }} + group-search-filter: {{ shinyproxy_ldap_group_search_filter }} + manager-dn: {{ shinyproxy_ldap_admin }} + manager-password: {{ shinyproxy_ldap_admin_pwd }} +{% endif %} + docker: + container-backend: {{ shinyproxy_container_backend }} + container-memory-request: {{ shinyproxy_docker_memory_request }} + container-memory-limit: {{ shinyproxy_docker_memory_limit }} + container-cpu-limit: {{ shinyproxy_docker_cpu_limit }} + cert-path: {{ shinyproxy_docker_certs_dir }} + url: {{ shinyproxy_docker_url }} + port-range-start: {{ shinyproxy_docker_port_range_start }} + specs: +{% if shinyproxy_default_apps %} + - id: 01_hello + display-name: Hello Application + description: Application which demonstrates the basics of a Shiny app + container-cmd: ["R", "-e shinyproxy::run_01_hello()"] + container-image: openanalytics/shinyproxy-demo + - id: 06_tabsets + docker-cmd: ["R", "-e shinyproxy::run_06_tabsets()"] + container-image: openanalytics/shinyproxy-demo +{% endif %} +{% if shinyproxy_apps is defined %} +{% for app in shinyproxy_apps %} + - id: {{ app.name }} + display-name: {{ app.display_name }} + description: {{ app.description }} + container-cmd: ["R", "-e {{ app.cmd }}"] + container-image: {{ app.docker_image }} + container-memory: {{ app.docker_memory | default('2g') }} + {% if app.groups is defined %} + groups: {{ app.groups }} + {% endif %} + +{% endfor %} +{% endif %} + +security: + basic: + enabled: {{ shinyproxy_basic_auth }} + +logging: + file: {{ shinyproxy_log_dir }}/shinyproxy.log + #max-size: {{ shinyproxy_max_log_size }} + level: + com.spotify.docker: {{ shinyproxy_docker_loglevel }} diff --git a/library/roles/shinyproxy/templates/shinyproxy-logrotate.j2 b/library/roles/shinyproxy/templates/shinyproxy-logrotate.j2 index e171fe85..a7d0b51d 100644 --- a/library/roles/shinyproxy/templates/shinyproxy-logrotate.j2 +++ b/library/roles/shinyproxy/templates/shinyproxy-logrotate.j2 @@ -1,4 +1,4 @@ -{{ shinyproxy_install_dir }}/shinyproxy.log { +{{ shinyproxy_log_dir }}/shinyproxy.log { copytruncate daily rotate 10 diff --git a/library/roles/shinyproxy/templates/sync_docker_certificates.sh.j2 b/library/roles/shinyproxy/templates/sync_docker_certificates.sh.j2 new file mode 100644 index 00000000..d192ce7f --- /dev/null +++ b/library/roles/shinyproxy/templates/sync_docker_certificates.sh.j2 @@ -0,0 +1,8 @@ +#!/bin/bash + +/bin/cp -f /var/lib/docker/swarm/certificates/swarm-root-ca.crt {{ shinyproxy_docker_certs_dir }}/ca.pem +/bin/cp -f /var/lib/docker/swarm/certificates/swarm-node.crt {{ shinyproxy_docker_certs_dir }}/cert.pem +/bin/cp -f /var/lib/docker/swarm/certificates/swarm-node.key {{ shinyproxy_docker_certs_dir }}/key.pem +chown shinyproxy {{ shinyproxy_docker_certs_dir }}/key.pem + +exit 0