Getting started - Bash script actions "converted" into a playbook

Hi All,

I’m managing a set of about 60 Debian computers with a deployment script.
Purpose is to copy some system files to configure the system (login manager, …) and have a default /home/user directory (bookmarks, pinneds apps, …).

I’d like to switch to Ansible to avoid having to run the script manually or each system, and to benefit from “idempotence” (I love the word :heart_eyes:).

I’m not asking to do the job on my behalf, just would like to confirm that my script building blocks properly translate into playbook entries.

Software updates

Script

apt update
apt upgrade -y
apt install -y rsync openssh-client openssh-server net-tools
apt purge -y --autoremove gnome-games

Ansible

  tasks:
    - name: updates
      block:
        - name: update
          apt:
            update_cache: yes
        - name: upgrade
          apt:
            upgrade: dist
        - name: install
          apt:
            name:
              - rsync
              - openssh-client
              - openssh-server
              - net-tools
            state: present
        - name: remove
          apt:
            name: gnome-games
            state: absent
            autoremove: yes

Disabling passwords

Script

passwd -d guest

Ansible

    - name: Désactivation du mot de passe pour l'utilisateur guest
      user:
        name: guest
        password: ""  # Mot de passe vide

Remove some files and copy some others

Script

rm -Rf /usr/share/wayland-sessions/*
rm -Rf /usr/share/xsessions/*
rm -Rf /etc/skel/*
rm -Rf /home/guest/*
rm -Rf /home/guest/.*
rsync -az --progress --ignore-times root@$SKELETON_SERVER:$SKELETON_PATH/ /etc/skel/
rsync -az --progress --ignore-times /etc/skel/ /

Ansible

    - name: Copie du skeleton depuis le serveur
      block:
        - name: Suppression des sessions Wayland et X existantes
          file:
            path: "{{ item }}"
            state: absent
          loop:
            - /usr/share/wayland-sessions/
            - /usr/share/xsessions/
        - name: Copie du skeleton depuis le serveur distant
          synchronize:
            src: "root@{{ skeleton_server }}:{{ skeleton_path }}/"
            dest: "{{ local_dest }}etc/skel/"
            mode: push
            archive: yes
            compress: yes
        - name: Application du skeleton à la racine
          synchronize:
            src: "{{ local_dest }}etc/skel/"
            dest: "{{ local_dest }}/"
            mode: pull
            archive: yes
            compress: yes

Ownership and permission changes

Script

chown -R guest:guest /home/guest
chmod +x /usr/share/sddm/scripts/Xstop

Ansible

        - name: Changement de propriétaire pour /home/guest
          file:
            path: /home/guest
            owner: guest
            group: guest
            recurse: yes

Other actions required

  1. I don’t know how to change permissions on folders
  2. I don’t know how to invoke extra specific cxommands such as
systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
sudo dconf update #pour couvrir la partie Cinnamon
sudo update-grub
systemctl restart ssh

Can you please help me confirm that my building blocks look OK?
Are there ways to run commands such as the ones at the bottom of my list?

Ultimately, if I have a working script, should I consider copying the script and simply running it on my clients via Ansible, and avoid converting the whole script into a playbook?

Thanks a lot!

3 Likes

Hi @cndpansible

Welcome to the Ansible forum! :slightly_smiling_face:

You got a really good starting point here. Under your Ansible heading, for your playbook tasks I’d recommend using the Fully Qualified Collection Name (FQCN) for the modules used in each task, this helps with knowing which collection the modules are from and if another collection has an apt module then it avoids potential clashes in the future.

A small example:

---
- name: Example Playbook
  hosts: some_hosts
  tasks:
    - name: Update apt cache
      ansible.builtin.apt:
        update_cache: true

You can find module FQCNs using the ansible-doc command like: ansible-doc apt or you can use the online doc site: ansible.builtin.apt module – Manages apt-packages — Ansible Community Documentation

  1. I don’t know how to change permissions on folders

You can use the mode parameter with the file module to change permissions (RWX):

- name: Change permissions for /home/guest
  ansible.builtin.file:
    path: /home/guest
    owner: guest
    group: guest
    recurse: true
    state: directory
    mode: u=rwx,g=rx,o=

The above mode is the equivalent of: chmod 750.

  1. I don’t know how to invoke extra specific cxommands such as
systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target

You could use the ansible.builtin.systemd_service module – Manage systemd units — Ansible Community Documentation to mask these and restart services like ssh.

Hope this helps :slightly_smiling_face: - Based on what you’ve said, I think Ansible would be ideal for this.

Here is some links which might help you further:

1 Like

I don’t know how to invoke extra specific commands such as …

Out of mind, for the systemd services you could try

    - name: Mask service
      systemd:
        name: "{{ item }}"
        masked: true
      loop:
        - sleep.target
        - suspend.target
        - hibernate.target
        - hybrid-sleep.target

and

    - name: Restart ssh daemon
      systemd:
        name: sshd
        daemon_reload: true
        state: restarted

For dconf There is also a module ansible.builtin.debconf .

1 Like

For update-grub I think the only option is to use the command module, there is no grub module:

- name: Grub configuration updated
  ansible.builtin.command:
    cmd: update-grub
  changed_when: true

I suggest setting changed_when to true because otherwise you would probably have to do something like use the shell module and write a Bash script that writes the output somewhere on each run and compare the latest run output to the previous output to see if they differ, I don’t think there is a simply way of knowing if running update-grub changed anything as it is a command with few options:

update-grub -h
Usage: grub-mkconfig [OPTION]
Generate a grub config file

  -o, --output=FILE       output generated config to FILE [default=stdout]
  -h, --help              print this message and exit
  -V, --version           print the version information and exit

Report bugs to <bug-grub@gnu.org>.
1 Like

Thanks a million @chris @dbrennand !

So many details and pointers, I had looked at the doc, but clearly had overlooked some stuff.

Allow me to play devil’s advocate: I do see the value of Ansible, but can you please help me understand what would be the upsides and downsides of trying to “simply” trigger my deployment script via Ansible, rather than fully translating it into playbooks?

I believe this might be a “too easy way out”, and maybe I would regret it in the future, but on the short term, I feel tempted to take the shortcut :wink:

Thanks again!

1 Like

And thank you @U880D too (I could only tag 2 people per post :wink: )

1 Like

I started using Ansible to run the Bash commands I’d be using for years, it’s fine to start there! Take it one step at a time and see how you get on.

1 Like

Well, from my point of view there is no right or wrong at the beginning. Since Ansible is agentless, you are almost writing a kind of documentation upfront, which can then be read and executed by a human or by a machine, it will depend on the complexity of the tasks and its dependencies.

For simple tasks without complexity it might be OK to use command or shell. But they may lack error handling then. Also be non-technical human may have problems to understand what the task is about. If there is more complexity which needs to be abstracted, error handling necessary, or dealing with data structures and formatting output, specific Ansible modules will gain advantage fast.

An example for such could be accessing REST APIs versus command with curl or the uri module. A lot of Ansible modules are just abstractions for REST API but make it very simple the write and read them, but it will also introduce a dependency to such modules, there availability and maintenance.

For the beginning one could start with commands and introduce more and more specific modules later during daily development and operations.

2 Likes

The upside is your existing script is already written. That’s kind of a huge thing. Within the scope of your question, there hardly is any downside. You can use ansible as an “easy button” to continue doing things the way you’ve been doing them. Even so, Ansible brings some things to the table. For example, how are you deploying the script to your hosts? An Asible project can act as the canonical source for your script (or its equivalent functionality in tasks), an automatic deployment mechanism, plus a trigger to run it, along with a lot of flexibility for specifying which hosts to deploy and run it on. That’s a lot of gain simply by using Ansible to “simply” trigger your script.

The downsides for only doing that, though, include missing out on a lot of error handling. Shell scripts are notoriously difficult to write in a way that properly handles errors. It’s possible, but rarely done. Breaking out that functionality into tasks gives you that error detection almost for free. You still have to decide what to do about errors, maybe, eventually, but at least you’ll have a reasonable chance of becoming aware of them. There’s a high likelihood that you wouldn’t find out about errors in your current script until you tried to use one of these new hosts.

Beyond the scope of this script or its equivalent functionality, though, you’ll likely come up with additional things you’ll need to do on, with, or to these or other hosts. Creating additional playbooks in the project fits perfectly into Ansible’s organized framework for accomplishing “do A, B, and C to hosts X, Y, and Z”-type activities. That’s so much cleaner than adding yet another script-without-a-home that only you know about that has to be deployed and run a certain way but not on Tuesday…

You can certainly start using Ansible as a simple trigger, but it quickly becomes a solution to a range of problems you may not have realized you have. You’ll soon find you aren’t “doing things the way you’ve been doing them” any more. You’ll still accomplish those things, but within a manageable, scalable framework that a bunch of scripts lacks.

So, you’re on the right track. Keep looking for additional things that Ansible can do for you, and by all means keep asking good questions when you get stuck. We’re all here to help each other succeed.

1 Like

Thank you so much @utoddl !
I feel that I would miss a lot if I would just use Ansible to trigger my script, but your help made me realize it’s not an “all or nothing” thing. I’ll explore and progress!
Thanks a lot to you and the splendid community :smile:

2 Likes