variablesansibletaskrolesansible-lint

Encountering an error decoupling tasks and vars from playbooks via roles


To start, I have a basic ansible directory structure for roles.

In the [ansible] directory:

- inventory
- playbook.yml
- [roles]
    - [gui_utils]
        - [defaults]
            - main.yml
        - [files]
            - main.yml
        - [handlers]
            - main.yml
        - [library]
            - my_module.py
        - [meta]
            - main.yml
        - [tasks]
            - main.yml
        - [templates]
            - main.yml
        - [vars]
            - main.yml

The only files that contain any relevant data are:

[all]
#
[prep]
ansible-prep ansible_connection=local ansible_host=localhost
 - hosts: prep
   tasks:
      - name: "Update cache if older than 3600 seconds"
        ansible.builtin.apt:
           update_cache: yes
           cache_valid_time: 3600
           update_cache_retries: 10
           update_cache_retry_max_delay: 18

      - name: "Import and run task to install 'gui_utils'".
        import_tasks: roles/gui_utils/tasks/main.yml
 - tasks:
      - name: "Load gui_utils_list variable"
        include_vars: "{{ role_path }}/vars/main.yml"

      - name: "Install GUI utility packages"
        ansible.builtin.apt:
           name: "{{ gui_utils_list }}"
           state: present
gui_utils_list:
   - notepadqq
   - redshift

Executing ansible-lint ansible/playbook.yml returns the following error.

root@ansible-prep:/home/user/Desktop/ansible-project# ansible-lint ansible/playbook.yml
CRITICAL Couldn't parse task at /home/user/Desktop/ansible-project/ansible/roles/gui_utils/tasks/main.yml:4 (couldn't resolve module/action 'tasks'. This often indicates a misspelling, missing collection, or incorrect module path.)
{ 'tasks': [ { '__file__': '/home/user/Desktop/ansible-project/ansible/roles/gui_utils/tasks/main.yml',
               '__line__': 16,
               'include_vars': '{{ role_path }}/vars/main.yml',
               'name': 'Load gui_utils_list variable'},
             { '__file__': '/home/user/Desktop/ansible-project/ansible/roles/gui_utils/tasks/main.yml',
               '__line__': 19,
               'ansible.builtin.apt': { '__file__': '/home/user/Desktop/ansible-project/ansible/roles/gui_utils/tasks/main.yml',
                                        '__line__': 21,
                                        'name': '{{ gui_utils_list }}',
                                        'state': 'present'},
               'name': 'Install GUI utility packages'}]}
root@ansible-prep:/home/user/Desktop/ansible-project# 

Unfortunately, this is not helping me to resolve the issue. ansible-lint ansible/roles/gui_utils/tasks/main.yml returns without any errors and, if I remove the - name and import_tasks lines from ansible/playbook.yml, ansible-lint ansible/playbook.yml also returns no errors. At this point, I think my error is in the last two lines of ansible/playbook.yml but I do not know what is wrong, specifically, or how to fix it.


Solution

  • Q: "gui_utils/tasks/main.yml:4 (couldn't resolve module/action 'tasks'."

    A: Remove the keyword tasks from ansible/gui_utils/tasks/main.yml. The task import_tasks is already in the tasks section of the playbook

    ---
    - name: "Load gui_utils_list variable"
      include_vars: "{{ role_path }}/vars/main.yml"
    
    - name: "Install GUI utility packages"
      ansible.builtin.apt:
        name: "{{ gui_utils_list }}"
        state: present
    

    import_role instead of import_tasks

    The code will be simpler with import_role instead of with import_tasks. Running tasks/main.yml is the default

          - name: "Import role gui_utils."
            import_role:
              name: gui_utils
    

    This way you can also omit the task "Load gui_utils_list variable" from ansible/gui_utils/tasks/main.yml. The vars/main.yml is read by default in the role too. See Understanding variable precedence

    ---
    - name: "Install GUI utility packages"
      ansible.builtin.apt:
        name: "{{ gui_utils_list }}"
        state: present
    

    The only difference is that import_role will make available other role's artifacts (defaults, handlers, ...) to the play. But, this is what the roles are for. See Notes.