我有一个ansible playbook,我想在一台机器上注册的变量可以在另一台机器上注册。
在我的情况下,我想在id;language;title;page_title;menu_title;meta_description;slug;path;has_url_overwrite;redirect;creation_date;published;publisher_is_draft;publisher_state;page_id;publisher_public_id$
217;en;Migration-test;"";"";"";migration-test;migration-test;f;"";2015-11-24 13:01:52.184969+00;t;t;0;99;218$
上运行一个命令,在这种情况下是localhost
,所以我可以记下当前的git分支和sha1,并注册这个输出,所以我可以在以后的git rev-parse --abbrev-ref HEAD
组中使用任何一台机器时在第二次播放中引用它。
但是,我不清楚如何在localhost上注册变量,所以我可以从main访问它。当我尝试在第二次播放中访问该变量时,我收到此消息:
main
这是我正在使用的剧本。有什么明显我应该做的吗?
TASK: [debug msg={{ app_git_sha1.stdout }}] ***********************************
fatal: [main] => One or more undefined variables: 'app_git_sha1' is undefined
答案 0 :(得分:82)
您遇到的问题是您尝试从另一台主机的实体/变量引用一个主机的事实/变量。您需要记住,在Ansible中,分配给主机app_git_sha1
的变量localhost
与分配给主机app_git_sha1
或任何其他主机的变量main
不同。如果要从另一个主机访问一个主机事实/变量,则需要通过hostvars
变量显式引用它。关于这个in this question还有一些讨论。
假设您有这样的剧本:
- hosts: localhost
tasks:
- command: /bin/echo "this is a test"
register: foo
- hosts: localhost
tasks:
- debug: var=foo
这会有效,因为您在两个播放中都引用了变量localhost
的主机localhosts
和foo
实例。这个剧本的输出是这样的:
PLAY [localhost] **************************************************************
GATHERING FACTS ***************************************************************
ok: [localhost]
TASK: [command /bin/echo "this is a test"] ************************************
changed: [localhost]
PLAY [localhost] **************************************************************
GATHERING FACTS ***************************************************************
ok: [localhost]
TASK: [debug var=foo] *********************************************************
ok: [localhost] => {
"var": {
"foo": {
"changed": true,
"cmd": [
"/bin/echo",
"this is a test"
],
"delta": "0:00:00.004585",
"end": "2015-11-24 20:49:27.462609",
"invocation": {
"module_args": "/bin/echo \"this is a test\"",
"module_complex_args": {},
"module_name": "command"
},
"rc": 0,
"start": "2015-11-24 20:49:27.458024",
"stderr": "",
"stdout": "this is a test",
"stdout_lines": [
"this is a test"
],
"warnings": []
}
}
}
如果您稍微修改此剧本以在一台主机上运行第一次播放而在另一台主机上播放第二次播放,您将收到您遇到的错误。解决方案是使用Ansible的内置hostvars
变量让第二个主机显式引用第一个hosts变量。所以修改第一个例子:
- hosts: localhost
tasks:
- command: /bin/echo "this is a test"
register: foo
- hosts: anotherhost
tasks:
- debug: var=foo
when: foo is defined
- debug: var=hostvars['localhost']['foo']
when: hostvars['localhost']['foo'] is defined
此剧本的输出显示第一个任务被跳过,因为foo
未由主持人anotherhost
定义。但第二个任务成功,因为它明确引用变量localhosts
的{{1}}实例:
foo
因此,简而言之,您希望修改TASK: [debug var=foo] *********************************************************
skipping: [anotherhost]
TASK: [debug var=hostvars['localhost']['foo']] **************************
ok: ['anotherhost'] => {
"var": {
"hostvars['localhost']['foo']": {
"changed": true,
"cmd": [
"/bin/echo",
"this is a test"
],
"delta": "0:00:00.005950",
"end": "2015-11-24 20:54:04.319147",
"invocation": {
"module_args": "/bin/echo \"this is a test\"",
"module_complex_args": {},
"module_name": "command"
},
"rc": 0,
"start": "2015-11-24 20:54:04.313197",
"stderr": "",
"stdout": "this is a test",
"stdout_lines": [
"this is a test"
],
"warnings": []
}
}
}
剧本中的变量引用,以此方式引用main
变量:
localhost
答案 1 :(得分:21)
例如,将K8S令牌和哈希从主服务器传递给工作者。
- name: "Cluster token"
shell: kubeadm token list | cut -d ' ' -f1 | sed -n '2p'
register: K8S_TOKEN
- name: "CA Hash"
shell: openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
register: K8S_MASTER_CA_HASH
- name: "Add K8S Token and Hash to dummy host"
add_host:
name: "K8S_TOKEN_HOLDER"
token: "{{ K8S_TOKEN.stdout }}"
hash: "{{ K8S_MASTER_CA_HASH.stdout }}"
- name:
debug:
msg: "[Master] K8S_TOKEN_HOLDER K8S token is {{ hostvars['K8S_TOKEN_HOLDER']['token'] }}"
- name:
debug:
msg: "[Master] K8S_TOKEN_HOLDER K8S Hash is {{ hostvars['K8S_TOKEN_HOLDER']['hash'] }}"
- name:
debug:
msg: "[Worker] K8S_TOKEN_HOLDER K8S token is {{ hostvars['K8S_TOKEN_HOLDER']['token'] }}"
- name:
debug:
msg: "[Worker] K8S_TOKEN_HOLDER K8S Hash is {{ hostvars['K8S_TOKEN_HOLDER']['hash'] }}"
- name: "Kubeadmn join"
shell: >
kubeadm join --token={{ hostvars['K8S_TOKEN_HOLDER']['token'] }}
--discovery-token-ca-cert-hash sha256:{{ hostvars['K8S_TOKEN_HOLDER']['hash'] }}
{{K8S_MASTER_NODE_IP}}:{{K8S_API_SERCURE_PORT}}
答案 2 :(得分:12)
即使是同一个主持人,我也遇到了类似的问题。要记住的事情是事实而不是变量,持续不断的戏剧。以下是我解决问题的方法。
#!/usr/local/bin/ansible-playbook --inventory=./inventories/ec2.py
---
- name: "TearDown Infrastructure !!!!!!!"
hosts: localhost
gather_facts: no
vars:
aws_state: absent
vars_prompt:
- name: "aws_region"
prompt: "Enter AWS Region:"
default: 'eu-west-2'
tasks:
- name: Make vars persistant
set_fact:
aws_region: "{{aws_region}}"
aws_state: "{{aws_state}}"
- name: "TearDown Infrastructure hosts !!!!!!!"
hosts: monitoring.ec2
connection: local
gather_facts: no
tasks:
- name: set the facts per host
set_fact:
aws_region: "{{hostvars['localhost']['aws_region']}}"
aws_state: "{{hostvars['localhost']['aws_state']}}"
- debug:
msg="state {{aws_state}} region {{aws_region}} id {{ ec2_id }} "
- name: last few bits
hosts: localhost
gather_facts: no
tasks:
- debug:
msg="state {{aws_state}} region {{aws_region}} "
结果
Enter AWS Region: [eu-west-2]:
PLAY [TearDown Infrastructure !!!!!!!] ***************************************************************************************************************************************************************************************************
TASK [Make vars persistant] **************************************************************************************************************************************************************************************************************
ok: [localhost]
PLAY [TearDown Infrastructure hosts !!!!!!!] *********************************************************************************************************************************************************************************************
TASK [set the facts per host] ************************************************************************************************************************************************************************************************************
ok: [XXXXXXXXXXXXXXXXX]
TASK [debug] *****************************************************************************************************************************************************************************************************************************
ok: [XXXXXXXXXXX] => {
"changed": false,
"msg": "state absent region eu-west-2 id i-0XXXXX1 "
}
PLAY [last few bits] *********************************************************************************************************************************************************************************************************************
TASK [debug] *****************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"changed": false,
"msg": "state absent region eu-west-2 "
}
PLAY RECAP *******************************************************************************************************************************************************************************************************************************
XXXXXXXXXXXXX : ok=2 changed=0 unreachable=0 failed=0
localhost : ok=2 changed=0 unreachable=0 failed=0
答案 3 :(得分:1)
您可以使用 Ansible 已知行为,即使用 group_vars 文件夹在您的剧本中加载一些变量。这旨在与清单组一起使用,但仍然是对全局变量声明的引用。如果您将一个与组同名的文件或文件夹放入其中,您希望某些变量存在,ansible 将确保它发生!
例如,让我们创建一个名为 all
的文件并在其中放置一个时间戳变量。然后,只要您需要,您就可以调用该变量,该变量可用于在您的 playbook 中的任何 play 中声明的每个主机。
我通常这样做是为了在第一次播放时更新一次时间戳,并使用该值使用相同的时间戳写入文件和文件夹。
我正在使用 lineinfile 模块更改以 timestamp :
开头的行
检查它是否适合您的目的。
在您的 group_vars/all 上
timestamp: t26032021165953
在剧本上,在第一场比赛中: 主机:本地主机 收集事实:没有
- name: Set timestamp on group_vars
lineinfile:
path: "{{ playbook_dir }}/group_vars/all"
insertafter: EOF
regexp: '^timestamp:'
line: "timestamp: t{{ lookup('pipe','date +%d%m%Y%H%M%S') }}"
state: present
在剧本上,在第二个剧本中:
hosts: any_hosts
gather_facts: no
tasks:
- name: Check if timestamp is there
debug:
msg: "{{ timestamp }}"