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: "git@myrepo.com"
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: "git@myrepo.com"
path: "/path/on/local_system"
branch: "branch_to_checkout"
$ cat roles/role_B/defaults/main.yml
repos_B:
name_of_repo_B:
url: "git@myrepo.com"
path: "/path/on/local_system"
branch: "branch_to_checkout"
$ cat roles/role_C/defaults/main.yml
repos_C:
name_of_repo_C:
url: "git@myrepo.com"
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": "git@myrepo.com"
},
"name_of_repo_B": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "git@myrepo.com"
},
"name_of_repo_C": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "git@myrepo.com"
}
}
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": "git@myrepo.com"
}
"name_of_repo_C": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "git@myrepo.com"
}
}
}
TASK [role_B : debug] **********************************************************************************
ok: [localhost] => {
"repos": {
"name_of_repo_A": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "git@myrepo.com"
},
"name_of_repo_B": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "git@myrepo.com"
}
}
}
TASK [role_C : debug] **********************************************************************************
ok: [localhost] => {
"repos": {
"name_of_repo_B": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "git@myrepo.com"
},
"name_of_repo_C": {
"branch": "branch_to_checkout",
"path": "/path/on/local_system",
"url": "git@myrepo.com"
}
}
}
ansible_play_role_names
or ansible_role_names
. See Special Variables.