00:文章简介
记录了ansible_runner的使用和遇到的问题解决办法
01:ansible_runner介绍
https://docs.ansible.com/ansible/latest/dev_guide/developing_api.html
在ansible官方网站中写到:
This API is intended for internal Ansible use. Ansible may make changes to this API at any time that could break backward compatibility with older versions of the API. Because of this, external use is not supported by Ansible. If you want to use Python API only for executing playbooks or modules, consider ansible-runner first.
If you would like to use Ansible programmatically from a language other than Python, trigger events asynchronously, or have access control and logging demands, please see the AWX project.
https://github.com/ansible/awx/
02:ansible_runner封装
在使用ansible_runner的时候需要指定inventory和playbook文件,这里对其封装一个方法,可以直接传入参数执行
run的参数的参考 https://ansible-runner.readthedocs.io/en/1.4.6/source/ansible_runner.html
events的返回值 https://ansible-runner.readthedocs.io/en/latest/ansible_runner/#module-ansible_runner.runner
import os
import uuid
import shutil
import pathlib
import ansible_runner
class RunAnsible:
"""
项目使用/opt/ansible作为运行根目录,并使用uuid生成不重复的临时运行目录,运行完成后会清除该临时运行目录
"""
def __init__(self, host):
self.host = host
self.temp_id = str(uuid.uuid4()).replace("-", '')
self.data_dir = os.path.join("/opt", "ansible", self.temp_id)
self.inventory = self.make_inventory(self.host)
self.make_dir = pathlib.Path.mkdir(pathlib.Path(self.data_dir), parents=True, exist_ok=True)
@classmethod
def make_inventory(cls, host):
data = {
"all": {
"hosts": host
}
}
return data
def clear(self):
ret = pathlib.Path(self.data_dir).exists()
if ret:
ret2 = shutil.rmtree(
self.data_dir,
# ignore_errors=True
)
return ('ok', ret2)
else:
return ('not', ret)
def run_model(self, model=None, model_args=None):
print(self.data_dir)
m = ansible_runner.run(
private_data_dir=self.data_dir,
inventory=self.inventory,
host_pattern="all",
module=model,
module_args=model_args,
quiet=True
)
print(m.rc)
stdout = m.stdout.read()
self.clear()
return stdout
def run_playbook(self, playbook=None):
playbook_path = os.path.join(self.data_dir, 'playbook.yaml')
print(playbook_path)
with open(playbook_path, 'w+') as fd:
fd.write(playbook)
m = ansible_runner.run_async(
private_data_dir=self.data_dir,
inventory=self.inventory,
playbook=playbook_path,
quiet=True
)
events = m[1].events
return events
03:ansible_runner封装使用示例
# 运行模块
result = RunAnsible(ipaddress).run_model(model, model_args)
# 运行playbook
a = RunAnsible('10.10.100.39')
my_playbook = """
---
- name: test host
hosts: all
tasks:
- name: shell id
command: "sleep 5"
"""
for event in a.run_playbook(playbook=my_playbook):
print(event['stdout']) # 循环输出playbook运行结果,输出结果和ansible命令行一致
04:ansible_runner使用中遇到的问题及解决办法
遇到的问题:
项目中使用uwsgi运行Django程序,并使用systemd来管理uwsgi,程序中使用了ansible_runner,在测试中发现下面的问题:
1. 使用uwsgi --ini xx.ini 和python manage.py runserver时,ansible_runner可以输出带颜色的stdout,但是使用systemd管理uwsgi后,输出的stdout不带颜色
2. uwsgi官方给的systemd示例,在使用过程中会出现启动失败的情况
排查原因
1. systemd启动失败是因为进程启动方式问题,使用forking即可解决
2. ansible_runner颜色问题,是因为缺少环境变量TERM=xterm-256color
# 排查方法,在两个方法中使用os.environ打印环境变量,最后排查出systemd中缺少上面的变量,导致出现无颜色
# 如果环境变量很多,使用EnvironmentDir指定文件,文件内容为key=value
# 测试时修改service后需要使用 systemd daemon-reload重新加载
附上验证没问题的配置
# uwsgi
[uwsgi]
socket=127.0.0.1:8000
chdir=/opt/SmartPXE/
module=smartpxe.wsgi:application
master=True
processes=cpu_count
pidfile=/tmp/SmartPXE-master.pid
daemonize=/var/log/SmartPXE-uwsgi.log
vacuum=True
# project.service
[Unit]
Description=SmartPXE App Server
After=network.target
[Service]
User=root
Environment=TERM=xterm-256color
WorkingDirectory=/opt/project/
ExecStart=/usr/local/bin/uwsgi --ini /opt/project/service_conf/uwsgi.ini
Restart=always
KillSignal=SIGQUIT
Type=forking
[Install]
WantedBy=multi-user.target
评论区