--- - name: Setup QGIS-Server and Lizmap hosts: testing handlers: - name: Ensure nginx is restarted become: true ansible.builtin.systemd: name: nginx state: restarted - name: Ensure OpenSSH is restarted become: true ansible.builtin.systemd: name: sshd state: restarted - name: Ensure postgresql is restarted become: true ansible.builtin.systemd: name: postgresql state: restarted - name: Ensure php-fpm is restarted become: true ansible.builtin.systemd: name: "php{{ php['version'] }}-fpm" state: restarted - name: Ensure sftp-permissions is restarted and enabled become: true ansible.builtin.systemd: name: sftp-permissions state: restarted enabled: true daemon_reload: true tasks: - name: Ensure custom motd is latest become: true ansible.builtin.template: src: ./templates/motd.sh.j2 dest: /etc/profile.d/motd.sh owner: root group: root mode: u=rw,g=r,o=r - name: Ensure valid apt cache and required tools are present become: true ansible.builtin.apt: cache_valid_time: 600 name: - acl - ufw - git - unzip - gnupg - software-properties-common - postgresql - acl # bug: https://github.com/ansible/ansible/issues/74830 - inotify-tools - postgis state: present - name: Ensure qgis-server is valid block: - name: Ensure qgis repository key is in apt-keyring become: true ansible.builtin.get_url: url: "{{ qgis_repo['keyring']['url'] }}" checksum: "{{ qgis_repo['keyring']['hash'] }}" dest: /etc/apt/keyrings/qgis-archive-keyring.gpg backup: true owner: root mode: u=rw,g=r,o=r - name: Ensure qgis repository is in apt-sources become: true ansible.builtin.template: src: ./templates/qgis.sources.j2 dest: /etc/apt/sources.list.d/qgis.sources backup: true owner: root mode: u=rw,g=r,o=r - name: Ensure qgis-server is present become: true ansible.builtin.apt: update_cache: true name: - "{{ 'qgis-server=' + qgis_server['full_version'] }}" state: present - name: Ensure qgis-server directory is present become: true ansible.builtin.file: dest: "{{ qgis_server['path'] }}" state: directory owner: www-data group: www-data mode: u=rwX,g=rwX,o=rX - name: Ensure qgis-server environment file is latest become: true ansible.builtin.template: src: ./templates/qgis_server_env.j2 dest: "{{ qgis_server['path'] }}/qgis_server_env" backup: true owner: www-data mode: u=rw,g=r,o=r - name: Ensure qgis-server systemd files are latest become: true ansible.builtin.template: src: "./templates/{{ item }}.j2" dest: "/etc/systemd/system/{{ item }}" backup: true owner: root group: root mode: u=rw,g=r,o=r loop: - "qgis-server@.service" - "qgis-server@.socket" - name: Ensure qgis-server service is enabled and stopped become: true ansible.builtin.systemd: daemon_reload: true enabled: true state: stopped name: "qgis-server@{{ item }}.service" loop: "{{ range(1, qgis_server['count'] + 1, 1) | list }}" - name: Ensure qgis-server socket is enabled and started become: true ansible.builtin.systemd: daemon_reload: true enabled: true state: started name: "qgis-server@{{ item }}.socket" loop: "{{ range(1, qgis_server['count'] + 1, 1) | list }}" - name: Ensure nginx is present become: true ansible.builtin.apt: cache_valid_time: 600 name: "nginx" state: present - name: Ensure custom ufw rules are latest become: true ansible.builtin.template: src: "{{ item }}" dest: "/etc/ufw/applications.d/{{ item | basename }}" owner: root group: root mode: u=rw,g=r,o=r with_fileglob: "templates/ufw/applications.d/*" - name: Ensure ufw rules are set become: true community.general.ufw: rule: allow name: "{{ item }}" state: enabled loop: - "SSH" - "Nginx HTTP" - "Nginx HTTPS" - "PostgreSQL" - name: Ensure postgresql for lizmap is valid block: - name: Check if PostgreSQL database is initialized. become: true ansible.builtin.stat: path: "/var/lib/postgresql/15/main/PG_VERSION" register: pgdata_dir_version - name: Ensure PostgreSQL database is initialized. become: true ansible.builtin.command: "pg_createcluster 15 main --start" when: not pgdata_dir_version.stat.exists changed_when: true - name: Ensure postgresql is started and enabled become: true ansible.builtin.systemd: name: postgresql state: started enabled: true - name: Ensure lizmap user exists become: true become_user: postgres community.postgresql.postgresql_user: name: "{{ lizmap['postgresql_connection']['user'] }}" encrypted: true password: "{{ postgresql_lizmap_pass }}" - name: Ensure lizmap database exists become: true become_user: postgres community.postgresql.postgresql_db: name: "{{ lizmap['postgresql_connection']['database'] }}" owner: "{{ lizmap['postgresql_connection']['user'] }}" - name: Ensure lizmap-web-client is valid block: - name: Ensure php packages required by lizmap are present notify: - "Ensure php-fpm is restarted" become: true ansible.builtin.apt: cache_valid_time: 600 name: "{{ lizmap['dependencies'] }}" state: present - name: Check if lizmap-web-client is present become: true ansible.builtin.stat: path: "{{ lizmap['path'] }}lizmap-web-client-{{ _lizmap_version }}/VERSION" register: _lizmap_version_stat - name: Check if lizmap-web-client has version information become: true ansible.builtin.slurp: src: "{{ lizmap['path'] }}lizmap-web-client-{{ _lizmap_version }}/VERSION" when: _lizmap_version_stat.stat.exists register: _lizmap_version_file - name: Check if lizmap-web-client must be installed when: "not _lizmap_version_stat.stat.exists" block: - name: Ensure lizmap-web-client is downloaded become: true ansible.builtin.get_url: url: "{{ lizmap['url'] }}" dest: "/tmp/lizmap-web-client-{{ lizmap['version'] }}.zip" checksum: "{{ lizmap['hash'] }}" owner: www-data mode: u=rw,g=r,o=r - name: Ensure lizmap-web-client is un-archived become: true ansible.builtin.unarchive: remote_src: true src: "/tmp/lizmap-web-client-{{ lizmap['version'] }}.zip" dest: "{{ lizmap['path'] }}" owner: www-data mode: u=rwX,g=rX,o=r register: _lizmap_extracted - name: Ensure lizmap-web-client is symlinked to documentRoot become: true ansible.builtin.file: src: "{{ lizmap['path'] }}lizmap-web-client-{{ _lizmap_version }}/lizmap/www" dest: "/var/www/html/lizmap" state: link - name: Ensure lizmap-web-client conf is latest become: true ansible.builtin.blockinfile: block: "{{ lookup('ansible.builtin.template', './templates/lizmap/' + item + '.j2') }}" dest: "{{ lizmap['path'] + 'lizmap-web-client-' + lizmap['version'] + '/lizmap/var/config/' + item }}" backup: true owner: www-data group: www-data mode: u=rw,g=r,o= create: true marker: "; {mark} ANSIBLE MANAGED BLOCK" loop: - profiles.ini.php - lizmapConfig.ini.php - localconfig.ini.php - name: Ensure lizmap-web-client directory has correct rights and owner become: true ansible.builtin.file: dest: "{{ lizmap['path'] }}lizmap-web-client-{{ lizmap['version'] }}/{{ item }}" owner: "www-data" group: "www-data" mode: u+rwX,g+rX recurse: true loop: # taken from lizmap-web-client-3.7.6/lizmap/install/set_rights.sh - "" - lizmap/var/config - lizmap/var/db - lizmap/var/log - lizmap/var/themes - lizmap/var/overloads - lizmap/var/mails - lizmap/var/uploads - lizmap/var/lizmap-theme-config - temp/lizmap - lizmap/www/cache/ - lizmap/www/document/ - lizmap/www/live/ - name: Ensure lizmap-web-client installer was executed # noqa: no-handler when: "_lizmap_extracted is changed" # TODO: find actual changes block: - name: Ensure lizmap-web-client default users file is latest become: true ansible.builtin.template: src: "./templates/lizmap/defaultusers.json.j2" dest: "{{ lizmap['path'] }}lizmap-web-client-{{ lizmap['version'] }}/lizmap/modules/lizmap/install/defaultusers.json" backup: false owner: www-data group: www-data mode: u=rw,g=r,o= - name: Run lizmap-web-client installer become: true become_user: www-data # TODO: ignore warning for remote_tmp ansible.builtin.command: chdir: "{{ lizmap['path'] }}lizmap-web-client-{{ lizmap['version'] }}" cmd: "php lizmap/install/installer.php" changed_when: true # TODO: find actual changes - name: Ensure lizmap-web-client default users file is removed become: true ansible.builtin.file: path: "{{ lizmap['path'] }}lizmap-web-client-{{ lizmap['version'] }}/lizmap/modules/lizmap/install/defaultusers.json" state: absent - name: Ensure nginx sites are valid notify: - "Ensure nginx is restarted" block: - name: Ensure default nginx site is disabled become: true ansible.builtin.file: dest: "/etc/nginx/sites-enabled/default" state: absent - name: Ensure qgis-server site conf is latest become: true ansible.builtin.template: src: "./templates/nginx/qgis-server.conf.j2" dest: "/etc/nginx/sites-available/qgis-server.conf" backup: true owner: root mode: u=rw,g=r,o=r - name: Ensure qgis-server site is enabled become: true ansible.builtin.file: src: "/etc/nginx/sites-available/qgis-server.conf" dest: "/etc/nginx/sites-enabled/qgis-server.conf" state: link - name: Ensure lizmap-web-client site conf is latest become: true ansible.builtin.template: src: "./templates/nginx/lizmap.conf.j2" dest: "/etc/nginx/sites-available/lizmap.conf" backup: true owner: root mode: u=rw,g=r,o=r - name: Ensure lizmap-web-client site is enabled become: true ansible.builtin.file: src: "/etc/nginx/sites-available/lizmap.conf" dest: "/etc/nginx/sites-enabled/lizmap.conf" state: link - name: Ensure qgis-server plugins are valid block: - name: Ensure requirements for qgis-server plugins are present become: true ansible.builtin.apt: cache_valid_time: 600 name: - python3-pip - python3-venv state: present - name: Ensure qgis-server venv and qgis-plugin-manager are present become: true become_user: www-data ansible.builtin.pip: virtualenv: "{{ qgis_server['path'] }}/qgis-server-venv" # virtualenv_site_packages: true virtualenv_command: python3 -m venv --system-site-packages name: - qgis-plugin-manager state: present - name: Ensure qgis-server plugins directory is present become: true ansible.builtin.file: dest: "{{ qgis_server['path'] }}/plugins" state: directory owner: www-data group: www-data mode: ug=rwX,o=r - name: Check if qgis-plugin-manager is initialized become: true ansible.builtin.stat: path: "{{ qgis_server['path'] }}/plugins/sources.list" register: _qgis_plugin_sources - name: Ensure qgis-plugin-manager is initialized become: true become_user: www-data ansible.builtin.command: chdir: "{{ qgis_server['path'] }}/plugins" cmd: "{{ qgis_server['path'] }}/qgis-server-venv/bin/qgis-plugin-manager init" when: not _qgis_plugin_sources.stat.exists changed_when: true - name: Check if Lizmap server plugin is present become: true ansible.builtin.stat: path: "{{ qgis_server['path'] }}/plugins/lizmap_server" register: _qgis_plugin_lizmap_server - name: Ensure Lizmap server plugin is present become: true become_user: www-data ansible.builtin.command: chdir: "{{ qgis_server['path'] }}/plugins" cmd: "{{ qgis_server['path'] }}/qgis-server-venv/bin/qgis-plugin-manager {{ item }}" loop: - update - install "Lizmap server" when: not _qgis_plugin_lizmap_server.stat.exists changed_when: true - name: Ensure sftp group exists become: true ansible.builtin.group: name: sftp - name: Ensure publisher user exists become: true ansible.builtin.user: user: "publisher" password: "{{ os_publisher_user_pass | password_hash('sha512') }}" update_password: on_create umask: u=rwX,g=rwX,o= append: true groups: - sftp - name: Ensure webserver user can access gis repositories become: true ansible.builtin.user: user: "www-data" append: true groups: - sftp - name: Ensure sftp root has correct rights and exists become: true ansible.builtin.file: dest: "{{ sftp_root }}" state: directory owner: root group: root mode: u=rwX,g=rX,o=rX recurse: false - name: Ensure lizmap root repository has correct rights and exists become: true ansible.builtin.file: dest: "{{ lizmap['root_repositories'] }}" state: directory owner: "publisher" group: sftp mode: u=rwX,g=rwXs,o= - name: Ensure sftp-permissions is latest notify: - Ensure sftp-permissions is restarted and enabled become: true block: - name: Ensure sftp-permissions dir exists ansible.builtin.file: dest: "{{ software_package_root }}/sftp-permissions" state: directory owner: root group: root mode: u=rwX,g=rX,o=rX - name: Ensure sftp-permissions script is latest ansible.builtin.template: src: ./templates/sftp-inotify.sh.j2 dest: "{{ software_package_root }}/sftp-permissions/sftp-inotify.sh" owner: root group: root mode: u=rwx,g=r,o= backup: true - name: Ensure sftp-permissions service is latest ansible.builtin.template: src: ./templates/sftp-permissions.service.j2 dest: /etc/systemd/system/sftp-permissions.service owner: root group: root mode: u=rw,g=r,o=r - name: Ensure sshd config is latest notify: - "Ensure OpenSSH is restarted" become: true ansible.builtin.template: src: ./templates/sshd_hardened.conf.j2 dest: /etc/ssh/sshd_config.d/sshd_hardened.conf backup: true owner: root mode: u=rw,g=r,o=r - name: Ensure publisher's ssh-keys are latest become: true ansible.posix.authorized_key: user: "publisher" state: present key: " {{ lookup('file', item) }} " loop: "{{ publisher_ssh_keys }}" - name: Ensure gis database is present block: - name: Ensure gis database user exists become: true become_user: postgres community.postgresql.postgresql_user: name: "{{ gis_database['user'] }}" encrypted: true password: "{{ postgresql_gis_pass }}" - name: Ensure gis databases exists become: true become_user: postgres community.postgresql.postgresql_db: name: "{{ item }}" owner: "{{ gis_database['user'] }}" loop: "{{ gis_database['databases'] }}" - name: Ensure postgis schema is available in databases become: true become_user: postgres community.postgresql.postgresql_ext: db: "{{ item }}" name: postgis loop: "{{ gis_database['databases'] }}" - name: Ensure gis database is reachable notify: Ensure postgresql is restarted block: - name: Ensure postgresql listens on addresses become: true ansible.builtin.template: src: ./templates/postgresql/postgresql_remote.conf.j2 dest: /etc/postgresql/15/main/conf.d/postgresql_remote.conf owner: postgres group: postgres mode: u=rw,g=r,o= backup: false - name: Ensure postgresql allows gis user to connect become: true ansible.builtin.blockinfile: block: "{{ lookup('ansible.builtin.template', './templates/postgresql/pg_hba_remote.conf.j2') }}" dest: /etc/postgresql/15/main/pg_hba.conf