--- - name: Base user configuration tags: [user:base] block: - ansible.builtin.set_fact: user_groups: - libvirt - wheel - vboxusers - wireshark - docker - sudonopw - games - kvm - video - name: Create user group ansible.builtin.group: name: "{{ user.name }}" state: present become: true become_user: root - name: Create user ansible.builtin.user: name: "{{ user.name }}" state: present home: "/home/{{ user.name }}" create_home: true groups: "{{ [user.name, 'dotfiles'] + user_groups }}" shell: /usr/bin/zsh skeleton: /dev/null become: true become_user: root - name: Create systemd directory ansible.builtin.file: state: directory path: "{{ item }}" owner: "{{ user.name }}" group: "{{ user.name }}" loop: - "/home/{{ user.name }}/.config/" - "/home/{{ user.name }}/.config/systemd/" - "/home/{{ user.name }}/.config/systemd/user/" - name: Create directory for getty autologin ansible.builtin.file: state: directory path: /etc/systemd/system/getty@tty{{ user.vt }}.service.d owner: root group: root mode: "0755" become: true become_user: root - name: Enable getty autologin ansible.builtin.copy: dest: /etc/systemd/system/getty@tty{{ user.vt }}.service.d/override.conf owner: root group: root mode: "0644" content: | [Service] ExecStart= ExecStart=-/sbin/agetty --autologin {{ user.name }} --noclear %I $TERM become: true become_user: root - name: Configure dotfiles tags: - user:dotfiles block: - name: Load dotfile list ansible.builtin.include_vars: file: dotfiles.yml - name: Get state of empty directories ansible.builtin.stat: path: ~/{{ item.name }} register: empty_dir_stat with_items: "{{ empty_directories }}" check_mode: false loop_control: label: "{{ item.name }}" - name: Remove symlinks ansible.builtin.file: path: "{{ item.stat.path }}" state: absent when: item.stat.exists and item.stat.islnk with_items: "{{ empty_dir_stat.results }}" loop_control: label: "{{ item.item.name }}" - name: Create empty directories for dotfiles ansible.builtin.file: state: directory path: ~/{{ item.name }} mode: "{{ item.mode | default('0755') }}" with_items: "{{ empty_directories }}" loop_control: label: "{{ item.name }}" - name: Link this folder to ~/.dotfiles ansible.builtin.file: state: link force: true follow: false owner: "{{ user.name }}" group: "{{ user.name }}" path: "/home/{{ user.name }}/.dotfiles" src: "{{ playbook_dir }}" become: true become_user: root - name: Get state of copy targets ansible.builtin.stat: path: ~/{{ item.to }} register: copy_stat when: not item.template|default(false) with_items: "{{ dotfiles }}" check_mode: false loop_control: label: "{{ item.to }}" - name: Remove invalid copy target (symlinks) ansible.builtin.file: path: "{{ item.stat.path }}" state: absent when: - not item.skipped is defined or not item.skipped - item.stat.exists - item.stat.islnk with_items: "{{ copy_stat.results }}" loop_control: label: "{{ item.item.from }}" - name: Make sure target directories exist ansible.builtin.file: state: directory path: "{{ (['/home', user.name, item.to] | join('/')) | dirname }}" owner: "{{ user.name }}" group: "{{ user.name }}" with_items: "{{ dotfiles }}" become: true become_user: root loop_control: label: "{{ item.to }}" - name: Copy dotfiles ansible.builtin.copy: dest: "/home/{{ user.name }}/{{ item.to }}" src: /var/lib/dotfiles/{{ item.from }} owner: "{{ user.name }}" group: "{{ user.name }}" when: not item.template|default(false) and not item.dir|default(false) with_items: "{{ dotfiles }}" become: true become_user: root loop_control: label: "{{ item.to }}" - name: Copy directories ansible.posix.synchronize: dest: "/home/{{ user.name }}/{{ item.to }}/" src: /var/lib/dotfiles/{{ item.from }}/ archive: false owner: false group: false links: true perms: false times: false recursive: true checksum: true delete: true when: item.dir|default(false) with_items: "{{ dotfiles }}" become: true become_user: root loop_control: label: "{{ item.to }}" - name: Apply directory permissions ansible.builtin.file: dest: "/home/{{ user.name }}/{{ item.to }}/" owner: "{{ user.name }}" group: "{{ user.name }}" recurse: true when: item.dir|default(false) with_items: "{{ dotfiles }}" become: true become_user: root loop_control: label: "{{ item.to }}" - name: Get state of template targets ansible.builtin.stat: path: ~/{{ item.to }} register: template_stat when: item.template|default(false) with_items: "{{ dotfiles }}" check_mode: false loop_control: label: "{{ item.to }}" - name: Remove invalid template target (directory or symlink) ansible.builtin.file: path: "{{ item.stat.path }}" state: absent when: - not item.skipped is defined or not item.skipped - item.stat.exists - not item.stat.isreg with_items: "{{ template_stat.results }}" loop_control: label: "{{ item.item.to }}" - name: Deploy dotfiles templates ansible.builtin.template: src: /var/lib/dotfiles/{{ item.from }}.j2 dest: "/home/{{ user.name }}/{{ item.to }}" owner: "{{ user.name }}" group: "{{ user.name }}" force: true become: true become_user: root when: item.template|default(false) with_items: "{{ dotfiles }}" loop_control: label: "{{ item.to }}" - name: Remove dotfiles ansible.builtin.file: state: absent path: "/home/{{ user.name }}/{{ item }}" loop: "{{ dotfiles_remove }}" - name: Create directories ansible.builtin.file: state: directory path: "{{ item }}" with_items: - ~/tmp - name: Stat ~/bin ansible.builtin.stat: path: "/home/{{ user.name }}/bin" register: bin_stat check_mode: false - name: Remove ~/bin if not a link ansible.builtin.file: state: absent path: "/home/{{ user.name }}/bin" when: - bin_stat.stat.exists - not bin_stat.stat.islnk - name: Link bin directory ansible.builtin.file: state: link force: true follow: false path: "/home/{{ user.name }}/bin" src: /var/lib/dotfiles/bin owner: "{{ user.name }}" group: "{{ user.name }}" - name: Vim tags: - user:vim block: - name: Install vim plugins ansible.builtin.command: nvim --headless +PlugInstall +qall register: vim_plugin_install changed_when: vim_plugin_install.stderr != "" - name: Update vim plugins ansible.builtin.command: nvim --headless +PlugUpdate +qall register: vim_plugin_update changed_when: vim_plugin_update.stderr != "" - name: Firefox tags: - user:firefox block: - name: Create firefox directories firefox_profile: name: "{{ item.key }}" loop: "{{ user.firefox_profiles | dict2items }}" check_mode: false register: firefox_profile_names - ansible.builtin.set_fact: firefox_preferences: browser.aboutConfig.showWarning: false extensions.pocket.enabled: false toolkit.legacyUserProfileCustomizations.stylesheets: true browser.contentblocking.category: "strict" browser.newtabpage.enabled: false browser.startup.homepage: "about:blank" privacy.trackingprotection.enabled: true privacy.trackingprotection.socialtracking.enabled: true general.smoothScroll: true # Restore last session on startup # https://support.mozilla.org/de/questions/1235263 browser.startup.page: 3 # reload the tabs properly when restoring browser.sessionstore.restore_on_demand: false # "Play DRM-controlled content" media.eme.enabled: true # "Recommend (extensions|features) as you browse" browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons: false browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features: false # "Ask to save logins and passwords for websites" signon.rememberSignons: false # "Allow Firefox to make personalized extension recommendations" browser.discovery.enabled: false # "Allow Firefox to install and run studies" app.shield.optoutstudies.enabled: false # "Check spelling as you type" layout.spellcheckDefault: 0 # Ask for download directory browser.download.useDownloadDir: false # (Try to) disable automatic update, as firefox is pulling a Windows app.update.auto: false app.update.service.enabled: false # remove this camera / microphone overlay when in calls or similar privacy.webrtc.legacyGlobalIndicator: false # remove ad tracking garbage dom.private-attribution.submission.enabled: false - ansible.builtin.include_role: name: firefox vars: firefox_profiles: "{{ {item.key: item.value} | combine({item.key: {'preferences': firefox_preferences}}, recursive=True) }}" loop: "{{ user.firefox_profiles | dict2items }}" when: not ansible_check_mode - name: Firefox - create chrome directory ansible.builtin.file: path: "{{ item.profile_path }}/chrome/" state: directory mode: "0755" with_items: "{{ firefox_profile_names.results }}" when: not ansible_check_mode loop_control: label: "{{ item.profile_path }}" - name: Firefox - configure firefox custom css ansible.builtin.copy: dest: "{{ item.profile_path }}/chrome/userChrome.css" content: | #TabsToolbar { visibility: collapse !important; } #titlebar { visibility: collapse !important; } #sidebar-header { visibility: collapse !important; } when: - not ansible_check_mode - user.firefox_profiles[item.profile_name].manage_css is sameas True with_items: "{{ firefox_profile_names.results }}" loop_control: label: "{{ item.profile_path }}" - name: Handle user units tags: - user:units block: - name: Link user service files ansible.builtin.file: state: link force: true follow: false path: "/home/{{ user.name }}/.config/systemd/user/{{ item | basename }}" src: "{{ item }}" owner: "{{ user.name }}" group: "{{ user.name }}" with_fileglob: /var/lib/dotfiles/services/* - name: Handle autostart units tags: - user:autostart block: - name: Create systemd user directory ansible.builtin.file: state: directory path: ~/{{ item }} loop: - .config/ - .config/systemd/ - .config/systemd/user/ - name: Link autostart service files ansible.builtin.file: state: link force: true follow: false path: "/home/{{ user.name }}/.config/systemd/user/{{ item | basename }}" src: "{{ item }}" owner: "{{ user.name }}" group: "{{ user.name }}" with_fileglob: /var/lib/dotfiles/autostart/services/* - name: Get state of autostart.target ansible.builtin.stat: path: "/home/{{ user.name }}/.config/systemd/user/autostart.target" register: autostart_target_stat - name: Remove invalid autostart.target ansible.builtin.file: path: "/home/{{ user.name }}/.config/systemd/user/autostart.target" state: absent when: - autostart_target_stat.stat.exists - not autostart_target_stat.stat.isreg - name: Deploy autostart.target ansible.builtin.template: src: ./autostart/autostart.target.j2 dest: "/home/{{ user.name }}/.config/systemd/user/autostart.target" owner: "{{ user.name }}" group: "{{ user.name }}" force: true follow: false - name: Gpg tags: - user:gpg when: user.gpg_key is defined block: - name: Import gpg key ansible.builtin.command: gpg --import ./gpgkeys/{{ user.gpg_key.email }}.gpg.asc register: gpg_import_output changed_when: not ("unchanged" in gpg_import_output.stderr) - name: Trust gpg key ansible.builtin.shell: "gpg --import-ownertrust <<< {{ user.gpg_key.fingerprint }}:6" args: executable: /bin/bash # required for <<< register: gpg_trust_output changed_when: gpg_trust_output.stderr_lines|length > 0