{"id":6012,"date":"2024-07-18T01:54:00","date_gmt":"2024-07-18T05:54:00","guid":{"rendered":"https:\/\/www.both.org\/?p=6012"},"modified":"2024-07-15T15:01:14","modified_gmt":"2024-07-15T19:01:14","slug":"how-to-do-fast-repeatable-linux-installations-3-ansible","status":"publish","type":"post","link":"https:\/\/www.both.org\/?p=6012","title":{"rendered":"How to do fast, repeatable Linux installations #3 &#8212; Ansible"},"content":{"rendered":"<div class=\"pld-like-dislike-wrap pld-template-1\">\r\n    <div class=\"pld-like-wrap  pld-common-wrap\">\r\n    <a href=\"javascript:void(0)\" class=\"pld-like-trigger pld-like-dislike-trigger  \" title=\"\" data-post-id=\"6012\" data-trigger-type=\"like\" data-restriction=\"cookie\" data-already-liked=\"0\">\r\n                        <i class=\"fas fa-thumbs-up\"><\/i>\r\n                <\/a>\r\n    <span class=\"pld-like-count-wrap pld-count-wrap\">    <\/span>\r\n<\/div><\/div>\n<p class=\"wp-block-paragraph\">In previous articles about my use of automation in performing post-install tasks for new Linux installations, I discussed my progression from no automation at all but at least using written notes for consistency, to simple <a href=\"https:\/\/www.both.org\/?p=6009\" data-type=\"post\" data-id=\"6009\" target=\"_blank\" rel=\"noreferrer noopener\">scripts<\/a>, to using <a href=\"https:\/\/www.both.org\/?p=6061\" data-type=\"link\" data-id=\"https:\/\/www.both.org\/?p=6061\" target=\"_blank\" rel=\"noreferrer noopener\">RPM packages<\/a> to install tools from the Fedora repositories and my own scripts and files. Those approaches worked well for the times I used them, but as the requirements of my network and the hosts connected to it grew and became more complex, the capabilities of those tools couldn&#8217;t keep up. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I needed a new method for doing post-install tasks. I also needed new ways to perform other tasks, too. So as a series of experiments, I started working with <a href=\"https:\/\/www.ansible.com\/\" data-type=\"link\" data-id=\"https:\/\/www.ansible.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Ansible<\/a> to first familiarize myself with it and then to perform more complex tasks such as Fedora updates and my post-install tasks.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The three articles in the list below describe my progression with using Ansible for tasks ranging from simple to a bit more complex. Please read those whether you&#8217;re familiar with Ansible or not so you can understand how I employ it in my home lab setting. They&#8217;re also a good learning tool if you&#8217;re not already familiar with Ansible.<\/p>\n\n\n\n<ol class=\"wp-block-list\" id=\"block-684fc464-bc24-484a-8d52-65344c9047d3\">\n<li><a href=\"https:\/\/www.both.org\/?p=4262\">Ansible #1: My first day using Ansible<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.both.org\/?p=5087\">Ansible #2 How to create an Ansible Playbook<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.both.org\/?p=5179\">Ansible #3: Finishing our Ansible playbook to manage workstation and server updates<\/a><\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">How Ansible works &#8212; the short version<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The key to using Ansible is in the way it works. The function of Ansible is to ensure that a Linux<sup data-fn=\"60472120-83a6-4f38-9825-b1bb304e869e\" class=\"fn\"><a href=\"#60472120-83a6-4f38-9825-b1bb304e869e\" id=\"60472120-83a6-4f38-9825-b1bb304e869e-link\">1<\/a><\/sup> host is maintained in a certain state. That means that if the Ansible playbook defines certain RPMs and local files as being present or not present, particular text lines to be changed from the default in a configuration file, specific systemd services to be on or off, and much more, running the playbook will always set the system to the desired state. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This statefull approach to system configuration makes it possible to run the playbook at a later time, after undesired or temporary changes have been made to the system, to achieve the defined state. I&#8217;ve had many situations in which I&#8217;ve made changes to a system as part of my process or problem determination, or as the result of some experiments I performed to determine whether I wanted to make some configuration changes on a permanent basis. While making those changes, I don&#8217;t need to worry about making notes so I can get the host back to the state I want for those things that matter to me.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Preparation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For my experiments, I use my personal workstation as the Ansible hub and the VM as the target host. I also take a snapshot of the VM immediately after the new installation and setting up the PPKP. That makes it easy to restore the VM to a pristine condition before performing additional experiments.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First login to the target VM and enable SSH. Ensure that root can perform a remote login via SSH. If the host being used as the Ansible hub doesn&#8217;t already have a PPKP created, do that now and then copy the public key to the target. The article, <a href=\"https:\/\/www.both.org\/?p=6355\" data-type=\"link\" data-id=\"https:\/\/www.both.org\/?p=6355\" target=\"_blank\" rel=\"noreferrer noopener\">How I use Public\/Private\/KeyPairs with SSH<\/a>, will show you how to do both of those tasks.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Playbook<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>Warning!!! \u2014 Don\u2019t use this Ansible playbook on a production system until you know exactly what it does and have modified it to meet your own needs. This article and the playbook that goes with it are intended as a tool to demonstrate what can be done with Ansible to perform post-installation tasks. I strongly recommend that you experiment with this tool on a non-production virtual machine.<\/em><\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now let&#8217;s look at how I used Ansible to perform post-install tasks. This is best done with the playbook itself, PostInstall.yml, starting in Figure 1. This is a very long listing of my Postinstall.yml playbook. A simple explanation of what it does begins at the end of Figure 1.<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>################################################################################\n#                                PostInstall.yml                               #\n#                                                                              #\n# This Ansible playbook performs post-installation updates and configuration   #\n# for newly installed Fedora hosts.                                            #\n#                                                                              #\n# Note: This playbook is intended for use only on one or more newly installed  #\n#       hosts. It is not intended for use with hosts that have been in use     #\n#       for a considerable period of time after installation. But it might     #\n#       work fine for that with most of my personal hosts.                     #\n#                                                                              #\n#                                                                              #\n#------------------------------------------------------------------------------#\n#                                                                              #\n# Change History                                                               #\n# Date        Name         Version   Description                               #\n# 2020\/10\/01  David Both   00.00     Started new code                          #\n&lt;SNIP&gt;\n# 2023\/08\/13  David Both   01.50     Add code to convert to NetworkManager for #\n#                                    resolv.conf to use nss-DNS and disable    #\n#                                    mDNS.                                     #\n# 2023\/09\/22  David Both   01.51     Add sipcalc to cli tools.                 #\n# 2023\/09\/22  David Both   01.52     Remove install of deltarpm.               #\n# 2024\/06\/23  David Both   01.53     Install fastfetch.                        #\n#                                                                              #\n################################################################################\n\n---\n- name: Post-installation updates, package installation, and configuration\n  hosts: testvm1\n  vars:\n    # Set this to false to prevent rebooting after installation of updates\n    # and after the entire procedure has completed. \n    # However setting this to false is not recommended.\n    Reboot: \"true\"\n\n    # When set to True the Gui variable allows install of some GUI tools,\n    # wallpapers, and themes. \n    Gui: \"true\"\n  \n    # When set to True, the Apps variable tells Ansible to install applications like \n    # LibreOffice and more.\n    Apps: \"true\"\n\n    # When set to True, install a large number of background pics. \n    # Takes a long time and space so default is false.\n    Wallpapers: \"true\"\n    \n    # Performs tasks for my own hosts when set to true. Skips those when set to false\n    # for when I work on computers that are not my own. Default is true for \n    # my own stuff.\n    David: \"true\"\n\n    # Install development tools for a primary workstation\n    development: \"false\"\n\n    # When false, this variable removes dnfdragora from the host because it used\n    # to suck and did not work. I don't like it on my stuff so delete it which\n    # allows me to remove it from my systems. The default is false.\n    dnfdragora: \"false\"\n\n    # When true install glances\n    glances: \"false\"\n\n    # When true, install the designated desktops\n    xfce: \"true\"\n    cinnamon: \"false\"\n    # Problems installing LXDE due to conficts\n    lxde: \"false\"\n    # Problems installing Mate due to conficts\n    mate: \"false\"\n\n  tasks:\n\n################################################################################\n################################################################################\n# Start with some kernel and system level configuration.                       #\n################################################################################\n################################################################################\n# Configure maximum number of kernels to keep, install some local scripts that #\n# we will use to do updates, and then install updates.                         #\n# The default number of kernels is three and we change it to 5.                #\n################################################################################\n    - name: Set installonly_limit to 5. Allows saving up to 5 old kernels.\n      replace:\n        path: \/etc\/dnf\/dnf.conf\n        regexp: 'installonly_limit=.*'\n        replace: 'installonly_limit=5'\n\n    - name: Remove possible old deprecated scripts\n      file:\n        path: \"{{ item }}\"\n        state: absent\n      with_items:\n        - \/home\/dboth\/development\/doUpdates\n        - \/usr\/local\/bin\/doUpdates\n        - \/home\/dboth\/development\/updatePrep.sh\n        - \/usr\/local\/bin\/updatePrep.sh\n          \n    - name: Install local scripts\n      copy:\n        src: \"{{ item }}\"\n        dest: \/usr\/local\/bin\n        mode: 0774\n        owner: root\n        group: root\n      with_fileglob:\n          - \/home\/dboth\/development\/ansible\/PostInstall\/files\/usrlocal\/bin\/*\n\n################################################################################\n# Disable mDNS and configure nss-DNS instead.                                  #\n################################################################################\n################################################################################\n# Stop and disable AVAHI services that are not needed. Masked means that it    #\n# cannot be restarted until it is unmasked. This is mDNS                       #\n################################################################################\n    - name: Stop and disable the Avahi service\n      systemd:\n        name: avahi-daemon.service\n        state: stopped\n        masked: yes\n        enabled: no\n\n    - name: Stop and disable the Avahi socket\n      systemd:\n        name: avahi-daemon.socket\n        state: stopped\n        masked: yes\n        enabled: no\n\n# Disable the systemd resolver.\n    - name: Stop and disable the systemd resolver\n      systemd:\n        name: systemd-resolved.service\n        state: stopped\n        masked: no\n        enabled: no\n          \n# Delete \/etc\/resolv.conf link\n    - name: Remove old resolv.conf link\n      ansible.builtin.file:\n        path: \/etc\/resolv.conf\n        state: absent\n\n# Restart NetworkManager which creates a new resolv.conf link every time\n# it is started.\n    - name: Restart NetworkManager to create the new resolv.conf link.\n      systemd:\n        name: NetworkManager\n        state: restarted\n        enabled: yes\n\n################################################################################\n# Disable pcscd smart card daemons                                             #\n################################################################################\n\n# Disable the smart card socket\n    - name: Stop and disable the pcscd smart card socket\n      systemd:\n        name: pcscd.socket\n        state: stopped\n        masked: no\n        enabled: no\n# Disable the smart card service\n    - name: Stop and disable the pcscd smart card service\n      systemd:\n        name: pcscd.service\n        state: stopped\n        masked: no\n        enabled: no\n\n################################################################################\n################################################################################\n# Install some files to standardize all kernel options (kernelopts) into       #\n# one place -- the \/etc\/sysctl.d directory. And a single file in the           #\n# directory local-sysctl.conf.                                                 #\n################################################################################\n################################################################################\n    - name: Install local-sysctl.conf\n      copy:\n        src: \/home\/dboth\/development\/ansible\/BasicTools\/files\/local-sysctl.conf\n        dest: \/etc\/sysctl.d\/local-sysctl.conf\n        mode:  644\n        owner: root\n        group: root\n\n    - name: Install latest MyStartup.sh\n      copy:\n        src: \/home\/dboth\/development\/ansible\/BasicTools\/files\/MyStartup.sh\n        dest: \/usr\/local\/bin\/MyStartup.sh\n        mode:  754\n        owner: root\n        group: root\n\n    - name: Create directory \/usr\/local\/lib\/systemd\/system\/ which does not exist by default\n      ansible.builtin.file:\n        path: \/usr\/local\/lib\/systemd\/system\/\n        state: directory\n        mode: '0755'\n        owner: root\n        group: root\n\n    - name: Install latest MyStartup.service\n      copy:\n        src: \/home\/dboth\/development\/ansible\/BasicTools\/files\/MyStartup.service\n        dest: \/usr\/local\/lib\/systemd\/system\/MyStartup.service\n        mode:  754\n        owner: root\n        group: root\n\n    - name: Enable and start MyStartup.service\n      service: \n        name: MyStartup.service\n        state: started \n        enabled: yes\n\n################################################################################\n# This lets us know if we need to reboot after installing updates. We probaly  #\n# will need to in most cases.                                                  #\n################################################################################\n    - name: Check for currently available updates\n      command: doUpdates.sh -c\n      register: check\n    - debug: var=check.stdout_lines\n\n################################################################################\n# Now install all available updates.                                           #\n################################################################################\n    - name: Install all current updates\n      dnf:\n        name: \"*\"\n        state: latest\n\n################################################################################\n# This will reboot and then wait for the remote host to complete its           #\n# restart before proceeding with the rest of the tasks                         #\n################################################################################\n    - name: Reboot if necessary and reboot extra variable is true\n      reboot:\n      when: (check.stdout | regex_search('reboot will be required')) and Reboot == \"true\"\n\n################################################################################\n# Install some additional repositories                                         #\n################################################################################\n    - name: Install and enable the RPM Fusion Free and nonfree repositories\n      dnf:\n        name: \"{{ item }}\"\n        state: present\n        # This is necessary to prevent a GPG error (version 32-1 - where did -1 come from?)\n        disable_gpg_check: yes\n      with_items:\n        - http:\/\/download1.rpmfusion.org\/free\/fedora\/rpmfusion-free-release-{{ ansible_distribution_version }}.noarch.rpm\n        - http:\/\/download1.rpmfusion.org\/nonfree\/fedora\/rpmfusion-nonfree-release-{{ ansible_distribution_version }}.noarch.rpm\n\n################################################################################\n# Install a bunch of tools and other packages. Install them all here with a    #\n# bit of grouping to make things a bit easier to find.                         #\n################################################################################\n# Install command line tools \n    - name: Install command line tools\n      dnf:\n        name: \n          - apcupsd\n          - atop\n          - bc\n          - clamav\n          - python3-cpuinfo\n          - ddrescue\n          - detox\n          - dictd\n          - dmidecode\n          - fail2ban\n          - hddtemp\n          - htop \n          - hwinfo\n          - iftop\n          - inxi\n          - iotop\n          - konsole\n          - iptables-services\n          - iptraf-ng\n          - lm_sensors\n          - logwatch\n          - lshw\n          - mc\n          - fastfetch\n          - newfetch\n          - nmon\n          - nvme-cli\n          - plocate\n          - powertop\n          - psutils\n          - rpmorphan \n          - screen\n          - screenfetch\n          - sendmail\n          - sendmail-cf\n          - ShellCheck\n          - sipcalc\n          - sysstat\n          - task\n          - trash-cli\n          - units\n          - util-linux-user\n          - vim-common \n          - vim-enhanced\n          - vim-filesystem\n          - vim-minimal\n          - wget\n          - whois\n        state: latest\n\n    - name: Install some fun command line programs\n      dnf:\n        name: \n          - asciiquarium\n          - banner\n          - boxes\n          - bsd-games\n          - cmatrix\n          - cowsay\n          - figlet\n          - fortune-mod\n          - sl\n        state: latest\n\n################################################################################\n# Install development tools required for Python pip and VirtualBox as well as  #\n# for development and creating RPM packages.                                   #\n################################################################################\n    - name: Install some development tools\n      dnf:\n        name: \n          - kernel-devel\n          - gcc\n          - dkms\n          - rpm-build\n          - python-devel\n        state: latest\n      when: development == \"true\"\n\n################################################################################\n# Add some configuration customization to \/etc\/screenrc for the                #\n# hard status line.                                                            #\n################################################################################\n    - name: Customize the \/etc\/screenrc hard status line 1.\n      lineinfile:\n        path: \/etc\/screenrc\n        insertafter: EOF\n        line: '# Customize the hard status line by David Both'\n\n    - name: Customize the \/etc\/screenrc hard status line 2.\n      lineinfile:\n        path: \/etc\/screenrc\n        insertafter: EOF\n        line: 'hardstatus alwayslastline'\n\n    - name: Customize the \/etc\/screenrc hard status line 3.\n      lineinfile:\n        path: \/etc\/screenrc\n        insertafter: EOF\n        line: \"hardstatus string '%{= kG}&#91; %{G}%H %{g}]&#91;%= %{= kw}%?%-Lw%?%{r}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%?%= %{g}]&#91;%{B} %m-%d %{W}%c %{g}]'\"\n          \n    - name: Customize the \/etc\/screenrc hard status line 4.\n      lineinfile:\n        path: \/etc\/screenrc\n        insertafter: EOF\n        line: ''\n\n################################################################################\n# Install Midnight Commander configuration files                               #\n################################################################################\n    - name: create ~\/.config directory in \/etc\/skel\n      file:\n        path: \/etc\/skel\/.config\n        state: directory\n        mode: 0775\n        owner: root\n        group: root\n\n    - name: copy latest personal Midnight Commander skin to \/usr\/share\n      copy:\n        src: \/home\/dboth\/development\/ansible\/PostInstall\/files\/MidnightCommander\/DavidsGoTar.ini\n        dest: \/usr\/share\/mc\/skins\/DavidsGoTar.ini\n        mode: 0644\n        owner: root\n        group: root\n\n    - name: create ~\/.config\/mc directory for root\n      file:\n        path: \/home\/dboth\/development\/.config\/mc\n        state: directory\n        mode: 0755\n        owner: root\n        group: root\n\n    - name: Copy the most current Midnight Commander configuration files to \/home\/dboth\/development\/.config\/mc\n      copy:\n        src: \"{{ item }}\"\n        dest: \/home\/dboth\/development\/.config\/mc\n        mode: 0755\n        owner: root\n        group: root\n      with_fileglob:\n          - \/home\/dboth\/development\/ansible\/PostInstall\/files\/MidnightCommander\/*ini\n\n# Placing the config files in \/etc\/skel makes them available for \n# all users created from now on.\n    - name: create ~\/.config\/mc directory in \/etc\/skel\n      file:\n        path: \/etc\/skel\/.config\/mc\n        state: directory\n        mode: 0775\n        owner: root\n        group: root\n\n    - name: Copy the most current Midnight Commander configuration files to \/etc\/skel\n      copy:\n        src: \"{{ item }}\"\n        dest: \/etc\/skel\/.config\/mc\n        mode: 0644\n        owner: root\n        group: root\n      with_fileglob:\n          - \/home\/dboth\/development\/ansible\/PostInstall\/files\/MidnightCommander\/*ini\n\n################################################################################\n# Install other configuration files                                            #\n################################################################################\n# Copy .bash_logout to \/etc\/skel becuase it is not created by default\n    - name: copy .bash_logout file to \/etc\/skel\n      copy:\n        src: \/home\/dboth\/development\/ansible\/PostInstall\/files\/BashConfigFiles\/.bash_logout\n        dest: \/etc\/skel\/\n        mode: 0644\n        owner: root\n        group: root\n\n# Copy .bash_logout to \/root because it is not created by default\n    - name: copy .bash_logout file to \/root\n      copy:\n        src: \/home\/dboth\/development\/ansible\/PostInstall\/files\/BashConfigFiles\/.bash_logout\n        dest: \/home\/dboth\/development\/\n        mode: 0644\n        owner: root\n        group: root\n\n    - name: copy myBashConfig.sh file to \/etc\/profile.d\n      copy:\n        src: \/home\/dboth\/development\/ansible\/PostInstall\/files\/BashConfigFiles\/myBashConfig.sh\n        dest: \/etc\/profile.d\n        mode: 0644\n        owner: root\n        group: root\n\n    - name: copy top configuration file to root\n      copy:\n        src: \/home\/dboth\/development\/ansible\/PostInstall\/files\/top\/toprc\n        dest: \/root\n        mode: 0644\n        owner: root\n        group: root\n\n    - name: copy top configuration file to \/etc\/skel\n      copy:\n        src: \/home\/dboth\/development\/ansible\/PostInstall\/files\/top\/toprc\n        dest: \/etc\/skel\n        mode: 0644\n        owner: root\n        group: root\n\n    - name: copy root crontab to \/var\/spool\/cron\n      copy:\n        src: \/home\/dboth\/development\/ansible\/PostInstall\/files\/crontab\/root\n        dest: \/var\/spool\/cron\n        mode: 0644\n        owner: root\n        group: root\n\n    - name: Restart the crond daemon\n      systemd:\n        name: crond\n        state: restarted\n        enabled: yes\n\n################################################################################\n# Install some additional files and Bash scripts to \/root                      #\n################################################################################\n    - name: Copy some additional Bash scripts to \/root\n      copy:\n        src: \"{{ item }}\"\n        dest: \/root\n        mode: 0774\n        owner: root\n        group: root\n      with_fileglob:\n          - \/home\/dboth\/development\/ansible\/PostInstall\/files\/root\/scripts\/*\n\n    - name: Copy some additional non-executable files to \/root\n      copy:\n        src: \"{{ item }}\"\n        dest: \/root\n        mode: 0664\n        owner: root\n        group: root\n      with_fileglob:\n          - \/home\/dboth\/development\/ansible\/PostInstall\/files\/root\/files\/*\n\n################################################################################\n# Stop the ABRT services to prevent crashes from sucking up huge amounts of    #\n# resources when a dump occurs. ABRT is the Automated Bug Reporting Tool that  #\n# is used for reporting crash information.                                     #\n################################################################################\n    - name: Stop and disable the abrt-xorg daemon\n      systemd:\n        name: abrt-xorg\n        state: stopped\n        masked: yes\n        enabled: no\n\n    - name: Stop and disable the abrt-journal-core daemon\n      systemd:\n        name: abrt-journal-core\n        state: stopped\n        masked: yes\n        enabled: no\n\n    - name: Stop and disable the abrt-oops daemon\n      systemd:\n        name: abrt-oops\n        state: stopped\n        masked: yes\n        enabled: no\n\n    - name: Stop and disable the abrtd daemon\n      systemd:\n        name: abrtd\n        state: stopped\n        masked: yes\n        enabled: no\n\n################################################################################\n# Start and enable some services that are needed.                              #\n################################################################################\n    - name: Start and enable the sysstat daemon\n      systemd:\n        name: sysstat\n        state: started\n        enabled: yes\n\n################################################################################\n# Set up daily creation of the MOTD                                            #\n################################################################################\n\n    - name: Install create_motd script in \/etc\/cron.daily\n      copy:\n        src: \/home\/dboth\/development\/ansible\/PostInstall\/files\/usrlocal\/bin\/create_motd\n        dest: \/etc\/cron.daily\n        mode: 0774\n        owner: root\n        group: root\n\n    - name: Create the \/etc\/motd file for the first time\n      command: \/usr\/local\/bin\/create_motd\n\n\n################################################################################\n# Setting SSHD configuration                                                   #\n################################################################################\n\n    - name: Add banner location to end of sshd_config\n      lineinfile:\n        path: \/etc\/ssh\/sshd_config\n        insertafter: EOF\n        line: 'Banner \/etc\/LogBanner'\n\n    - name: Copy the LogBanner file\n      copy:\n        src: \/home\/dboth\/development\/ansible\/PostInstall\/files\/etc\/LogBanner\n        dest: \/etc\n        mode: 0664\n        owner: root\n        group: root\n\n###############################################################################\n# Set grub.conf to remove \"rhgb\" from kernel config line, set menu timeout to #\n# 10 seconds and comment out \"hiddenmenu\". This gives more time to interrupt  #\n# the boot process and make on-the-fly changes to it.                         #\n#                                                                             #\n# Also set selinux=0 to disable selinux on the kernel command line.           #\n###############################################################################\n# modify \/etc\/default\/grub\n    - name: Change \/etc\/default\/grub to allow recovery boot option.\n      replace:\n        path: \/etc\/default\/grub\n        regexp: 'GRUB_DISABLE_RECOVERY=\"true\"'\n        replace: 'GRUB_DISABLE_RECOVERY=\"false\"'\n\n    - name: Change \/etc\/default\/grub to 10 second timeout\n      replace:\n        path: \/etc\/default\/grub\n        regexp: 'GRUB_TIMEOUT=&#91;0-9]*'\n        replace: 'GRUB_TIMEOUT=10'\n\n    - name: Remove rhgb option from \/etc\/default\/grub kernel command line\n      replace:\n        path: \/etc\/default\/grub\n        regexp: ' rhgb'\n        replace: ''\n\n    - name: Remove quiet option from \/etc\/default\/grub kernel command line\n      replace:\n        path: \/etc\/default\/grub\n        regexp: ' quiet'\n        replace: ''\n\n    - name: Set selinux=0 on \/etc\/default\/grub kernel command line\n      replace:\n        path: \/etc\/default\/grub\n        regexp: 'usr\"'\n        replace: 'usr selinux=0\"'\n\n# Rebuild grub.cfg files\n    - name: Rebuild \/boot\/grub2\/grub.cfg\n      command:\n        cmd: grub2-mkconfig -o \/boot\/grub2\/grub.cfg\n\n################################################################################\n# Also set the selinux configuration file to permissive.                       #\n################################################################################\n    - name: Set selinux to disabled in \/etc\/selinux\/config\n      replace:\n        path: \/etc\/selinux\/config\n        regexp: 'SELINUX=enforcing'\n        replace: 'SELINUX=permissive'\n\n\n################################################################################\n# Set the level of detail for logwatch.conf and start timer.                   #\n################################################################################\n    - name: Add the highest level of detail to logwatch.conf\n      lineinfile:\n        path: \/etc\/logwatch\/conf\/logwatch.conf\n        insertafter: EOF\n        line: 'Detail = 6'\n\n################################################################################\n# Add my email address to \/etc\/aliases if it exists, so that all emails to     #   \n# root go to my email address. This must be done after installing SendMail.    #   \n################################################################################\n    - name: Add my email address to \/etc\/aliases\n      lineinfile:\n        path: \/etc\/aliases\n        insertafter: EOF\n        line: 'root:           david@both.org'\n\n    - name: Activate revised aliases\n      command:\n        cmd: newaliases\n\n################################################################################\n# Install BOINC                                                                #\n################################################################################\n    - name: Install the Boinc client and tui\n      dnf:\n        name: \n          - boinc-client\n          - boinc-tui\n      when: David == \"true\"\n################################################################################\n# Copy default boinc configuration files.                                      #\n################################################################################\n    - name: Install default boinc configuration files.\n      copy:\n        src: \"{{ item }}\"\n        dest: \/var\/lib\/boinc\n        mode: 0644\n        owner: boinc\n        group: boinc\n      with_fileglob:\n          - \/home\/dboth\/development\/ansible\/PostInstall\/files\/boinc\/*\n      when: David == \"true\"\n\n################################################################################\n# Add a line to end of \/etc\/vimrc to set listchars to allow viewing of         #\n# whitespace characters.                                                       #\n################################################################################\n    - name: Add a line to end of \/etc\/vimrc to allow viewing of whitespace characters.\n      lineinfile:\n        path: \/etc\/vimrc\n        insertafter: EOF\n        line: 'set listchars=eol:$,nbsp:_,tab:&lt;-&gt;,trail:~,extends:&gt;,space:+'\n\n################################################################################\n# Create non-root users                                                        #\n# Use mkpasswd --method=sha-512 &lt;Password&gt; to generate the password hash.      #\n################################################################################\n# Add non-root user dboth (me) This needs to be done before some other\n# tasks and after installing Midnight Commander configuration files in \/etc\/skel\n    - name: Add user dboth\n      user:\n        name: dboth\n        comment: David Both\n        password: $6$iVSAb5VYBem\/ZC.W$KcHhEiylLXsPFy2tu.Z2Mr2TnE8Ed69ojOmf57HfceJvf8y6J9QSAXmKuq9WDxdWJH9y09CZTuBPj3eTjZpak.\n        groups: wheel\n        state: present\n        create_home: yes\n      when: David == \"true\"\n\n    - name: Add student user for testing\n      user:\n        name: student\n        comment:  Student User\n        password: $6$.N.Kuu3j8pu.WDZH$HyQeho4itMqwsy61PxiFwrOsDtCO8Km7jLDD0zQcvhL\/LzB0zErHnr2zyrX\/qIpMwhloegA4DcugUsNZnWYma0\n        state: present\n        create_home: yes\n      when: David == \"true\"\n\n    - name: Install some GUI admninistration tools\n      dnf:\n        name: gnote,vim-X11,xfe\n        state: latest\n      when: Gui == \"true\"\n\n################################################################################\n# Lightdm is the default display manager but install others just in case.      #\n################################################################################\n# Install the display managers\n    - name: Install Alternative display managers, lxdm,xorg-x11-xdm,sddm,and lightdm\n      dnf:\n        name: lxdm,xorg-x11-xdm,sddm,lightdm\n        state: latest\n\n################################################################################\n# Install additional desktops if this is to be a GUI workstation.              #\n# - Mate Desktop                                                               #\n# - Cinnamon Desktop                                                           #\n# - LXDE Desktop                                                               #\n# - Xfce Desktop                                                               #\n#                                                                              #\n################################################################################\n    - name: Install Mate desktop\n      dnf:\n        name: '@Mate Desktop'\n        state: latest\n      when: mate == \"true\"\n    - name: Install Cinnamon desktop\n      dnf:\n        name: '@Cinnamon Desktop'\n        state: latest\n      when: cinnamon == \"true\"\n    - name: Install LXDE desktop\n      dnf:\n        name: '@LXDE Desktop'\n        state: latest\n      when: lxde == \"true\"\n    - name: Install XFCE desktop\n      dnf:\n        name: '@Xfce Desktop'\n        state: latest\n      when: xfce == \"true\"\n\n################################################################################\n# Installing these new desktops changes the enabled display manager. So we     #\n# reenable lightdm and restart the display manager service.                    #\n################################################################################\n    - name: Disable the current display manager\n      ansible.builtin.systemd:\n        name: display-manager.service\n        enabled: no\n \n    - name: Enable lightdm\n      ansible.builtin.systemd:\n        name: lightdm.service\n        enabled: yes\n\n\n    - name: Copy a large number of big background files to \/usr\/share\/wallpapers. This will take a while.\n      copy:\n        src: \"{{ item }}\"\n        dest: \/usr\/share\/wallpapers\/\n        mode: 0664\n        owner: root\n        group: root\n      with_fileglob:\n          - \/home\/dboth\/development\/ansible\/PostInstall\/files\/wallpapers\/*\n      when: Wallpapers == \"true\"\n\n################################################################################\n# Install some GUI applications here if variables Gui and Apps are both true.  #\n################################################################################\n# Start with some groups\n    - name: Install basic LibreOffice applications\n      dnf:\n        name: '@LibreOffice'\n        state: latest\n      when: Gui == \"true\" and Apps == \"true\"\n\n    - name: Install fonts group from the Fedora repository\n      dnf:\n        name: '@fonts'\n        state: latest\n      when: Gui == \"true\" and Apps == \"true\"\n\n    - name: Install additional individual fonts from the Fedora repository\n      dnf:\n        name: 'cmatrix-x11-fonts'\n        state: latest\n      when: Gui == \"true\" and Apps == \"true\"\n\n    - name: Install some additional GUI applications and tools \n      dnf:\n        name: \n          - libreoffice-base\n          - libreoffice-draw\n          - libreoffice-math\n          - libreoffice-icon-theme-papirus\n          - libreoffice-TexMaths\n          - krusader\n          - kmymoney\n          - skrooge\n          - tellico\n          - gramps\n          - gnucash\n          - stellarium \n          - celestia\n          - thunderbird\n          - firefox\n          - okular  \n          - amarok\n          - asunder\n          - audacious\n          - audacity\n        state: latest\n      when: Gui == \"true\" and Apps == \"true\"\n\n################################################################################\n# Remove some things that are not needed, not wanted, or just don't work.      #\n################################################################################\n    - name: Remove dnfdragora because it does not work.\n      dnf:\n        name: dnfdragora\n        state: absent\n      when: dnfdragora == \"false\"\n\n\n\n################################################################################\n# Perform some final tasks that need to be done after everything else          #\n################################################################################\n    - name: Install Rootkit Hunter\n      dnf:\n        name: \n          - rkhunter\n        state: latest\n\n    - name: Create a current file properties database for rkhunter\n      command:\n        cmd: rkhunter --propupd\n\n# Rebuild the man pages\n    - name: Rebuild man pages\n      command: mandb\n\n################################################################################\n# This will reboot the target host and then wait for it to complete its final  #\n# reboot when the reboot variable is true. Which it is by default. The         #\n# sequence of operations in this playbook does not result in showing the added #\n# user accounts on the graphical login screen. The reboot does that. It also   #\n# ensures that all newly created users and groups are acive for new logins and #\n# the latest libraries are in effect.                                          #\n################################################################################\n    - name: Reboot at the end of the procedure \n      reboot:\n      when: Reboot == \"true\"\n\n################################################################################\n################################################################################<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\">Figure 1: Ansible playbook for performing all my post-install tasks.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>Warning!!! \u2014 Don\u2019t use this Ansible playbook on a production system until you know exactly what it does and have modified it to meet your own needs. This article and the playbook that goes with it are intended as a tool to demonstrate what can be done with Ansible to perform post-installation tasks. I strongly recommend that you experiment with this tool on a non-production virtual machine.<\/em><\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What it does &#8212; a bit<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Don&#8217;t worry &#8212; despite including the entire playbook so you can see some of the many things that can be done with Ansible, I&#8217;m not going to describe every line of this playbook. The comments and the Ansible tasks themselves are fairly explanatory. However, you do need to know that some of the files that are installed via this playbook are local ones and work only on my hosts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The first part of the playbook sets a number of variables that are used throughout. The only one I usually change is the hostname. Any variables can be set from the command line using the ansible-playbook option, -e, but I do like to change them in the playbook; that&#8217;s just my preference. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then there&#8217;s a short section that sets some configuration. The section that disables AVAHI services and enables the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Name_Service_Switch\" data-type=\"link\" data-id=\"https:\/\/en.wikipedia.org\/wiki\/Name_Service_Switch\" target=\"_blank\" rel=\"noreferrer noopener\">NSS DNS<\/a> service is important to me. I find that, for my network, that&#8217;s a better option for name services. I have a DNS server in my network and, when configured with NSS, is faster than the very chatty, peer-dependent, AVAHI <a href=\"https:\/\/en.wikipedia.org\/wiki\/Multicast_DNS\" data-type=\"link\" data-id=\"https:\/\/en.wikipedia.org\/wiki\/Multicast_DNS\" target=\"_blank\" rel=\"noreferrer noopener\">mDNS<\/a>. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I also disable the smart-card deamon because I don&#8217;t use smart cards in my environment. I&#8217;ve never encountered a situation where this service was used, so I&#8217;m not sure why it&#8217;s even included by default, let alone enabled. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then Ansible installs some files that need to be there after the installation of updates and the reboot. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It also installs all current updates and reboots the target host. This is where some of the advantages of using Ansible become apparent. Unless it&#8217;s updating itself, Ansible doesn&#8217;t run on the target host; it runs on the Ansible hub and sends commands to the target host via SSH. When Ansible sends the <strong>reboot<\/strong> command to the target host, it waits until that system has rebooted and is responding to SSH commands. Ansible then continues sending instructions from the rest of the playbook. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That bit of coolness prevents the SysAdmin, me, from needing to intervene manually to either perform the reboot or to restart the playbook after the reboot. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A large part of the rest of the playbook installs a large number of problem solving tools I like to use and that aren&#8217;t installed by default. Any of those tools that are already installed because I used a different Fedora spin, or whatever, are recognized by Ansible and noted with the green OK message. It also performs a number of configuration tasks that saves me a lot of time, both in performing the configuration, as well as in performance of my SysAdmin tasks.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You&#8217;ll also notice that the playbook does install some fun command line games. SysAdmins like to have fun, too.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Desktops<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Whether your system already has a GUI desktop installed or not, this playbook can install any desktops that you specify, like Xfce, LCDE, MATE, or Cinnamon. Those are the ones I usually install. If you want to add others, you can add tesks to do so. Just list the desktop groups to install for Fedora with the command in Figure 2&#8230; <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$<strong> dnf grouplist | grep -i desk<\/strong>\n   Phosh Desktop\n   LXQt Desktop\n   MATE Desktop\n   Sugar Desktop Environment\n   Deepin Desktop\n   Budgie Desktop\n   Basic Desktop\n   i3 desktop\n   Sway Desktop\n   Xfce Desktop\n   LXDE Desktop\n   Cinnamon Desktop\n   Desktop accessibility\n   Budgie Desktop Applications\n   GNOME Desktop Environment\n   KDE (K Desktop Environment)<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\">Figure 2: This command displays all Fedora package groups.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&#8230; Then get more information about the LXDE desktop, for example, as in Figure 3. You can use this command to learn more about any of the desktop groups.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>dnf groupinfo \"LXDE Desktop\"<\/strong>\nLast metadata expiration check: 0:05:06 ago on Mon 08 Jul 2024 01:01:35 PM EDT.\nEnvironment Group: LXDE Desktop\n Description: LXDE is a lightweight X11 desktop environment designed for computers with low hardware specifications like netbooks, mobile devices or older computers.\n Mandatory Groups:\n   Administration Tools\n   Common NetworkManager Submodules\n   Core\n   Desktop accessibility\n   Dial-up Networking Support\n   Fonts\n   Guest Desktop Agents\n   Hardware Support\n   Input Methods\n   LXDE\n   Multimedia\n   Printing Support\n   Standard\n   base-x\n Optional Groups:\n   3D Printing\n   Applications for the LXDE Desktop\n   Cloud Management Tools\n   LXDE Office\n   Multimedia support for LXDE<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\">Figure 3: More detailed information about the LXDE desktop.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once you&#8217;ve decided which desktops to install, add tasks to do that. It&#8217;s not necessary to delete any of the ones that are already there.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Parting thoughts<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Performing all of my post-installation tasks using Ansible saves me having to monitor the process and to intervene. I have configured Ansible to send commands to the remote host using the root account, but it also provides options for using non-root accounts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Modifying the Ansible playbook is easy so don&#8217;t hesitate to experiment with it on your VM. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you have multiple target hosts you can have Ansible work on them both at the same time. Just list the hostnames in the hosts variable in the playbook or the extended-variables at the command line. Ansible keeps track of each host separately so even if they&#8217;re significantly different in speed, the fastest host isn&#8217;t forced to wait untill the slower hosts catch up. All hosts finish at their own speed. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I currently use Ansible to perform all of my post-installation tasks. It&#8217;s the best tool I&#8217;ve used in that it does everything I need it to and I don&#8217;t need to intervene at any point. <\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n<ol class=\"wp-block-footnotes\"><li id=\"60472120-83a6-4f38-9825-b1bb304e869e\">Ansible can also be used with <a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/os_guide\/windows_usage.html\" data-type=\"link\" data-id=\"https:\/\/docs.ansible.com\/ansible\/latest\/os_guide\/windows_usage.html\" target=\"_blank\" rel=\"noreferrer noopener\">Windows<\/a> hosts. <a href=\"#60472120-83a6-4f38-9825-b1bb304e869e-link\" aria-label=\"Jump to footnote reference 1\">\u21a9\ufe0e<\/a><\/li><\/ol>","protected":false},"excerpt":{"rendered":"<p>In previous articles about my use of automation in performing post-install tasks for new Linux installations, Those approaches worked well for the times I used them, but as the requirements of my network and the hosts connected to it grew and became more complex, the capabilities of those tools couldn&#8217;t keep up.<\/p>\n<p>I needed a new method for doing post-install tasks. I also needed new ways to perform other tasks, too. I started working with Ansible to first familiarize myself with it and then to perform more complex tasks such as Fedora updates and my post-install tasks.<\/p>\n","protected":false},"author":2,"featured_media":6351,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","footnotes":"[{\"content\":\"Ansible can also be used with <a href=\\\"https:\/\/docs.ansible.com\/ansible\/latest\/os_guide\/windows_usage.html\\\" data-type=\\\"link\\\" data-id=\\\"https:\/\/docs.ansible.com\/ansible\/latest\/os_guide\/windows_usage.html\\\" target=\\\"_blank\\\" rel=\\\"noreferrer noopener\\\">Windows<\/a> hosts.\",\"id\":\"60472120-83a6-4f38-9825-b1bb304e869e\"}]"},"categories":[482,295,69,90,5,480],"tags":[483,296,481],"class_list":["post-6012","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-advanced","category-ansible","category-fun","category-in-depth","category-linux","category-post-installation","tag-advanced","tag-ansible","tag-post-install-tasks"],"modified_by":"David Both","_links":{"self":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/6012","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6012"}],"version-history":[{"count":29,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/6012\/revisions"}],"predecessor-version":[{"id":6488,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/6012\/revisions\/6488"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/media\/6351"}],"wp:attachment":[{"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6012"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=6012"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=6012"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}