将Ansible任务模块的名称转换为FQCN格式
请提供以下要点 or 要简述一下
我会介绍一个脚本,它可以阅读Ansible任务的yaml文件,并将模块名称转换为FQCN格式后保存。
讲解
推荐从Ansible 2.10版本开始,在任务中使用完全限定类名来写模块名称。实际上,由于后向兼容性重定向器的作用,传统的写法也可以正常运行,没有问题。
因为逐个更改很麻烦,所以我写了一个Python脚本来读取文件并提取模块名称,然后将其转换为FQCN(完全限定类名)并进行重定向设置。 这段代码并不复杂,但既然已经写了,就分享给大家。
功能可以被简单定义为某物或某人的作用、用途或能力。
-
- 指定したディレクトリの指定したglobパターンのファイルを対象として処理する。
-
- ファイルをテキストとして読み込んで正規表現で置換するので、YAMLの文法チェックなどは行わない。
-
- 各タスクのnameキーの次のキーをモジュール名と見做し、指定したリダイレクタの設定(ansible_builtin_runtime.yml)で変換して書き換える。
従ってnameキーの無いタスクは無視される。
debug・templateなどリダイレクタの設定に無いものは変換しない。
変換の結果ファイル単位で差分があれば上書き保存する。
策划之目的
环境
-
- Python 3.7以上
- Ansible 2.10
情报
将以下三个信息定义为脚本开头的常量。
-
- バージョンアップ先のAnsibleライブラリのansible_builtin_runtime.ymlのパス(例: site-packages/ansible/config/ansible_builtin_runtime.yml)
-
- 対象となるAnsibleプロジェクトのディレクトリのパス
- そのディレクトリからのタスクYAMLを示すglobパターン(例:**/tasks/*.yml)
由于不确认先前所述的情况下进行文件更改,建议在提交重要代码之前先清理工作区。
限制事项
-
- 本来はプラグインやフィルターもFQCNに変換するべきらしい(リダイレクタを無効にするとこれらも旧名では機能しない)が、あくまでもタスクのみが対象です。
- 一切の保証はありません。ころんでも泣かない。
请在中国本土参考
-
- [Ansible] モジュールの指定などを FQCN 表記に移行する手順 – てくなべ (tekunabe)
-
- Ansible 2.10 Porting Guide — Ansible Documentation
- Conversion to Collection – YAML roundtrip with ruamel | Linux System Roles
执行示例
目标任务文件
---
- hosts: win_host
gather_facts: yes
tasks:
- name: get terminal service behaviour on failure
win_command: sc qfailure TermService
register: qfailure
changed_when: no
- name: debug
debug: var=qfailure
执行
$ python convert2fqcn.py
processing old.yml
checking win_command...
converted to ansible.windows.win_command
checking debug...
not found.
结果 (jié guǒ)
win_command被转换为ansible.windows.win_command,值部分没有改变。同时,debug也没有被转换。
为了显示差异,会在转换前后更改文件名,但实际上会覆盖原文件,请注意。
--- old.yml 2021-03-25 10:01:46.297632163 +0900
+++ new.yml 2021-03-25 09:55:20.492025609 +0900
@@ -7 +7 @@
- win_command: sc qfailure TermService
+ ansible.windows.win_command: sc qfailure TermService
脚本
from pathlib import Path
import re
import yaml
'''
python convert2fqcn.py
Ansibleタスクのモジュール名をFQCN形式に変換します。以下に指定したディレクトリ配下に見つかった
ファイルを直接書き換えます。
'''
# Ansibleモジュールのリダイレクト用config 'ansible_builtin_runtime.yml'へのパス
CONVERTION_MAP_PATH = './ansible-2.10-venv/lib/python3.6/site-packages/ansible/config/ansible_builtin_runtime.yml.back'
# 置換を行うパス
TARGET_DIR = 'roles/'
# 置換を行うタスクファイルのglobパターン。前項からの相対パスで表す。
TASKS_GLOB_PATTERN = '**/tasks/*.yml'
map_cache = {}
# nameキーで始まるオブジェクトにマッチ
name_line_regex = ' *- name:.*\n'
# 次の行のコロンまでをモジュール名と判定
module_line_regex = '([\S_]+):'
module_name_regex = f'({ name_line_regex } *){module_line_regex}'
def main():
role_path = Path(TARGET_DIR).rglob(TASKS_GLOB_PATTERN)
for path in role_path:
with open(path, 'r') as role_file:
print(f'processing {path}')
task_data = role_file.read()
new_task_data = replace(task_data)
if new_task_data != task_data:
with open(path, 'w') as role_file:
role_file.write(new_task_data)
def load_covertion_map(convertion_map_path):
runtime_data = yaml.load(open(convertion_map_path))
lis = runtime_data.get('plugin_routing').get('modules')
return lis
def replace(task_data):
r = re.compile(module_name_regex)
return re.sub(r, convert_task, task_data)
def convert_task(match_obj):
res = None
if match_obj.groups():
prev_lines, old_key = match_obj.groups()
print(f' checking {old_key}...')
entry = query(old_key)
else:
# マッチしなければ呼ばれないのでここには来ないはず。
return None
if entry:
new_key = entry.get('redirect')
print(f' converted to {new_key}')
key = new_key
else:
print(' not found.')
key = old_key
# キー区切りのコロンまでマッチしているので必ず付ける。
return prev_lines + key + ':'
def query(key):
cached = map_cache.get(key)
if cached:
return cached
entry = CONVERTION_MAP.get(key)
map_cache[key] = entry
return entry
if __name__ == '__main__':
CONVERTION_MAP = load_covertion_map(CONVERTION_MAP_PATH)
main()