vars
を使用して複数の変数をタスクに渡したい。現在、以下のようにやっています
vars:
var1_name: "var1_value"
var2_name: "var2_value"
変数の数が増える可能性があるため、vars
を使用して変数の辞書をタスクに渡すことをお勧めします。私は以下のような変数の辞書を作成しました
- name: set fact
hosts: localhost
tasks:
- set_fact:
variables: "{{ variables|default({}) | combine( {item.variable: item.value} ) }}"
with_items:
- variable: var1_name
value: "var1_value"
- variable: var2_name
value: "var2_name"
辞書は次のようになります。
"variables": {
"var1_name": "var1_value",
"var2_name": "var2_value",
}
ここで、このディクショナリの変数を他のホストで実行されているロールで使用できるようにします。
しかし、以下のように辞書をvars
に渡そうとしたとき
vars: "{{ variables }}"
Ansibleはエラーをスローします:
ERROR! Vars in a Play must be specified as a dictionary, or a list of dictionaries
vars
で辞書変数を渡す方法は?
Ansibleのソースコードを検索したところ、Ansibleの開発者でさえ問題になっているようです。一部の統合テストでは、これと同じエラーのためにコメントアウトされる特定のテストがあります。
ansible/tests/Integration/targets/include_import/role/test_include_role.yml
## FIXME Currently failing with
## ERROR! Vars in a IncludeRole must be specified as a dictionary, or a list of dictionaries
# - name: Pass all variables in a variable to role
# include_role:
# name: role1
# tasks_from: vartest.yml
# vars: "{{ role_vars }}"
また、これが変数を含めるために呼び出されている基になる関数であることがわかりました。
def _load_vars(self, attr, ds):
'''
Vars in a play can be specified either as a dictionary directly, or
as a list of dictionaries. If the later, this method will turn the
list into a single dictionary.
'''
def _validate_variable_keys(ds):
for key in ds:
if not isidentifier(key):
raise TypeError("'%s' is not a valid variable name" % key)
try:
if isinstance(ds, dict):
_validate_variable_keys(ds)
return combine_vars(self.vars, ds)
Elif isinstance(ds, list):
all_vars = self.vars
for item in ds:
if not isinstance(item, dict):
raise ValueError
_validate_variable_keys(item)
all_vars = combine_vars(all_vars, item)
return all_vars
Elif ds is None:
return {}
else:
raise ValueError
except ValueError as e:
raise AnsibleParserError("Vars in a %s must be specified as a dictionary, or a list of dictionaries" % self.__class__.__name__,
obj=ds, orig_exc=e)
except TypeError as e:
raise AnsibleParserError("Invalid variable name in vars specified for %s: %s" % (self.__class__.__name__, e), obj=ds, orig_exc=e)
「{{}}」は実際には単なるYAML文字列であるため、Ansibleはそれをdictとして認識しません。つまり、vars属性はJinja2エンジンを通過せず、実際の内容について評価されます。 。
YAMLオブジェクトを渡す唯一の方法はアンカーを使用することですが、これにはオブジェクトを動的にではなく全体として定義する必要があります。
var: &_anchored_var
attr1: "test"
att2: "bar"
vars:
<<: *_anchored_var
次のような変数を管理する構造化された方法を使用することをお勧めします。
ファイルmyvars1.yml
myvars:
var1_name: "var1_value"
var2_name: "var2_value"
次に、次のような変数を読み取ります
- name: Read all variables
block:
- name: Get All Variables
stat:
path: "{{item}}"
with_fileglob:
- "/myansiblehome/vars/common/myvars1.yml"
- "/myansiblehome/vars/common/myvars2.yml"
register: _variables_stat
- name: Include Variables when found
include_vars : "{{item.stat.path}}"
when : item.stat.exists
with_items : "{{_variables_stat.results}}"
no_log : true
delegate_to: localhost
become: false
その後、次のように使用します。
- name: My Running Module
mymodule:
myaction1: "{{ myvars.var1_name }}"
myaction2: "{{ myvars.var2_name }}"
それが役に立てば幸い