使用Python API 2.0.0.1运行Ansible Playbook

2024-05-19 01:40:30 发布

您现在位置:Python中文网/ 问答频道 /正文

Ansible版本:2.0.0.1

我已经看了很多遍了,我发现的大多数文档要么不完整,要么已弃用(this post is for version 1.8.4, ie

我正在尝试通过Python API启动Ansible playbook。Ansible的文档似乎展示了如何生成和播放任务,但没有展示如何加载和运行PlaybookYML文件。我一直在深入研究代码,试图了解如何启动它,我想我已经取得了一些进展,但我真的遇到了困难。以下是我目前掌握的情况:

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()

我对执行器部分一点也不确定,当我尝试启动代码时,我一直收到一个“attributerror:”Options“object has no attribute‘listhosts’”错误(奇怪的是,它应该忽略它的不存在,我认为(line 60)

我应该如何加载一个YML文件并通过Python API启动它?我是走在好的道路上还是迷失了自我?为什么Ansible没有更好的文档?为什么42是7*7的答案?


Tags: 文档managerpasswordloaderansiblevariableregionoptions
3条回答

免责声明

发布以完成。
我在为ansibe2.4设置详细信息时遇到问题。我主要谈谈这个。

TL;DR

Ansible在__main__文件(您启动的那个文件)中使用一个全局对象Display如果它不存在,一些导入将创建它。
这被认为是bad practicenot PEP8 compliant(第二个要点)


解释部分

版本:(我正在使用python virtualenv)

  • ansible=2.4.2.0(也在2.4.1.0中测试)
  • Python=2.7.13

如何在ansible内部使用

try:
    from __main__ import display
except ImportError:
    from ansible.utils.display import Display
    display = Display()

几乎每个文件(108)都会调用它。 就像这样,在入口点中有一个新的显示,然后所有其他模块将检索这个第一次声明的显示。

以另一种冗长的方式运行

您只需声明如下显示对象:

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()

注释

  1. 我需要在namedtuple中添加4个选项:
    listhosts=True, listtasks=False, listtags=False, syntax=False
  2. import __main__使调试变得不切实际,因为当使用调试器(在我的例子中是pudb)时,__main__文件是调试器文件,因此from __main__ import display将永远无法工作

高温高压

[编辑1]:添加了注释

我写这篇文章时没有看到你想要版本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

下面是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()

使用Python2.7.10和ansible 2.0.1.0进行测试

相关问题 更多 >

    热门问题