如何在 ansible 中扩展 dict,而不是覆盖它?
How to extend dict in ansible, not overwriting it?
假设我有一个 ansible 角色,它被导入任何地方都会将存储库克隆到指定路径,例如 "git_role"。
这是一种机制,当它包含在剧本中时,克隆存储库用于由一个角色完成的项目。
它是通过像
这样分配字典来完成的
repos:
name_of_repo:
url: "git@myrepo.com"
path: "/path/on/local_system"
branch: "branch_to_checkout"
而关于 "git_role" 的这条指令是这样处理克隆回购的:
- name: Clone repositories
git:
repo: "{{ item['value']['url'] }}"
dest: "{{ item['value']['path'] }}"
accept_hostkey: yes
loop: "{{ repos | dict2items }}"
我希望 "repos" dict 可以由任何其他角色轻松扩展。例如,角色 "A" 定义字典 "repos" 和角色 "A" 所需的回购协议,并且在我将角色 "git_role" 与角色 "A" 一起导入剧本之后。 "git_role" 将查看扩展字典 "repos" 并克隆所有描述的存储库。
例如,角色 "B" 可以在字典 "repos" 和 "git_role" 中描述另一个仓库,在这种情况下克隆角色 "B" 所需的仓库等等。
Ansible dy 默认有:
hash_behaviour=replace
而且我不想更改它,因为开发人员不建议这样做。 reddit conversation
我调查了 "combine" 但它也覆盖了 dict...
谁能建议通过任何来源扩展一个特定命令的正确无痛方法?
连 dict 也不一定。 "git_role" 可以使用任何数据源并克隆所有指定的存储库。
(ansible 2.7.9)
可以合并来自不同角色的词典。让角色 role_A、role_B 和 role_C 具有默认变量。
$ 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"
如果字典的名字跟在角色的名字后面repos_<SECOND-PART-OF-ROLE-NAME>
那么下面的剧本
- 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
给出组合目录
"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"
}
}
控制角色内部的回购
可以控制角色内部的repos。让我们把下面的任务放到角色中,引入变量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
下面的任务
- 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
给予
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 2.8 中使用 ansible_play_role_names
或 ansible_role_names
。参见 Special Variables。
假设我有一个 ansible 角色,它被导入任何地方都会将存储库克隆到指定路径,例如 "git_role"。
这是一种机制,当它包含在剧本中时,克隆存储库用于由一个角色完成的项目。
它是通过像
这样分配字典来完成的repos:
name_of_repo:
url: "git@myrepo.com"
path: "/path/on/local_system"
branch: "branch_to_checkout"
而关于 "git_role" 的这条指令是这样处理克隆回购的:
- name: Clone repositories
git:
repo: "{{ item['value']['url'] }}"
dest: "{{ item['value']['path'] }}"
accept_hostkey: yes
loop: "{{ repos | dict2items }}"
我希望 "repos" dict 可以由任何其他角色轻松扩展。例如,角色 "A" 定义字典 "repos" 和角色 "A" 所需的回购协议,并且在我将角色 "git_role" 与角色 "A" 一起导入剧本之后。 "git_role" 将查看扩展字典 "repos" 并克隆所有描述的存储库。
例如,角色 "B" 可以在字典 "repos" 和 "git_role" 中描述另一个仓库,在这种情况下克隆角色 "B" 所需的仓库等等。
Ansible dy 默认有:
hash_behaviour=replace
而且我不想更改它,因为开发人员不建议这样做。 reddit conversation
我调查了 "combine" 但它也覆盖了 dict...
谁能建议通过任何来源扩展一个特定命令的正确无痛方法?
连 dict 也不一定。 "git_role" 可以使用任何数据源并克隆所有指定的存储库。
(ansible 2.7.9)
可以合并来自不同角色的词典。让角色 role_A、role_B 和 role_C 具有默认变量。
$ 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"
如果字典的名字跟在角色的名字后面repos_<SECOND-PART-OF-ROLE-NAME>
那么下面的剧本
- 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
给出组合目录
"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"
}
}
控制角色内部的回购
可以控制角色内部的repos。让我们把下面的任务放到角色中,引入变量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
下面的任务
- 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
给予
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 2.8 中使用
ansible_play_role_names
或 ansible_role_names
。参见 Special Variables。