diff --git a/CHANGELOG.md b/CHANGELOG.md index b5db81eacb..58f7207fd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ ### HEAD +* Add `bin/xdebug-tunnel.sh` to manage Xdebug and SSH tunnels on remote hosts ([#678](https://github.com/roots/trellis/pull/678)) +* Move Xdebug installation/configuration into its own role ([#678](https://github.com/roots/trellis/pull/678)) * Disable wp-cron emails ([#685](https://github.com/roots/trellis/pull/685)) * Make `raw_vars` compatible with play vars and Ansible 2.1 ([#684](https://github.com/roots/trellis/pull/684)) * Ensure there is always at least one PHP-FPM pool defined ([#682](https://github.com/roots/trellis/pull/682)) diff --git a/bin/xdebug-tunnel.sh b/bin/xdebug-tunnel.sh new file mode 100644 index 0000000000..8f475677ac --- /dev/null +++ b/bin/xdebug-tunnel.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +show_usage() { + echo " +Usage: bin/xdebug-tunnel.sh + + can be 'open' or 'close' + is the hostname, IP, or inventory alias in your \`hosts/\` file. + +Examples: + To open a tunnel: + bin/xdebug-tunnel.sh open 12.34.56.78 + + To close a tunnel: + bin/xdebug-tunnel.sh close 12.34.56.78 +" +} + +if [[ $1 == "open" ]]; then + REMOTE_ENABLE=1 +elif [[ $1 == "close" ]]; then + REMOTE_ENABLE=0 +else + >&2 echo "The provided argument '${1}' is not acceptable." + show_usage + exit 1 +fi + +if [[ -z $2 ]]; then + >&2 echo "The argument is required." + show_usage + exit 1 +fi + +XDEBUG_ENABLE="-e xdebug_remote_enable=${REMOTE_ENABLE}" +SSH_HOST="-e xdebug_tunnel_inventory_host=$2" + +if [[ -n $DEBUG ]]; then + PARAMS="$PARAMS ${VERBOSITY:--vvvv}" +fi + +ansible-playbook xdebug-tunnel.yml $XDEBUG_ENABLE $SSH_HOST $PARAMS diff --git a/dev.yml b/dev.yml index a721acfcc1..1df5a083c0 100644 --- a/dev.yml +++ b/dev.yml @@ -13,6 +13,7 @@ - { role: mariadb, tags: [mariadb] } - { role: mailhog, tags: [mailhog, mail] } - { role: php, tags: [php] } + - { role: xdebug, tags: [php, xdebug] } - { role: memcached, tags: [memcached] } - { role: nginx, tags: [nginx] } - { role: logrotate, tags: [logrotate] } diff --git a/group_vars/development/php.yml b/group_vars/development/php.yml index a7d5fbb24d..7b9af47888 100644 --- a/group_vars/development/php.yml +++ b/group_vars/development/php.yml @@ -5,11 +5,5 @@ php_track_errors: 'On' php_mysqlnd_collect_memory_statistics: 'On' php_opcache_enable: 0 -xdebug_install: true -php_xdebug_remote_enable: true -php_xdebug_remote_connect_back: true -php_xdebug_remote_host: localhost -php_xdebug_remote_port: 9000 -php_xdebug_remote_log: /tmp/xdebug.log -php_xdebug_idekey: XDEBUG -php_max_nesting_level: 200 +xdebug_remote_enable: 1 +xdebug_remote_connect_back: 1 diff --git a/roles/php/defaults/main.yml b/roles/php/defaults/main.yml index 8575f4f4d9..f47ca9b544 100644 --- a/roles/php/defaults/main.yml +++ b/roles/php/defaults/main.yml @@ -23,11 +23,3 @@ php_opcache_interned_strings_buffer: 8 php_opcache_max_accelerated_files: 4000 php_opcache_memory_consumption: 128 php_opcache_revalidate_freq: 60 - -php_xdebug_remote_enable: "false" -php_xdebug_remote_connect_back: "false" -php_xdebug_remote_host: localhost -php_xdebug_remote_port: "9000" -php_xdebug_remote_log: /tmp/xdebug.log -php_xdebug_idekey: XDEBUG -php_max_nesting_level: 200 diff --git a/roles/php/tasks/main.yml b/roles/php/tasks/main.yml index 55b27400d2..45f7f0ca05 100644 --- a/roles/php/tasks/main.yml +++ b/roles/php/tasks/main.yml @@ -24,24 +24,6 @@ - php7.0-xmlrpc - php7.0-zip -- name: Install Xdebug - apt: - name: php-xdebug - state: latest - when: xdebug_install | default(false) - -- name: xdebug configuration file - template: - src: xdebug.ini.j2 - dest: /etc/php/7.0/mods-available/xdebug.ini - when: xdebug_install | default(false) - -- name: Disable xdebug CLI - file: - path: /etc/php/7.0/cli/conf.d/20-xdebug.ini - state: absent - when: xdebug_install | default(false) - - name: Start php7.0-fpm service service: name: php7.0-fpm diff --git a/roles/php/templates/xdebug.ini.j2 b/roles/php/templates/xdebug.ini.j2 deleted file mode 100644 index 8e8953bc7f..0000000000 --- a/roles/php/templates/xdebug.ini.j2 +++ /dev/null @@ -1,12 +0,0 @@ -; {{ ansible_managed }} - -[XDebug] -zend_extension="xdebug.so" -xdebug.remote_enable={{ php_xdebug_remote_enable }} -xdebug.remote_connect_back={{ php_xdebug_remote_connect_back }} -xdebug.remote_host={{ php_xdebug_remote_host }} -xdebug.remote_port={{ php_xdebug_remote_port }} -xdebug.remote_handler="dbgp" -xdebug.remote_log={{ php_xdebug_remote_log }} -xdebug.idekey="{{ php_xdebug_idekey }}" -xdebug.max_nesting_level = {{ php_max_nesting_level }} diff --git a/roles/remote-user/tasks/main.yml b/roles/remote-user/tasks/main.yml index ffdd66d2e9..94432a6c66 100644 --- a/roles/remote-user/tasks/main.yml +++ b/roles/remote-user/tasks/main.yml @@ -3,7 +3,7 @@ fail: msg: | When using `--ask-pass` option, use `-u` option to define remote-user: - ansible-playbook server.yml -e env={{ env }} -u root --ask-pass + ansible-playbook server.yml -e env={{ env | default('production') }} -u root --ask-pass when: ansible_user is not defined and cli_ask_pass | default(false) - name: Check whether Ansible can connect as root diff --git a/roles/xdebug-tunnel/defaults/main.yml b/roles/xdebug-tunnel/defaults/main.yml new file mode 100644 index 0000000000..c9a52a144a --- /dev/null +++ b/roles/xdebug-tunnel/defaults/main.yml @@ -0,0 +1,10 @@ +xdebug_tunnel_remote_port: 9000 +xdebug_tunnel_host: localhost +xdebug_tunnel_local_port: 9000 +xdebug_tunnel_control_socket: /tmp/trellis-xdebug-{{ xdebug_tunnel_inventory_host }} +xdebug_tunnel_control_identity: "{{ ansible_user_id }}" + +xdebug_tunnel_port_mapping: "{{ xdebug_tunnel_remote_port }}:{{ xdebug_tunnel_host }}:{{ xdebug_tunnel_local_port }}" +xdebug_tunnel_ssh_user: "{{ hostvars[xdebug_tunnel_inventory_host]['ansible_user'] | default(admin_user) }}" +xdebug_tunnel_ssh_host: "{{ hostvars[xdebug_tunnel_inventory_host]['ansible_host'] | default(xdebug_tunnel_inventory_host) }}" +xdebug_tunnel_user_at_host: "{{ xdebug_tunnel_ssh_user }}@{{ xdebug_tunnel_ssh_host }}" diff --git a/roles/xdebug-tunnel/tasks/main.yml b/roles/xdebug-tunnel/tasks/main.yml new file mode 100644 index 0000000000..087428970d --- /dev/null +++ b/roles/xdebug-tunnel/tasks/main.yml @@ -0,0 +1,27 @@ +--- +- name: Create or close Xdebug SSH tunnel + command: | + {% if xdebug_remote_enable | bool %} + ssh -M -S '{{ xdebug_tunnel_control_socket }}' -fnNT -R {{ xdebug_tunnel_port_mapping }} {{ xdebug_tunnel_user_at_host}} '{{ xdebug_tunnel_control_identity }}' + {% else %} + ssh -S '{{ xdebug_tunnel_control_socket }}' -O exit '{{ xdebug_tunnel_control_identity }}' + {% endif %} + connection: local + register: xdebug_tunnel + ignore_errors: true + +- name: Interpret and present Xdebug SSH tunnel errors + fail: + msg: | + {% if 'already' in xdebug_tunnel.stderr | default('') %} + SSH tunnel already exists! Refer to TODO for help. + {% elif 'No such file or directory' in xdebug_tunnel.stderr | default('') %} + SSH tunnel already closed! + {% endif %} + {{ xdebug_tunnel.stderr | default('Unknown error in handling Xdebug SSH tunnel') }} + when: xdebug_tunnel | failed or 'already' in xdebug_tunnel.stderr | default('') + +- name: Announce Xdebug SSH tunnel status + debug: + msg: SSH Tunnel was {{ xdebug_remote_enable | bool | ternary('created', 'closed') }}! + when: xdebug_tunnel | changed diff --git a/roles/xdebug/defaults/main.yml b/roles/xdebug/defaults/main.yml new file mode 100644 index 0000000000..334b958b8c --- /dev/null +++ b/roles/xdebug/defaults/main.yml @@ -0,0 +1,41 @@ +# XDebug Remote Debugging +xdebug_remote_enable: 0 +xdebug_remote_connect_back: 0 +xdebug_remote_host: localhost +xdebug_remote_port: 9000 +xdebug_remote_log: /tmp/xdebug.log +xdebug_idekey: XDEBUG +xdebug_extended_info: 1 +xdebug_max_nesting_level: 200 + +# XDebug Display Settings +xdebug_force_display_errors: 0 +xdebug_force_error_reporting: 0 +xdebug_scream: 0 +xdebug_var_display_max_children: 128 +xdebug_var_display_max_data: 512 +xdebug_var_display_max_depth: 3 + +# XDebug Function/Stack Traces +xdebug_collect_assignments: 0 +xdebug_collect_includes: 1 +xdebug_collect_params: 0 +xdebug_collect_return: 0 +xdebug_collect_vars: 0 +xdebug_show_exception_trace: 0 +xdebug_show_local_vars: 0 +xdebug_show_mem_delta: 0 +xdebug_trace_enable_trigger: 0 +xdebug_trace_enable_trigger_value: +xdebug_trace_format: 0 +xdebug_trace_options: 0 +xdebug_trace_output_dir: /tmp +xdebug_trace_output_name: trace.%c + +# XDebug Profiler +xdebug_profiler_append: 0 +xdebug_profiler_enable: 0 +xdebug_profiler_enable_trigger: 0 +xdebug_profiler_enable_trigger_value: +xdebug_profiler_output_dir: /tmp +xdebug_profiler_output_name: cachegrind.out.%p diff --git a/roles/xdebug/tasks/main.yml b/roles/xdebug/tasks/main.yml new file mode 100644 index 0000000000..ae88b34d50 --- /dev/null +++ b/roles/xdebug/tasks/main.yml @@ -0,0 +1,33 @@ +--- +- block: + - name: Install Xdebug + apt: + name: php-xdebug + state: latest + + - name: Template the Xdebug configuration file + template: + src: xdebug.ini.j2 + dest: /etc/php/7.0/mods-available/xdebug.ini + notify: reload php-fpm + + - name: Ensure 20-xdebug.ini is present + file: + src: /etc/php/7.0/mods-available/xdebug.ini + dest: /etc/php/7.0/fpm/conf.d/20-xdebug.ini + state: link + notify: reload php-fpm + + when: xdebug_remote_enable | bool + +- name: Disable Xdebug + file: + path: /etc/php/7.0/fpm/conf.d/20-xdebug.ini + state: absent + when: not xdebug_remote_enable | bool + notify: reload php-fpm + +- name: Disable Xdebug CLI + file: + path: /etc/php/7.0/cli/conf.d/20-xdebug.ini + state: absent diff --git a/roles/xdebug/templates/xdebug.ini.j2 b/roles/xdebug/templates/xdebug.ini.j2 new file mode 100644 index 0000000000..72435a2bf8 --- /dev/null +++ b/roles/xdebug/templates/xdebug.ini.j2 @@ -0,0 +1,47 @@ +; {{ ansible_managed }} + +[XDebug] +zend_extension=xdebug.so + +; Remote Debugging +xdebug.remote_enable={{ xdebug_remote_enable }} +xdebug.remote_connect_back={{ xdebug_remote_connect_back }} +xdebug.remote_host={{ xdebug_remote_host }} +xdebug.remote_port={{ xdebug_remote_port }} +xdebug.remote_handler=dbgp +xdebug.remote_log={{ xdebug_remote_log }} +xdebug.idekey={{ xdebug_idekey }} +xdebug.extended_info={{ xdebug_extended_info }} +xdebug.max_nesting_level={{ xdebug_max_nesting_level }} + +; Display Settings +xdebug.force_display_errors={{ xdebug_force_display_errors }} +xdebug.force_error_reporting={{ xdebug_force_error_reporting }} +xdebug.scream={{ xdebug_scream }} +xdebug.var_display_max_children={{ xdebug_var_display_max_children }} +xdebug.var_display_max_data={{ xdebug_var_display_max_data }} +xdebug.var_display_max_depth={{ xdebug_var_display_max_depth }} + +; Function/Stack Traces +xdebug.collect_assignments={{ xdebug_collect_assignments }} +xdebug.collect_includes={{ xdebug_collect_includes }} +xdebug.collect_params={{ xdebug_collect_params }} +xdebug.collect_return={{ xdebug_collect_return }} +xdebug.collect_vars={{ xdebug_collect_vars }} +xdebug.show_exception_trace={{ xdebug_show_exception_trace }} +xdebug.show_local_vars={{ xdebug_show_local_vars }} +xdebug.show_mem_delta={{ xdebug_show_mem_delta }} +xdebug.trace_enable_trigger={{ xdebug_trace_enable_trigger }} +xdebug.trace_enable_trigger_value={{ xdebug_trace_enable_trigger_value }} +xdebug.trace_format={{ xdebug_trace_format }} +xdebug.trace_options={{ xdebug_trace_options }} +xdebug.trace_output_dir={{ xdebug_trace_output_dir }} +xdebug.trace_output_name={{ xdebug_trace_output_name }} + +; Profiler +xdebug.profiler_append={{ xdebug_profiler_append }} +xdebug.profiler_enable={{ xdebug_profiler_enable }} +xdebug.profiler_enable_trigger={{ xdebug_profiler_enable_trigger }} +xdebug.profiler_enable_trigger_value={{ xdebug_profiler_enable_trigger_value }} +xdebug.profiler_output_dir={{ xdebug_profiler_output_dir }} +xdebug.profiler_output_name={{ xdebug_profiler_output_name }} diff --git a/xdebug-tunnel.yml b/xdebug-tunnel.yml new file mode 100644 index 0000000000..19aed882cb --- /dev/null +++ b/xdebug-tunnel.yml @@ -0,0 +1,17 @@ +--- +- name: Determine Remote User + hosts: "{{ xdebug_tunnel_inventory_host }}" + gather_facts: false + roles: + - { role: remote-user, tags: [remote-user, always] } + +- name: Enable or Disable Xdebug and SSH Tunnel + hosts: "{{ xdebug_tunnel_inventory_host }}" + roles: + - { role: xdebug, tags: [xdebug] } + - { role: xdebug-tunnel, tags: [xdebug-tunnel] } + handlers: + - name: reload php-fpm + service: + name: php7.0-fpm + state: reloaded