--- - name: "🔍 Resolve the OpenProject web hosting node and container id" ansible.builtin.include_tasks: "{{ lookup('path_absolute', 'roles/sys-svc-compose/tasks/utils/swarm/resolve_host_cid.yml') }}" vars: resolve_service_key: web resolve_service_name: "{{ lookup('container_service', 'web-app-openproject', 'web') }}" resolve_output_prefix: NEXTCLOUD_OPENPROJECT resolve_compose_cid: "{{ NEXTCLOUD_OPENPROJECT_CONTAINER_ADDRESS }}" resolve_converge_retries: 120 resolve_converge_delay: 5 - name: ⏳ Wait for the OpenProject web endpoint wait_for: host: "{{ DOCKER_REACH_HOST }}" port: "{{ lookup('config', 'web-app-openproject', 'services.openproject.ports.local.http') }}" delay: 5 timeout: "{{ lookup('timeout', 600) | int }}" - name: 📁 Create the Nextcloud storage + OpenProject OAuth application ansible.builtin.shell: cmd: >- # nocheck: container-exec-resolver NEXTCLOUD_OPENPROJECT_LOCAL_CID resolved at delegate_to runtime; container_address would return a manager-only subshell container exec -i -e NEXTCLOUD_HOST={{ lookup('tls', 'web-app-nextcloud', 'url.base') | quote }} -e STORAGE_NAME={{ nextcloud_op_storage_name | quote }} -e NC_HAS_OP_SECRET={{ nextcloud_op_client_secret_current.stdout | trim | quote }} {{ NEXTCLOUD_OPENPROJECT_LOCAL_CID | quote }} bash -lc 'cd /app && bundle exec rails runner -' stdin: "{{ lookup('file', 'ruby/utils/doorkeeper_allow_onion_redirect.rb') ~ '\n' ~ lookup('file', 'ruby/addons/openproject/ensure_nextcloud_storage.rb') }}" delegate_to: "{{ NEXTCLOUD_OPENPROJECT_HOST_NODE }}" register: nextcloud_op_storage_create changed_when: "'\"oauth_application_created\":true' in nextcloud_op_storage_create.stdout" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" - name: 🔎 Parse the OpenProject OAuth application credentials set_fact: nextcloud_op_oauth: "{{ nextcloud_op_storage_create.stdout | regex_search('{.*}') | from_json }}" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" - name: 🔍 Resolve the effective OpenProject OAuth client secret (fresh or persisted) set_fact: nextcloud_op_client_secret: >- {{ nextcloud_op_oauth.openproject_client_secret | default((nextcloud_op_client_secret_current.stdout | trim), true) }} no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" - name: 🛑 Fail when no usable OpenProject OAuth application secret is available assert: that: - nextcloud_op_oauth.openproject_client_id | default('') | length > 0 - (nextcloud_op_client_secret | default('') | trim) | length > 0 fail_msg: >- OpenProject did not return a usable OAuth application and no client secret is persisted in Nextcloud. A freshly generated client secret is only available the first time the application is created; reset the integration_openproject app config (openproject_client_id, openproject_client_secret, nc_oauth_client_id) and the OpenProject storage to re-provision. - name: ⬆️ Push the OpenProject OAuth application credentials into Nextcloud shell: > {{ NEXTCLOUD_DOCKER_EXEC_OCC }} config:app:set integration_openproject {{ item.key }} --value={{ item.value | quote }} loop: - { key: "authorization_method", value: "oauth2" } - { key: "openproject_client_id", value: "{{ nextcloud_op_oauth.openproject_client_id }}" } - { key: "openproject_client_secret", value: "{{ nextcloud_op_client_secret }}" } loop_control: label: "{{ item.key }}" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" - name: 📝 Register a Nextcloud OAuth2 client for OpenProject shell: > {{ NEXTCLOUD_DOCKER_EXEC_OCC }} oauth2:add-client "OpenProject client" "{{ nextcloud_op_expected_url }}/oauth_clients/%s/callback" --output=json register: nextcloud_op_ncclient_create changed_when: nextcloud_op_ncclient_create.rc == 0 failed_when: false no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" - name: 🔌 Wire the Nextcloud OAuth2 client into both sides when it was created when: (nextcloud_op_ncclient_create.rc | default(1)) == 0 block: - name: 🔎 Parse the Nextcloud OAuth2 client credentials set_fact: nextcloud_op_ncclient: "{{ nextcloud_op_ncclient_create.stdout | trim | from_json }}" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" - name: ⬆️ Push the Nextcloud OAuth2 client id into integration_openproject shell: > {{ NEXTCLOUD_DOCKER_EXEC_OCC }} config:app:set integration_openproject nc_oauth_client_id --value={{ nextcloud_op_ncclient.clientId | quote }} changed_when: true no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" - name: 📝 Register the Nextcloud OAuth2 client back on the OpenProject storage ansible.builtin.shell: cmd: >- # nocheck: container-exec-resolver NEXTCLOUD_OPENPROJECT_LOCAL_CID resolved at delegate_to runtime; container_address would return a manager-only subshell container exec -i -e NEXTCLOUD_HOST={{ lookup('tls', 'web-app-nextcloud', 'url.base') | quote }} -e STORAGE_NAME={{ nextcloud_op_storage_name | quote }} -e NC_OAUTH_CLIENT_ID={{ nextcloud_op_ncclient.clientId | quote }} -e NC_OAUTH_CLIENT_SECRET={{ nextcloud_op_ncclient.clientSecret | quote }} {{ NEXTCLOUD_OPENPROJECT_LOCAL_CID | quote }} bash -lc 'cd /app && bundle exec rails runner -' stdin: "{{ lookup('file', 'ruby/utils/doorkeeper_allow_onion_redirect.rb') ~ '\n' ~ lookup('file', 'ruby/addons/openproject/ensure_nextcloud_storage.rb') }}" delegate_to: "{{ NEXTCLOUD_OPENPROJECT_HOST_NODE }}" register: nextcloud_op_client_store changed_when: true no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"