Contact us
Leave a message

Computer Management

By now, all our Linux-based PCs (well, we don't have any others ;) are managed through Ansible -- which greatly facilitates harmonizing the machines' configurations or re-installing them from scratch. Here I present some useful procedures I follow in the context of family PC management.

Host-specific user management

If a computer in our inventory gets assigned to the familiy_boxes group, user accounts get automatically created according to configuration data found in a users list, each user configuration being defined by a dictionary of user-specific values (excerpt; in reality, some more configuration parameters are taken into account):

users:
  - name: homer
    full_name: Homer
    password: $6$D'oh
    is_kid: false
    manage_desktop: true
  - name: marge
    full_name: Marge
    password: $6$Hrmmm
    is_kid: false
    manage_desktop: false
  - name: bart
    full_name: Bart
    password: $6$EatMyShorts
    is_kid: true
    manage_desktop: true
  - name: lisa
    full_name: Lisa
    password: $6$IfAnyoneWantsMe,I'llBeInMyRoom
    shell: /usr/bin/zsh
    is_kid: true
    manage_desktop: false
  - name: maggie
    full_name: Maggie
    password: $6$SuckSuck
    is_kid: true
    manage_desktop: true

For certain hosts, it might turn out that some of these default values need to be changed, or it might even be necessary to create additional user accounts. In order to not need to explicitly re-type the whole users list, a role user_management was defined, which updates the users list according to a host-specific host_users dictionary. Such a dictionary might e. g. look like this:

host_users:
  marge:
    manage_desktop: false
  lisa:
    shell: /bin/bash
    manage_desktop: false
  guest:
    full_name: Guest
    manage_desktop: false
    password: $6$guest

Here's the task carrying out the magic:

---
# Tasks for user_management role

  - name: get list of default user names
    set_fact:
      # Creates a list of all the 'name' values of all dictionaries
      # contained in the default users list.
      _default_user_names: "{{ 
        users 
        | map(attribute='name') 
        | list 
      }}"

  - name: get list of host user_names
    set_fact:
      # Creates a list of all keys of the host_users dictionary, which are
      # the names of all users to be configured specifically for this host.
      _host_user_names: "{{ 
        (host_users | default({}, true))
        | dict2items
        | map(attribute='key') 
        | list
      }}"

  - name: determine additional user names
    set_fact:
      # Excludes all default user names from the set of host-specific user names.
      _additional_user_names: "{{
        _host_user_names 
        | difference(_default_user_names) 
      }}"

  - name: append additional users to default users
    set_fact:
      # For each host-specific user not yet contained in the default users dictionaries list,
      # add a dicionary containing 'name' as key and the additional user's name as value.
      users: "{{
        (users | default([]))
        + [{
          'name': item
        }]
      }}"
    loop: "{{ _additional_user_names}}"

  - name: process users' configuration
    set_fact:
      # For all users (both default and host-specific users, additional or not), merge/overwrite
      # host-specific user configuration into the user's cohnfiguration dictionary.
      _all_users: "{{ 
        (_all_users | default([])) 
        + [
            item 
            | combine(
                host_users[item.name] | default({}), 
                recursive = True
            )
        ]
      }}"
    loop: "{{ users }}"

  - name: get default user groups
    set_fact:
      # Ensures we have a list of default groups user are to assigned to.
      _default_user_groups: "{{ default_user_groups | default([]) }}"
  
  - name: show default user groups
    debug:
      # For debugging purposes.
      msg: "{{ _default_user_groups }}"

  - name: complete users' configuration
    set_fact:
      # Re-build the list of user dictionaries, ensuring all expected keys are present
      # and have default values, if not specified otherwise in the configuration data
      # gathered thus far.
      _users: "{{ 
        (_users | default([])) 
        + [
            item 
            | combine(
                {
                  'groups': (_default_user_groups + (item.addidional_groups | default([]))),
                  'full_name': (item.full_name | default(item.name)),
                  'shell': (item.shell | default('/bin/bash')),
                  'is_system_user': (item.is_system_user | default(false)),
                  'home': (item.home | default('/home/' + item.name)),
                  'id_rsa': (item.id_rsa | default('id_rsa')),
                  'is_kid': (item.is_kid | default(false)),
                  'manage_home': (item.is_kid | default(false)),
                  'manage_desktop': (item.is_kid | default(false)),
                  'record_session': (item.is_kid | default(false))
                }
            )
        ]
      }}"
    loop: "{{ _all_users }}"

  - name: apply users configuration
    set_fact:
      # Re-assign the newly created user configuration list to the users variable.
      users: "{{ _users}}"

  - name: show users
    debug:
      # For debugging purposes.
      msg: "{{ users }}"
  

And here's the effective user configuration finally applied to the host (changes highlighted):

users:
  - name: homer
    full_name: Homer
    password: $6$D'oh
    is_kid: false
    manage_desktop: true
  - name: marge
    full_name: Marge
    password: $6$Hrmmm
    is_kid: false
    manage_desktop: false # Was: true
  - name: bart
    full_name: Bart
    password: $6$EatMyShorts
    is_kid: true
    manage_desktop: true
  - name: lisa
    full_name: Lisa
    password: $6$IfAnyoneWantsMe,I'llBeInMyRoom
    shell: /bin/bash # Was: /usr/bin/zsh
    is_kid: true
    manage_desktop: false # Was: true
  - name: maggie
    full_name: Maggie
    password: $6$SuckSuck
    is_kid: true
    manage_desktop: true
  - name: guest # Completely new user entry
    full_name: Guest
    password: $6$guest
    is_kid: false
    manage_desktop: true