From fa3937a82a0cc03779649918b00612775d26c6df Mon Sep 17 00:00:00 2001 From: Johnathan Kupferer Date: Fri, 17 Jan 2025 19:59:50 -0500 Subject: [PATCH 1/2] Add role host_workloads for minimal config --- ansible/cloud_providers/multi_destroy_env.yml | 16 ++++++ ansible/configs/minimal/default_vars.yml | 51 +++++++++++++++++++ ansible/configs/minimal/destroy_env.yml | 23 +++++++-- ansible/configs/minimal/infra.yml | 21 +++++++- ansible/configs/minimal/noop.yml | 4 ++ ansible/configs/minimal/post_infra.yml | 21 +++++++- ansible/configs/minimal/post_software.yml | 21 +++++++- ansible/configs/minimal/pre_infra.yml | 21 +++++++- ansible/configs/minimal/pre_software.yml | 21 +++++++- ansible/configs/minimal/software.yml | 21 +++++++- ansible/configs/minimal/start.yml | 28 +++++++--- ansible/configs/minimal/stop.yml | 28 +++++++--- ansible/roles/host_workloads/README.adoc | 46 +++++++++++++++++ .../roles/host_workloads/defaults/main.yml | 5 ++ ansible/roles/host_workloads/tasks/main.yml | 31 +++++++++++ .../host_workloads/tasks/run_workload.yml | 13 +++++ 16 files changed, 344 insertions(+), 27 deletions(-) create mode 100644 ansible/cloud_providers/multi_destroy_env.yml create mode 100644 ansible/configs/minimal/noop.yml create mode 100644 ansible/roles/host_workloads/README.adoc create mode 100644 ansible/roles/host_workloads/defaults/main.yml create mode 100644 ansible/roles/host_workloads/tasks/main.yml create mode 100644 ansible/roles/host_workloads/tasks/run_workload.yml diff --git a/ansible/cloud_providers/multi_destroy_env.yml b/ansible/cloud_providers/multi_destroy_env.yml new file mode 100644 index 00000000000..97ef7011cc7 --- /dev/null +++ b/ansible/cloud_providers/multi_destroy_env.yml @@ -0,0 +1,16 @@ +--- +- name: Step 001.1 Destroy Infrastructure + hosts: localhost + connection: local + gather_facts: false + become: false + tags: + - step001 + - step001.1 + - deploy_infrastructure + + tasks: + + - name: Destroy multi cloud_provider debug task + ansible.builtin.debug: + msg: Destroy multi cloud_provider debug task diff --git a/ansible/configs/minimal/default_vars.yml b/ansible/configs/minimal/default_vars.yml index a2c76b5f015..682070d4b09 100644 --- a/ansible/configs/minimal/default_vars.yml +++ b/ansible/configs/minimal/default_vars.yml @@ -9,6 +9,57 @@ output_dir: "/tmp/output_dir/{{ guid }}" # Writable working scratch directo project_tag: "{{ env_type }}-{{ guid }}" # This var is used to identify stack (cloudformation, azure resourcegroup, ...) agnosticd_inventory_exporter_enable: true # Dump inventory in output_dir +# Workloads should be specified in the appropriate var targeting the stage. +# The format for each is a list with role name, hosts, and optional vars +# +# Workload roles use the ACTION var do determine whether they should +# perform provision, start, stop, or destroy. +# +# If vars are included then those will be set with set_fact before the role +# is called. This allows the same role to be called repeatedly on the same +# or different hosts with different variables. +# +# Example: +# +# infra_workloads: +# # Provsision a VM, add host to inventory +# - name: mitzi_vm +# hosts: localhost +# +# # Configure software on bastion VM +# software_workloads: +# - name: mitzi_software +# hosts: bastion +# +# # Cleanup is just destroy the bastion +# destroy_workloads: +# - name: mitzi_vm +# hosts: localhost +# +# # Start the VM, then check software state +# start_workloads: +# - name: mitzi_vm +# hosts: localhost +# - name: mitzi_software +# hosts: bastion +# +# # Shutdown the VM +# stop_workloads: +# - name: mitzi_vm +# hosts: localhost +# - name: mitzi_software +# hosts: bastion +# +pre_infra_workloads: [] +infra_workloads: [] +post_infra_workloads: [] +pre_software_workloads: [] +software_workloads: [] +post_software_workloads: [] +destroy_workloads: [] +start_workloads: [] +stop_workloads: [] + email: "{{ env_type }}@opentlc.com" guid: "{{ env_type }}-01" uuid: "{{ guid }}" diff --git a/ansible/configs/minimal/destroy_env.yml b/ansible/configs/minimal/destroy_env.yml index 058d8118110..bc13a189220 100644 --- a/ansible/configs/minimal/destroy_env.yml +++ b/ansible/configs/minimal/destroy_env.yml @@ -1,10 +1,27 @@ --- - - name: Import destroy workloads - ansible.builtin.import_playbook: workloads.yml + ansible.builtin.import_playbook: >- + {{ 'workloads.yml' if destroy_workloads is mapping else 'noop.yml' }} + when: destroy_workloads is defined vars: _workload_title_: "Pre Infra" - _workloads_: "{{ destroy_workloads | default([]) }}" + _workloads_: "{{ destroy_workloads }}" + +- name: Run host_workloads for destroy + hosts: all:localhost + gather_facts: false + tasks: + - name: Include host_workloads for destroy + when: + - destroy_workloads is iterable + - destroy_workloads is not mapping + - destroy_workloads is not string + vars: + agnosticd_stage: destroy + host_workloads: "{{ destroy_workloads }}" + ansible.builtin.include_role: + name: host_workloads - name: Import default cloud_provider destroy playbook ansible.builtin.import_playbook: ../../cloud_providers/{{ cloud_provider }}_destroy_env.yml +... diff --git a/ansible/configs/minimal/infra.yml b/ansible/configs/minimal/infra.yml index 9238668d745..7673f0f878a 100644 --- a/ansible/configs/minimal/infra.yml +++ b/ansible/configs/minimal/infra.yml @@ -20,9 +20,26 @@ # ---------------------------------------------------------------------- - name: Import infra workloads - ansible.builtin.import_playbook: workloads.yml + ansible.builtin.import_playbook: >- + {{ 'workloads.yml' if infra_workloads is mapping else 'noop.yml' }} vars: _workload_title_: "Infra" - _workloads_: "{{ infra_workloads | default([]) }}" + _workloads_: "{{ infra_workloads }}" +- name: Run host_workloads for infra_workloads + hosts: all:localhost + gather_facts: false + tasks: + - debug: + msg: "{{ infra_workloads is mapping }}" + - name: Include host_workloads for infra + when: + - infra_workloads is iterable + - infra_workloads is not mapping + - infra_workloads is not string + vars: + agnosticd_stage: infra + host_workloads: "{{ infra_workloads }}" + ansible.builtin.include_role: + name: host_workloads ... diff --git a/ansible/configs/minimal/noop.yml b/ansible/configs/minimal/noop.yml new file mode 100644 index 00000000000..b5224c748cb --- /dev/null +++ b/ansible/configs/minimal/noop.yml @@ -0,0 +1,4 @@ +--- +# Stand-in to implement no-op for workloads import_playbook compatibility +- name: Workloads not configured as mapping for {{ _workload_title_ }} + hosts: localhost diff --git a/ansible/configs/minimal/post_infra.yml b/ansible/configs/minimal/post_infra.yml index 6b1b50ec6c7..aa0bc112d87 100644 --- a/ansible/configs/minimal/post_infra.yml +++ b/ansible/configs/minimal/post_infra.yml @@ -19,7 +19,24 @@ # ---------------------------------------------------------------------- - name: Import post_infra workloads - ansible.builtin.import_playbook: workloads.yml + ansible.builtin.import_playbook: >- + {{ 'workloads.yml' if post_infra_workloads is mapping else 'noop.yml' }} vars: _workload_title_: "Post Infra" - _workloads_: "{{ post_infra_workloads | default([]) }}" + _workloads_: "{{ post_infra_workloads }}" + +- name: Run host_workloads for post_infra_workloads + hosts: all:localhost + gather_facts: false + tasks: + - name: Include host_workloads for post_infra + when: + - post_infra_workloads is iterable + - post_infra_workloads is not mapping + - post_infra_workloads is not string + vars: + agnosticd_stage: post_infra + host_workloads: "{{ post_infra_workloads }}" + ansible.builtin.include_role: + name: host_workloads +... diff --git a/ansible/configs/minimal/post_software.yml b/ansible/configs/minimal/post_software.yml index 6d5d4b34d75..88a3951396e 100644 --- a/ansible/configs/minimal/post_software.yml +++ b/ansible/configs/minimal/post_software.yml @@ -15,7 +15,24 @@ # ---------------------------------------------------------------------- - name: Import Post-software workloads - ansible.builtin.import_playbook: workloads.yml + ansible.builtin.import_playbook: >- + {{ 'workloads.yml' if post_software_workloads is mapping else 'noop.yml' }} vars: _workload_title_: "Post Software" - _workloads_: "{{ post_software_workloads | default([]) }}" + _workloads_: "{{ post_software_workloads }}" + +- name: Run host_workloads for post_software_workloads + hosts: all:localhost + gather_facts: false + tasks: + - name: Include host_workloads for post_software + when: + - post_software_workloads is iterable + - post_software_workloads is not mapping + - post_software_workloads is not string + vars: + agnosticd_stage: post_software + host_workloads: "{{ post_software_workloads }}" + ansible.builtin.include_role: + name: host_workloads +... diff --git a/ansible/configs/minimal/pre_infra.yml b/ansible/configs/minimal/pre_infra.yml index b7a600818aa..ea27b63ce9a 100644 --- a/ansible/configs/minimal/pre_infra.yml +++ b/ansible/configs/minimal/pre_infra.yml @@ -20,7 +20,24 @@ # ---------------------------------------------------------------------- - name: Import pre_infra workloads - ansible.builtin.import_playbook: workloads.yml + ansible.builtin.import_playbook: >- + {{ 'workloads.yml' if pre_infra_workloads is mapping else 'noop.yml' }} vars: _workload_title_: "Pre Infra" - _workloads_: "{{ pre_infra_workloads | default([]) }}" + _workloads_: "{{ pre_infra_workloads }}" + +- name: Run host_workloads for pre_infra_workloads + hosts: all:localhost + gather_facts: false + tasks: + - name: Include host_workloads for pre_infra + when: + - infra_workloads is iterable + - pre_infra_workloads is not mapping + - pre_infra_workloads is not string + vars: + agnosticd_stage: pre_infra + host_workloads: "{{ pre_infra_workloads }}" + ansible.builtin.include_role: + name: host_workloads +... diff --git a/ansible/configs/minimal/pre_software.yml b/ansible/configs/minimal/pre_software.yml index e47f97f01c8..441fc1d48df 100644 --- a/ansible/configs/minimal/pre_software.yml +++ b/ansible/configs/minimal/pre_software.yml @@ -18,7 +18,24 @@ # ---------------------------------------------------------------------- - name: Import Pre-software workloads - ansible.builtin.import_playbook: workloads.yml + ansible.builtin.import_playbook: >- + {{ 'workloads.yml' if pre_software_workloads is mapping else 'noop.yml' }} vars: _workload_title_: "Pre Software" - _workloads_: "{{ pre_software_workloads | default([]) }}" + _workloads_: "{{ pre_software_workloads }}" + +- name: Run host_workloads for pre_software_workloads + hosts: all:localhost + gather_facts: false + tasks: + - name: Include host_workloads for pre_software + when: + - software_workloads is iterable + - pre_software_workloads is not mapping + - pre_software_workloads is not string + vars: + agnosticd_stage: pre_software + host_workloads: "{{ pre_software_workloads }}" + ansible.builtin.include_role: + name: host_workloads +... diff --git a/ansible/configs/minimal/software.yml b/ansible/configs/minimal/software.yml index 1c2847cc945..821812bb5e2 100644 --- a/ansible/configs/minimal/software.yml +++ b/ansible/configs/minimal/software.yml @@ -20,7 +20,24 @@ # ---------------------------------------------------------------------- - name: Import Software workloads - ansible.builtin.import_playbook: workloads.yml + ansible.builtin.import_playbook: >- + {{ 'workloads.yml' if software_workloads is mapping else 'noop.yml' }} vars: _workload_title_: "Software" - _workloads_: "{{ software_workloads | default([]) }}" + _workloads_: "{{ software_workloads }}" + +- name: Run host_workloads for software_workloads + hosts: all:localhost + gather_facts: false + tasks: + - name: Include host_workloads for software + when: + - software_workloads is iterable + - software_workloads is not mapping + - software_workloads is not string + vars: + agnosticd_stage: software + host_workloads: "{{ software_workloads }}" + ansible.builtin.include_role: + name: host_workloads +... diff --git a/ansible/configs/minimal/start.yml b/ansible/configs/minimal/start.yml index d7c4bac963b..0efd3fd8abb 100644 --- a/ansible/configs/minimal/start.yml +++ b/ansible/configs/minimal/start.yml @@ -4,17 +4,33 @@ gather_facts: false become: false tasks: - - - name: Start Playbook - ansible.builtin.debug: - msg: "Start Playbook Running" + - name: Start Playbook + ansible.builtin.debug: + msg: "Start Playbook Running" # ---------------------------------------------------------------------- # Start Workloads as role # ---------------------------------------------------------------------- - name: Import start workloads - ansible.builtin.import_playbook: workloads.yml + ansible.builtin.import_playbook: >- + {{ 'workloads.yml' if start_workloads is mapping else 'noop.yml' }} vars: _workload_title_: "Start" - _workloads_: "{{ start_workloads | default([]) }}" + _workloads_: "{{ start_workloads }}" + +- name: Run host_workloads for start + hosts: all:localhost + gather_facts: false + tasks: + - name: Include host_workloads for start + when: + - start_workloads is iterable + - start_workloads is not mapping + - start_workloads is not string + vars: + agnosticd_stage: start + host_workloads: "{{ start_workloads }}" + ansible.builtin.include_role: + name: host_workloads +... diff --git a/ansible/configs/minimal/stop.yml b/ansible/configs/minimal/stop.yml index 515ff7dc57a..549e2dc8630 100644 --- a/ansible/configs/minimal/stop.yml +++ b/ansible/configs/minimal/stop.yml @@ -4,17 +4,33 @@ gather_facts: false become: false tasks: - - - name: Stop Playbook - ansible.builtin.debug: - msg: "Stop Playbook Running" + - name: Stop Playbook + ansible.builtin.debug: + msg: "Stop Playbook Running" # ---------------------------------------------------------------------- # Stop Workloads as role # ---------------------------------------------------------------------- - name: Import stop workloads - ansible.builtin.import_playbook: workloads.yml + ansible.builtin.import_playbook: >- + {{ 'workloads.yml' if stop_workloads is mapping else 'noop.yml' }} vars: _workload_title_: "Stop" - _workloads_: "{{ stop_workloads | default([]) }}" + _workloads_: "{{ stop_workloads }}" + +- name: Run host_workloads for stop + hosts: all:localhost + gather_facts: false + tasks: + - name: Include host_workloads for stop + when: + - stop_workloads is iterable + - stop_workloads is not mapping + - stop_workloads is not string + vars: + agnosticd_stage: stop + host_workloads: "{{ stop_workloads }}" + ansible.builtin.include_role: + name: host_workloads +... diff --git a/ansible/roles/host_workloads/README.adoc b/ansible/roles/host_workloads/README.adoc new file mode 100644 index 00000000000..08b1af5b304 --- /dev/null +++ b/ansible/roles/host_workloads/README.adoc @@ -0,0 +1,46 @@ +:role: host_workloads +:author1: Johnathan Kupferer +:team: Red Hat Demo Platform + + +Role: {role} +============ + +The role {role} runs workloads roles on hosts using hosts selector. + +Variables +------------ + +* This role requires only `host_workloads` variable to be set. + +* The reference implementation of calling this role is found in the minimal config. + +Example: + +---- +- name: Run host_workloads for infra_workloads + hosts: all:localhost + gather_facts: false + tasks: + - debug: + msg: "{{ infra_workloads is mapping }}" + - name: Include host_workloads for infra + when: + - infra_workloads is iterable + - infra_workloads is not mapping + - infra_workloads is not string + vars: + agnosticd_stage: infra + host_workloads: "{{ infra_workloads }}" + include_role: + name: host_workloads +---- + +Author Information +------------------ + +* Author/owner: +** {author1} + +* Team: +** {team} diff --git a/ansible/roles/host_workloads/defaults/main.yml b/ansible/roles/host_workloads/defaults/main.yml new file mode 100644 index 00000000000..17f600aa0b5 --- /dev/null +++ b/ansible/roles/host_workloads/defaults/main.yml @@ -0,0 +1,5 @@ +--- +# List of dictionaries describing what roles to run on which hosts. +# Each entry must have `name`, should have `hosts`, and may also set `vars`. +host_workloads: [] +... diff --git a/ansible/roles/host_workloads/tasks/main.yml b/ansible/roles/host_workloads/tasks/main.yml new file mode 100644 index 00000000000..2f91db421ba --- /dev/null +++ b/ansible/roles/host_workloads/tasks/main.yml @@ -0,0 +1,31 @@ +--- +- name: Check workloads set hosts and names + loop: "{{ host_workloads }}" + loop_control: + loop_var: __workload + label: "{{ __workload.name }}" + ansible.builtin.assert: + that: + - __workload is defined + - __workload is mapping + - __workload.name is defined + - __workload.name is string + - __workload.hosts is defined + - __workload.hosts is string + +- name: Run workloads + loop: "{{ host_workloads }}" + loop_control: + loop_var: __workload + label: "{{ __workload.name }}" + vars: + # Default hosts to localhost in infra and all during software + __default_hosts: >- + {{ + 'localhost' if agnosticd_stage.endswith('infra') else 'all' + }} + when: + - inventory_hostname in lookup('inventory_hostnames', __workload.hosts | default(__default_hosts)) + ansible.builtin.include_tasks: + file: run_workload.yml +... diff --git a/ansible/roles/host_workloads/tasks/run_workload.yml b/ansible/roles/host_workloads/tasks/run_workload.yml new file mode 100644 index 00000000000..0ce5f7e7c37 --- /dev/null +++ b/ansible/roles/host_workloads/tasks/run_workload.yml @@ -0,0 +1,13 @@ +- name: Set vars for host workload {{ __workload.name }} + when: __workload.vars is defined + loop: >- + {{ __workload.vars | dict2items }} + loop_control: + loop_var: __var + label: "{{ __var.key }}" + ansible.builtin.set_fact: + "{{ __var.key }}": "{{ __var.value }}" + +- name: Run workload {{ __workload.name }} + ansible.builtin.include_role: + name: "{{ __workload.name }}" From 67892b3d0805f7d6e174dd57b1c0bab42a730576 Mon Sep 17 00:00:00 2001 From: Johnathan Kupferer Date: Sat, 18 Jan 2025 09:49:47 -0500 Subject: [PATCH 2/2] Fix for standard YAML indent --- ansible/configs/minimal/infra.yml | 24 +++++++++++------------ ansible/configs/minimal/post_infra.yml | 20 +++++++++---------- ansible/configs/minimal/post_software.yml | 20 +++++++++---------- ansible/configs/minimal/pre_infra.yml | 20 +++++++++---------- ansible/configs/minimal/pre_software.yml | 20 +++++++++---------- ansible/configs/minimal/software.yml | 20 +++++++++---------- 6 files changed, 62 insertions(+), 62 deletions(-) diff --git a/ansible/configs/minimal/infra.yml b/ansible/configs/minimal/infra.yml index 7673f0f878a..8cd0612cfc6 100644 --- a/ansible/configs/minimal/infra.yml +++ b/ansible/configs/minimal/infra.yml @@ -30,16 +30,16 @@ hosts: all:localhost gather_facts: false tasks: - - debug: - msg: "{{ infra_workloads is mapping }}" - - name: Include host_workloads for infra - when: - - infra_workloads is iterable - - infra_workloads is not mapping - - infra_workloads is not string - vars: - agnosticd_stage: infra - host_workloads: "{{ infra_workloads }}" - ansible.builtin.include_role: - name: host_workloads + - debug: + msg: "{{ infra_workloads is mapping }}" + - name: Include host_workloads for infra + when: + - infra_workloads is iterable + - infra_workloads is not mapping + - infra_workloads is not string + vars: + agnosticd_stage: infra + host_workloads: "{{ infra_workloads }}" + ansible.builtin.include_role: + name: host_workloads ... diff --git a/ansible/configs/minimal/post_infra.yml b/ansible/configs/minimal/post_infra.yml index aa0bc112d87..13d7aee6bf2 100644 --- a/ansible/configs/minimal/post_infra.yml +++ b/ansible/configs/minimal/post_infra.yml @@ -29,14 +29,14 @@ hosts: all:localhost gather_facts: false tasks: - - name: Include host_workloads for post_infra - when: - - post_infra_workloads is iterable - - post_infra_workloads is not mapping - - post_infra_workloads is not string - vars: - agnosticd_stage: post_infra - host_workloads: "{{ post_infra_workloads }}" - ansible.builtin.include_role: - name: host_workloads + - name: Include host_workloads for post_infra + when: + - post_infra_workloads is iterable + - post_infra_workloads is not mapping + - post_infra_workloads is not string + vars: + agnosticd_stage: post_infra + host_workloads: "{{ post_infra_workloads }}" + ansible.builtin.include_role: + name: host_workloads ... diff --git a/ansible/configs/minimal/post_software.yml b/ansible/configs/minimal/post_software.yml index 88a3951396e..0dab84bda64 100644 --- a/ansible/configs/minimal/post_software.yml +++ b/ansible/configs/minimal/post_software.yml @@ -25,14 +25,14 @@ hosts: all:localhost gather_facts: false tasks: - - name: Include host_workloads for post_software - when: - - post_software_workloads is iterable - - post_software_workloads is not mapping - - post_software_workloads is not string - vars: - agnosticd_stage: post_software - host_workloads: "{{ post_software_workloads }}" - ansible.builtin.include_role: - name: host_workloads + - name: Include host_workloads for post_software + when: + - post_software_workloads is iterable + - post_software_workloads is not mapping + - post_software_workloads is not string + vars: + agnosticd_stage: post_software + host_workloads: "{{ post_software_workloads }}" + ansible.builtin.include_role: + name: host_workloads ... diff --git a/ansible/configs/minimal/pre_infra.yml b/ansible/configs/minimal/pre_infra.yml index ea27b63ce9a..1c8053dbc44 100644 --- a/ansible/configs/minimal/pre_infra.yml +++ b/ansible/configs/minimal/pre_infra.yml @@ -30,14 +30,14 @@ hosts: all:localhost gather_facts: false tasks: - - name: Include host_workloads for pre_infra - when: - - infra_workloads is iterable - - pre_infra_workloads is not mapping - - pre_infra_workloads is not string - vars: - agnosticd_stage: pre_infra - host_workloads: "{{ pre_infra_workloads }}" - ansible.builtin.include_role: - name: host_workloads + - name: Include host_workloads for pre_infra + when: + - infra_workloads is iterable + - pre_infra_workloads is not mapping + - pre_infra_workloads is not string + vars: + agnosticd_stage: pre_infra + host_workloads: "{{ pre_infra_workloads }}" + ansible.builtin.include_role: + name: host_workloads ... diff --git a/ansible/configs/minimal/pre_software.yml b/ansible/configs/minimal/pre_software.yml index 441fc1d48df..b55541a7722 100644 --- a/ansible/configs/minimal/pre_software.yml +++ b/ansible/configs/minimal/pre_software.yml @@ -28,14 +28,14 @@ hosts: all:localhost gather_facts: false tasks: - - name: Include host_workloads for pre_software - when: - - software_workloads is iterable - - pre_software_workloads is not mapping - - pre_software_workloads is not string - vars: - agnosticd_stage: pre_software - host_workloads: "{{ pre_software_workloads }}" - ansible.builtin.include_role: - name: host_workloads + - name: Include host_workloads for pre_software + when: + - software_workloads is iterable + - pre_software_workloads is not mapping + - pre_software_workloads is not string + vars: + agnosticd_stage: pre_software + host_workloads: "{{ pre_software_workloads }}" + ansible.builtin.include_role: + name: host_workloads ... diff --git a/ansible/configs/minimal/software.yml b/ansible/configs/minimal/software.yml index 821812bb5e2..2be593611be 100644 --- a/ansible/configs/minimal/software.yml +++ b/ansible/configs/minimal/software.yml @@ -30,14 +30,14 @@ hosts: all:localhost gather_facts: false tasks: - - name: Include host_workloads for software - when: - - software_workloads is iterable - - software_workloads is not mapping - - software_workloads is not string - vars: - agnosticd_stage: software - host_workloads: "{{ software_workloads }}" - ansible.builtin.include_role: - name: host_workloads + - name: Include host_workloads for software + when: + - software_workloads is iterable + - software_workloads is not mapping + - software_workloads is not string + vars: + agnosticd_stage: software + host_workloads: "{{ software_workloads }}" + ansible.builtin.include_role: + name: host_workloads ...