Let's say I have an ansible role which being imported in any place will clone repositories to specified path, called "git_role", for example.
It's mechanism, clone repositories for projects doing by one role when it's inlcuded to playbook.
And it's doing by assigning dict like
repos:
name_of_repo:
url: "[email protected]"
path: "/path/on/local_system"
branch: "branch_to_checkout"
And this dict on "git_role" which doing clone repo handled like this:
- name: Clone repositories
git:
repo: "{{ item['value']['url'] }}"
dest: "{{ item['value']['path'] }}"
accept_hostkey: yes
loop: "{{ repos | dict2items }}"
I want that "repos" dict can be easy extended by any other roles. For example role "A" define dict "repos" with repo needed for role "A", and after I imported role "git_role" along with role "A" in playbook. "git_role" will look into extended dict "repos" and going clone all described repos.
Role "B" for example can described another repo in dict "repos" and "git_role" in that case clone that repos needed for role "B" and so on.
Ansible dy default has :
hash_behaviour=replace
And I don't want change it, as developers don't suggest it. reddit conversation
I look into "combine" but it also override dict...
Who can suggest right painless way to extend one particular dict by any sources?
Not even dict must. There can be any data source which "git_role" can consume and clone all specified repos.
(ansible 2.7.9)
It is possible to combine dictionaries from different roles. Let's have roles role_A, role_B, and role_C with default variables.
$ cat roles/role_A/defaults/main.yml
repos_A:
name_of_repo_A:
url: "[email protected]"
path: "/path/on/local_system"
branch: "branch_to_checkout"
$ cat roles/role_B/defaults/main.yml
repos_B:
name_of_repo_B:
url: "[email protected]"
path: "/path/on/local_system"
branch: "branch_to_checkout"
$ cat roles/role_C/defaults/main.yml
repos_C:
name_of_repo_C:
url: "[email protected]"
path: "/path/on/local_system"
branch: "branch_to_checkout"
If the names of the dictionaries follow the names of the roles repos_<SECOND-PART-OF-ROLE-NAME>
then the play below
- hosts: localhost
roles:
- role_A
- role_B
- role_C
tasks:
- set_fact:
repos: "{{ repos|default({})|
combine(lookup('vars',
'repos_' ~ item.split('_').1,
default={}))
}}"
loop: "{{ role_names }}"
- debug:
var: repos
gives the combined directory
"repos": {
"name_of_repo_A": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "[email protected]"
},
"name_of_repo_B": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "[email protected]"
},
"name_of_repo_C": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "[email protected]"
}
}
Control repos inside roles
It is possible to control the repos inside the roles. Let's put the tasks below into the roles and introduce the variable repos_source
$ cat roles/role_A/tasks/main.yml
- set_fact:
repos: {}
- set_fact:
repos: "{{ repos|
combine(lookup('vars',
'repos_' ~ item.split('_').1,
default={}))
}}"
loop: "{{ repos_source }}"
- debug:
var: repos
The tasks below
- import_role:
name: role_A
vars:
repos_source:
- role_A
- role_C
- import_role:
name: role_B
vars:
repos_source:
- role_A
- role_B
- import_role:
name: role_C
vars:
repos_source:
- role_B
- role_C
give
TASK [role_A : debug] **********************************************************************************
ok: [localhost] => {
"repos": {
"name_of_repo_A": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "[email protected]"
}
"name_of_repo_C": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "[email protected]"
}
}
}
TASK [role_B : debug] **********************************************************************************
ok: [localhost] => {
"repos": {
"name_of_repo_A": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "[email protected]"
},
"name_of_repo_B": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "[email protected]"
}
}
}
TASK [role_C : debug] **********************************************************************************
ok: [localhost] => {
"repos": {
"name_of_repo_B": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "[email protected]"
},
"name_of_repo_C": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "[email protected]"
}
}
}
ansible_play_role_names
or ansible_role_names
. See Special Variables.