Ansible版本:2.0.0.1
我现在一直在四处寻找,我找到的大多数文档都不完整或已弃用(this post is for version 1.8.4, ie)
我正在尝试通过Python API启动Ansible playbook。 Ansible的文档似乎展示了如何生成和播放任务,而不是如何加载和运行playbook yml文件。我一直在深入研究代码,试图了解如何启动它,我认为我已经取得了一些进展,但我真的打了一堵墙。这是我到目前为止所做的:
def createcluster(region, environment, cluster):
Options = namedtuple('Options', ['region','env', 'cluster'])
# initialize needed objects
variable_manager = VariableManager()
loader = DataLoader()
options = Options(region=region, env=environment, cluster=cluster)
options.listhosts = False
vault_password = getpass.getpass('Enter vault password :')
passwords = dict(vault_pass=vault_password)
#Getting hosts
hostsread = open('provisioning/inventory/hosts','r')
hosts = hostsread.read()
inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=hosts)
variable_manager.set_inventory(inventory)
#Create and load the playbook file
playbook = Playbook(loader)
playbook.load('provisioning/cluster.yml', variable_manager,loader)
#Create an executor to launch the playbook ?
executor = None
executor = PlaybookExecutor(playbook,inventory,variable_manager,loader,options,passwords)
try:
result = executor.run()
finally:
if executor is not None:
executor.cleanup()
我完全不确定执行程序部分,并且当我尝试启动代码时,我不断得到“AttributeError:'Options'对象没有属性'listhosts'”错误(奇怪的是它应该忽略它的缺席,我认为(line 60))
我应该如何加载YML文件并通过Python API启动它?我是走在好路上还是迷失了自己?为什么Ansible没有更好的记录?为什么42会成为7 * 7的答案?
答案 0 :(得分:2)
以下是Ansible 2的示例:
#!/usr/bin/python2
from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars import VariableManager
from ansible.inventory import Inventory
from ansible.playbook import Playbook
from ansible.executor.playbook_executor import PlaybookExecutor
Options = namedtuple('Options', ['connection', 'forks', 'become', 'become_method', 'become_user', 'check', 'listhosts', 'listtasks', 'listtags', 'syntax', 'module_path'])
variable_manager = VariableManager()
loader = DataLoader()
options = Options(connection='local', forks=100, become=None, become_method=None, become_user=None, check=False, listhosts=False, listtasks=False, listtags=False, syntax=False, module_path="")
passwords = dict(vault_pass='secret')
inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list='localhost')
variable_manager.set_inventory(inventory)
playbooks = ["./test.yaml"]
executor = PlaybookExecutor(
playbooks=playbooks,
inventory=inventory,
variable_manager=variable_manager,
loader=loader,
options=options,
passwords=passwords)
executor.run()
使用Python 2.7.10和ansible 2.0.1.0进行测试
答案 1 :(得分:2)
发布完成。
我无法为ansible 2.4设置详细程度。我将主要谈论这个。
Ansible使用Display
文件中的全局__main__
对象(您启动的对象),如果它不存在则某些导入会创建它。
这被视为bad practice和not PEP8 compliant(第二个要点)
try:
from __main__ import display
except ImportError:
from ansible.utils.display import Display
display = Display()
几乎每个文件(108)都会调用它。 就像这样你在入口点有一个新的显示,然后所有其他模块将检索这个第一个声明的显示。
您只需声明一个Display对象:
from ansible.utils.display import Display
display = Display(verbosity=5)
您也可以在display.verbosity = 1000
我希望能够完全删除ansible输出(负值=无输出)
我最终创建了一个像这样的新类:
from ansible.utils.display import Display
class AnsibleDisplay(Display):
'''
This class override the display.display() function
'''
def display(self, *args, **kwargs):
if self.verbosity >= 0:
super(AnsibleDisplay, self).display(*args, **kwargs)
然后将其导入我的__main__
文件
# Ansible call this global object for display
sys.path.append(ROOT_DIR + os.sep + 'lib')
from ansible_display import AnsibleDisplay
display = AnsibleDisplay(verbosity=0)
仅在导入所有其他模块后
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
ROOT_DIR = os.path.dirname(SCRIPT_DIR)
## For ansible
import json
from collections import namedtuple
# Ansible call this global object for display
sys.path.append(ROOT_DIR + os.sep + 'lib')
from ansible_display import AnsibleDisplay
display = AnsibleDisplay(verbosity=0)
# Load other libs after to make sure they all use the above 'display'
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.playbook.play import Play
from ansible.executor.playbook_executor import PlaybookExecutor
def apply_verbosity(args):
global display
verb = -1 if args.verbosity is None else args.verbosity
display.verbosity = verb
def ansible_part():
playbook_path = "%s/ansible/main_playbook.yml" % (ROOT_DIR)
inventory_path = "%s/watev/my_inventory.ini"
Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'become', 'become_method', 'become_user', 'check', 'diff', 'listhosts', 'listtasks', 'listtags', 'syntax'])
# initialize needed objects
loader = DataLoader()
options = Options(connection='local', module_path='%s/' % (ROOT_DIR), forks=100, become=None, become_method=None, become_user=None, check=False,
diff=False, listhosts=True, listtasks=False, listtags=False, syntax=False)
passwords = dict(vault_pass='secret')
# create inventory and pass to var manager
inventory = InventoryManager(loader=loader, sources=[inventory_path])
variable_manager = VariableManager(loader=loader, inventory=inventory)
pbex = PlaybookExecutor(playbooks=[playbook_path], inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=passwords)
results = pbex.run()
def main():
ansible_part()
listhosts=True, listtasks=False, listtags=False, syntax=False
import __main__
使得调试变得不切实际,因为在使用调试器时(在我的情况下是pudb),__main__
文件是调试器文件,因此from __main__ import display
永远不会工作HTH
[Edit1]:添加了备注
答案 2 :(得分:1)
多亏了这个帖子中的建议,我设法找到了一种简单的方法来改变冗长:
import ansible
class AnsibleDisplay(ansible.utils.display.Display):
def display(self, *args, **kwargs):
self.verbosity = int(os.getenv('ANSIBLE_VERBOSITY', 0))
super(AnsibleDisplay, self).display(*args, **kwargs)
ansible.utils.display.Display = AnsibleDisplay
# Then import ansible packages after the patch
import ansible.constants as C
from ansible import context
from ansible.cli import CLI
from ansible.executor.playbook_executor import PlaybookExecutor
答案 3 :(得分:0)
我在没有看到你想要版本2的情况下写了这篇文章。离开它,虽然这不是正确答案。
这将在1.9中有效。您可以修改createcluster()命令来调用它。
def run_ansible():
vaultpass = "password"
inventory = ansible.inventory.Inventory("provisioning/inventory/hosts", vault_password=vaultpass)
stats = callbacks.AggregateStats()
playbook_cb = callbacks.PlaybookCallbacks(verbose=3)
pb = ansible.playbook.PlayBook(
playbook=playbook,
inventory=inventory,
extra_vars=parsed_extra_vars,
#private_key_file="/path/to/key.pem",
vault_password=vaultpass,
stats=stats,
callbacks=playbook_cb,
runner_callbacks=callbacks.PlaybookRunnerCallbacks(stats, verbose=3)
)
pb.run()
hosts = sorted(pb.stats.processed.keys())
failed_hosts = []
unreachable_hosts = []
for h in hosts:
t = pb.stats.summarize(h)
if t['failures'] > 0:
failed_hosts.append(h)
if t['unreachable'] > 0:
unreachable_hosts.append(h)
print("failed hosts: ", failed_hosts)
print("unreachable hosts: ", unreachable_hosts)
retries = failed_hosts + unreachable_hosts
print("retries:", retries)
if len(retries) > 0:
return 1
return 0