ansible的核心類

1. 給予Django的ansible web框架設計

 

2. 核心類介紹

概括前端

核心類 用途 所在的模塊路徑
DataLoader 用於讀取yaml、json格式的文件 ansible.parsing.dataloader
Play 存儲執行hosts的角色信息 ansible.playbook.play
TaskQueueManager ansible底層用到的任務隊列 ansible.executor.task_queue_manager
PlaybookExecutor 核心類執行playbook劇本 ansible.executor.playbook_executor
CallbackBase 狀態回調,各類成功失敗的狀態 ansible.plugins.callback
InventoryManager 用於導入inventory文件 ansible.inventory.manager
VariableManager 用於存儲各種變量信息 ansible.var.manager
Host,Group 操做單個主機或者主機組信息 ansible.inventory.host

 

2.1 InventoryManager 

功能:用來管理主機和主機組相關的資源設備信息python

from ansible.parsing.dataloader import DataLoader
from ansible.inventory.manager import InventoryManager
from ansible.vars.manager import VariableManager


# InventoryManager類
loader = DataLoader() # 實例化對象
inv = InventoryManager(loader=loader,sources=['auto_hosts'])

# add_host()方法,添加主機到指定的主機組 inv.add_host(host='192.168.1.112',port=22,group='test_group3') # get_groups_dict()方法,查看主機組資源 inv.get_groups_dict() """ {'all': ['192.168.1.112', '192.168.1.101', '192.168.1.110'], 'test_group1': ['192.168.1.112', '192.168.1.101', '192.168.1.110'], 'test_group2': ['192.168.1.112', '192.168.1.101'], 'test_group3': ['192.168.1.110', '192.168.1.112'], 'ungrouped': []} """ # get_hosts() 獲取全部的主機信息,返回的爲列表 inv.get_hosts # [192.168.1.112, 192.168.1.101, 192.168.1.110] # get_host() 獲取指定的主機對象 inv.get_host(hostname='192.168.1.112') # 192.168.1.112

 

2.2 VariableManager

功能:進行主機變量的讀取web

from ansible.parsing.dataloader import DataLoader
from ansible.inventory.manager import InventoryManager
from ansible.vars.manager import VariableManager


# InventoryManager類
loader = DataLoader() # 實例化對象
inv = InventoryManager(loader=loader,sources=['auto_hosts'])
#VariableManager類
variable_manager = VariableManager(loader=loader,inventory=inv)

# get_vars() # 查看變量方法
variable_manager.get_vars()
"""
{'ansible_playbook_python': '/usr/bin/python3',
 'groups': {'all': ['192.168.1.112', '192.168.1.101', '192.168.1.110'],
  'test_group1': ['192.168.1.112', '192.168.1.101', '192.168.1.110'],
  'test_group2': ['192.168.1.112', '192.168.1.101'],
  'test_group3': ['192.168.1.110', '192.168.1.112'],
  'ungrouped': []},
 'omit': '__omit_place_holder__04e40184623ea65c38973233a8c804a29215f21d',
 'playbook_dir': '/u01/autoops/script'}
"""

# get_vars() # 查詢主機指定的變量信息
host = inv.get_host(hostname='192.168.1.110')
variable_manager.get_vars(host=host)
"""
{'ansible_playbook_python': '/usr/bin/python3',
 'ansible_port': 22,
 'ansible_ssh_pass': 123456,
 'ansible_ssh_user': 'root',
 'group_names': ['test_group1', 'test_group3'],
 'groups': {'all': ['192.168.1.112', '192.168.1.101', '192.168.1.110'],
  'test_group1': ['192.168.1.112', '192.168.1.101', '192.168.1.110'],
  'test_group2': ['192.168.1.112', '192.168.1.101'],
  'test_group3': ['192.168.1.110', '192.168.1.112'],
  'ungrouped': []},
 'inventory_dir': '/u01/autoops/script',
 'inventory_file': '/u01/autoops/script/auto_hosts',
 'inventory_hostname': '192.168.1.110',
 'inventory_hostname_short': '192',
 'omit': '__omit_place_holder__3d8bb8c134c30295abd201bee6ef34093e580c2f',
 'playbook_dir': '/u01/autoops/script'}
"""

# set_host_variable() # 修改指定主機的變量信息
variable_manager.set_host_variable(host=host,varname='ansible_ssh_pass',value='111111')
variable_manager.get_vars(host=host)
"""
{'ansible_playbook_python': '/usr/bin/python3',
 'ansible_port': 22,
 'ansible_ssh_pass': '111111',
 'ansible_ssh_user': 'root',
 'group_names': ['test_group1', 'test_group3'],
 'groups': {'all': ['192.168.1.112', '192.168.1.101', '192.168.1.110'],
  'test_group1': ['192.168.1.112', '192.168.1.101', '192.168.1.110'],
  'test_group2': ['192.168.1.112', '192.168.1.101'],
  'test_group3': ['192.168.1.110', '192.168.1.112'],
  'ungrouped': []},
 'inventory_dir': '/u01/autoops/script',
 'inventory_file': '/u01/autoops/script/auto_hosts',
 'inventory_hostname': '192.168.1.110',
 'inventory_hostname_short': '192',
 'omit': '__omit_place_holder__3d8bb8c134c30295abd201bee6ef34093e580c2f',
 'playbook_dir': '/u01/autoops/script'}
""" # extra_vars={} # 添加指定對象的擴展變量,全局有效 variable_manager.extra_vars={'myweb':'jd.com','myname':'jacob'} variable_manager.get_vars(host=host) """ {'ansible_playbook_python': '/usr/bin/python3', 'ansible_port': 22, 'ansible_ssh_pass': '111111', 'ansible_ssh_user': 'root', 'group_names': ['test_group1', 'test_group2', 'test_group3'], 'groups': {'all': ['192.168.1.112', '192.168.1.101', '192.168.1.110'], 'test_group1': ['192.168.1.112', '192.168.1.101', '192.168.1.110'], 'test_group2': ['192.168.1.112', '192.168.1.101'], 'test_group3': ['192.168.1.110', '192.168.1.112'], 'ungrouped': []}, 'inventory_dir': '/u01/autoops/script', 'inventory_file': '/u01/autoops/script/auto_hosts', 'inventory_hostname': '192.168.1.110', 'inventory_hostname_short': '192', 'myname': 'jacob', 'myweb': 'jd.com', 'omit': '__omit_place_holder__04e40184623ea65c38973233a8c804a29215f21d', 'playbook_dir': '/u01/autoops/script'}
"""

 

2.3 ad-hoc模式調用場景

ansible的ad-hoc模式的調用示例:shell

 

ad-hoc模式通常用於批量執行簡單命令,文件替換等。此處的重點是執行對象和模塊,資源資產配置清單,執行選項。json

所需類及其調用關係爲:後端

 

2.3.1 namedtuple的用法回顧api

from collections import namedtuple

# User = namedtuple('User', 'name age id')
User = namedtuple('User', ['name', 'age', 'id'])
user = User('tester', '22', '24242432')
print(user)
# User(name='tester', age='22', id='24242432')
namedtuple用法

 

 2.3.2 ansible的ad-hoc模式options總結併發

-v, --verbose:輸出更詳細的執行過程信息,-vvv可獲得全部執行過程信息。

-i PATH, --inventory=PATH:指定inventory信息,默認/etc/ansible/hosts。

-f NUM, --forks=NUM:併發線程數,默認5個線程。

--private-key=PRIVATE_KEY_FILE:指定密鑰文件。

-m NAME, --module-name=NAME:指定執行使用的模塊。

-M DIRECTORY, --module-path=DIRECTORY:指定模塊存放路徑,默認/usr/share/ansible,也能夠經過ANSIBLE_LIBRARY設定默認路徑。

-a 'ARGUMENTS', --args='ARGUMENTS':模塊參數。

-k, --ask-pass SSH:認證密碼。

-K, --ask-sudo-pass sudo:用戶的密碼(—sudo時使用)。

-o, --one-line:標準輸出至一行。

-s, --sudo:至關於Linux系統下的sudo命令。

-t DIRECTORY, --tree=DIRECTORY:輸出信息至DIRECTORY目錄下,結果文件以遠程主機名命名。

-T SECONDS, --timeout=SECONDS:指定鏈接遠程主機的最大超時,單位是:秒。

-B NUM, --background=NUM:後臺執行命令,超NUM秒後kill正在執行的任務。

-P NUM, --poll=NUM:按期返回後臺任務進度。

-u USERNAME, --user=USERNAME:指定遠程主機以USERNAME運行命令。

-U SUDO_USERNAME, --sudo-user=SUDO_USERNAM:E使用sudo,至關於Linux下的sudo命令。

-c CONNECTION, --connection=CONNECTION:指定鏈接方式,可用選項paramiko (SSH), ssh, local。Local方式經常使用於crontab 和 kickstarts。

-l SUBSET, --limit=SUBSET:指定運行主機。

-l ~REGEX, --limit=~REGEX:指定運行主機(正則)。

--list-hosts:列出符合條件的主機列表,不執行任何其餘命令
options

 

2.3.3 結合options和play類的使用的簡單案例框架

# -*- coding: utf-8 -*-
#!/usr/bin/env python

#核心類
from collections import namedtuple
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.task_queue_manager import TaskQueueManager
from ansible.plugins.callback import CallbackBase

#InventoryManager類
loader = DataLoader()
inventory = InventoryManager(loader=loader,sources=['auto_hosts'])

#VariableManager類
variable_manager = VariableManager(loader=loader,inventory=inventory)

#Options 執行選項
Options = namedtuple('Options',
                     ['connection',     
                      'remote_user',   
                      'ask_sudo_pass', 
                      'verbosity',
                      'ack_pass',
                      'module_path',
                      'forks',         
                      'become',
                      'become_method',
                      'become_user',
                      'check',
                      'listhosts',
                      'listtasks',
                      'listtags',
                      'syntax',
                      'sudo_user',      
                      'sudo',
                      'diff'])
options = Options(connection='smart',   
                       remote_user=None,
                       ack_pass=None,
                       sudo_user=None,
                       forks=5,
                       sudo=None,
                       ask_sudo_pass=False,
                       verbosity=5,
                       module_path=None,
                       become=None,
                       become_method=None,
                       become_user=None,
                       check=False,
                       diff=False,
                       listhosts=None,
                       listtasks=None,
                       listtags=None,
                       syntax=None)
#Play 執行對象和模塊
play_source =  dict(
        name = "Ansible Play ad-hoc test", # 任務執行的名稱
        hosts = '192.168.102.101', # # 控制着任務執行的目標主機,能夠經過逗號填入多臺主機,或者正則匹配,或者主機組
        gather_facts = 'no', # 執行任務以前去獲取響應主機的相關信息,建議關閉,提升執行效率
        tasks = [
            # 以dict的方式實現,一個任務一個dict,能夠寫多個,module 爲對應模塊,args爲傳入的參數
            dict(action=dict(module='shell', args='touch /tmp/ad_hoc_test1')),
            # dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}')))
         ]
    )
play = Play().load(play_source, variable_manager=variable_manager, loader=loader)


passwords = dict() # 沒有實際做用,實際中密碼已經寫在文件中了
tqm = TaskQueueManager(
          inventory=inventory,
          variable_manager=variable_manager,
          loader=loader,
          options=options,
          passwords=passwords,
      )
result = tqm.run(play)
ansible_api_k1.py
[root@test01 script]# python3 ansible_api_k1.py 

PLAY [Ansible Play ad-hoc test] *******************************************************************************************************************************************

TASK [command] ************************************************************************************************************************************************************
 [WARNING]: Consider using file module with state=touch rather than running touch

changed: [192.168.102.101]

# 且在192.168.102.101生成/tmp/ad_hoc_test1文件
輸出結果

 

2.4 playbook模式調用場景

ansible的paybook模式的調用示例:ssh

palybook模式通常用於批量執行復雜的自動化任務,如批量安裝等。此處的重點是資源資產配置清單,執行選項等。

所需類及其調用關係爲:

2.4.1 playbook結合options和play類的使用的簡單案例

# -*- coding: utf-8 -*-
#!/usr/bin/env python

#核心類
from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.executor.playbook_executor import PlaybookExecutor
from ansible.playbook.play import Play
from ansible.executor.task_queue_manager import TaskQueueManager


#InventoryManager類
loader = DataLoader()
inventory = InventoryManager(loader=loader,sources=['auto_hosts'])

#VariableManager類
variable_manager = VariableManager(loader=loader,inventory=inventory)

#Options 執行選項
Options = namedtuple('Options',
                     ['connection',
                      'remote_user',
                      'ask_sudo_pass',
                      'verbosity',
                      'ack_pass',
                      'module_path',
                      'forks',
                      'become',
                      'become_method',
                      'become_user',
                      'check',
                      'listhosts',
                      'listtasks',
                      'listtags',
                      'syntax',
                      'sudo_user',
                      'sudo',
                      'diff'])
options = Options(connection='smart',
                       remote_user=None,
                       ack_pass=None,
                       sudo_user=None,
                       forks=5,
                       sudo=None,
                       ask_sudo_pass=False,
                       verbosity=5,
                       module_path=None,
                       become=None,
                       become_method=None,
                       become_user=None,
                       check=False,
                       diff=False,
                       listhosts=None,
                       listtasks=None,
                       listtags=None,
                       syntax=None)


#PlaybookExecutor 執行playbook
passwords = dict()
playbook = PlaybookExecutor(playbooks=['touch.yml'], # 注意路徑,多個基本直接添加便可
                            inventory=inventory,
                            variable_manager=variable_manager,
                            loader=loader,
                            options=options,
                            passwords=passwords,
                            )

playbook.run()
ansible_api_k2.py
---
- hosts: 192.168.102.101
  remote_user: root
  vars:
      touch_file: touch.file
  tasks:
      - name: touch file
        shell: "touch /tmp/{{touch_file}}"
touch.yml
PLAY [192.168.102.101] ****************************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************************************
ok: [192.168.102.101]

TASK [touch file] *********************************************************************************************************************************************************
 [WARNING]: Consider using file module with state=touch rather than running touch

changed: [192.168.102.101]

PLAY RECAP ****************************************************************************************************************************************************************
192.168.102.101            : ok=2    changed=1    unreachable=0    failed=0

# 會在192.168.102.101上生成/tmp/touch.file
輸出結果

 

2.5 callback的改寫

經過上面腳本的執行咱們會發現腳本執行結果並非很友善,好比執行任務的時間,執行任務所耗費時間,執行了什麼,特別是工程中咱們將輸出結果發送到前端進行展現以及後端日誌保存,若是隻是簡單地字符串則就不易操做,此時就要使用callback的改寫。

 

2.5.1 爲何要重寫callback

爲了自定義格式輸出

 

2.5.2 怎麼改寫callback

1. 經過子類繼承父類(callbackbase)

2. 經過子類改寫父類的部分方法

      v2_runner_on_unreachable

     v2_runner_on_ok

     v2_runner_on_failed

 

2.5.3 重寫ad-hoc模式的類

# -*- coding: utf-8 -*-
# !/usr/bin/env python

# 核心類
from collections import namedtuple
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.task_queue_manager import TaskQueueManager
from ansible.plugins.callback import CallbackBase

# InventoryManager類
loader = DataLoader()
inventory = InventoryManager(loader=loader, sources=['auto_hosts'])

# VariableManager類
variable_manager = VariableManager(loader=loader, inventory=inventory)

# Options 執行選項
Options = namedtuple('Options',
                     ['connection',
                      'remote_user',
                      'ask_sudo_pass',
                      'verbosity',
                      'ack_pass',
                      'module_path',
                      'forks',
                      'become',
                      'become_method',
                      'become_user',
                      'check',
                      'listhosts',
                      'listtasks',
                      'listtags',
                      'syntax',
                      'sudo_user',
                      'sudo',
                      'diff'])
options = Options(connection='smart',
                  remote_user=None,
                  ack_pass=None,
                  sudo_user=None,
                  forks=5,
                  sudo=None,
                  ask_sudo_pass=False,
                  verbosity=5,
                  module_path=None,
                  become=None,
                  become_method=None,
                  become_user=None,
                  check=False,
                  diff=False,
                  listhosts=None,
                  listtasks=None,
                  listtags=None,
                  syntax=None)
# Play 執行對象和模塊
play_source = dict(
    name="Ansible Play ad-hoc test",  # 任務執行的名稱
    hosts='192.168.102.101',  # 控制着任務執行的目標主機,能夠經過逗號填入多臺主機,或者正則匹配,或者主機組
    gather_facts='no',  # 執行任務以前去獲取響應主機的相關信息,建議關閉,提升執行效率
    tasks=[
        # 以dict的方式實現,一個任務一個dict,能夠寫多個,module 爲對應模塊,args爲傳入的參數
        dict(action=dict(module='shell', args='touch /tmp/ad_hoc_test1')),
        # dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}')))
    ]
)
play = Play().load(play_source, variable_manager=variable_manager, loader=loader)


class ModelResultsCollector(CallbackBase):  # 繼承父類CallbackBase
    """
    重寫callbackBase類的部分方法
    """

    def __init__(self, *args, **kwargs):
        super(ModelResultsCollector, self).__init__(*args, **kwargs)  # 初始化父類方法
        self.host_ok = {}
        self.host_unreachable = {}
        self.host_failed = {}

    def v2_runner_on_unreachable(self, result):  # result 爲父類中獲取全部執行結果信息的對象
        self.host_unreachable[result._host.get_name()] = result

    def v2_runner_on_ok(self, result):
        self.host_ok[result._host.get_name()] = result

    def v2_runner_on_failed(self, result):
        self.host_failed[result._host.get_name()] = result


callback = ModelResultsCollector()

passwords = dict()
tqm = TaskQueueManager(
    inventory=inventory,
    variable_manager=variable_manager,
    loader=loader,
    options=options,
    passwords=passwords,  # 沒有實際的做用
    stdout_callback=callback,
)
result = tqm.run(play)

print(callback.host_ok.items())
# [(u"192.168.102.101",<ansible.executor.task_result.TaskResult object at 0x10406b790>)]

result_raw = {'success': {}, 'failed': {}, 'unreachable': {}}

for host, result in callback.host_ok.items():
    result_raw['success'][host] = result._result # _result屬性來獲取任務執行的結果
for host, result in callback.host_failed.items():
    result_raw['failed'][host] = result._result
for host, result in callback.host_unreachable.items():
    result_raw['unreachable'][host] = result._result
    
print(result_raw)
ansible_api_k1.py
{
    'success': {
        '192.168.102.101': {
            'changed': True,
            'end': '2019-03-03 21:24:29.426184',
            'stdout': '',
            'cmd': 'touch /tmp/ad_hoc_test1',
            'rc': 0,
            'start': '2019-03-03 21:24:29.422987',
            'stderr': '',
            'delta': '0:00:00.003197',
            'invocation': {
                'module_args': {
                    'warn': True,
                    'executable': None,
                    '_uses_shell': True,
                    '_raw_params': 'touch /tmp/ad_hoc_test1',
                    'removes': None,
                    'creates': None,
                    'chdir': None,
                    'stdin': None
                }
            },
            'warnings': ['Consider using file module with state=touch rather than running touch'],
            '_ansible_parsed': True,
            'stdout_lines': [],
            'stderr_lines': [],
            '_ansible_no_log': False,
            'failed': False
        }
    },
    'failed': {},
    'unreachable': {}
}
輸出結果

 

2.5.4 重寫playbook模式的類

# -*- coding: utf-8 -*-
# !/usr/bin/env python

# 核心類
from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.executor.playbook_executor import PlaybookExecutor
from ansible.playbook.play import Play
from ansible.executor.task_queue_manager import TaskQueueManager
from ansible.plugins.callback import CallbackBase

# InventoryManager類
loader = DataLoader()
inventory = InventoryManager(loader=loader, sources=['auto_hosts'])

# VariableManager類
variable_manager = VariableManager(loader=loader, inventory=inventory)

# Options 執行選項
Options = namedtuple('Options',
                     ['connection',
                      'remote_user',
                      'ask_sudo_pass',
                      'verbosity',
                      'ack_pass',
                      'module_path',
                      'forks',
                      'become',
                      'become_method',
                      'become_user',
                      'check',
                      'listhosts',
                      'listtasks',
                      'listtags',
                      'syntax',
                      'sudo_user',
                      'sudo',
                      'diff'])
options = Options(connection='smart',
                  remote_user=None,
                  ack_pass=None,
                  sudo_user=None,
                  forks=5,
                  sudo=None,
                  ask_sudo_pass=False,
                  verbosity=5,
                  module_path=None,
                  become=None,
                  become_method=None,
                  become_user=None,
                  check=False,
                  diff=False,
                  listhosts=None,
                  listtasks=None,
                  listtags=None,
                  syntax=None)


# CallbackBase改寫
class PlayBookResultsCollector(CallbackBase):
    CALLBACK_VERSION = 2.0

    def __init__(self, *args, **kwargs):
        super(PlayBookResultsCollector, self).__init__(*args, **kwargs)
        self.task_ok = {}
        self.task_skipped = {}
        self.task_failed = {}
        self.task_status = {}
        self.task_unreachable = {}

    def v2_runner_on_ok(self, result, *args, **kwargs):
        self.task_ok[result._host.get_name()] = result

    def v2_runner_on_failed(self, result, *args, **kwargs):
        self.task_failed[result._host.get_name()] = result

    def v2_runner_on_unreachable(self, result):
        self.task_unreachable[result._host.get_name()] = result

    def v2_runner_on_skipped(self, result):
        self.task_ok[result._host.get_name()] = result

    def v2_playbook_on_stats(self, stats):
        hosts = sorted(stats.processed.keys())
        for h in hosts:
            t = stats.summarize(h)
            self.task_status[h] = {
                "ok": t['ok'],
                "changed": t['changed'],
                "unreachable": t['unreachable'],
                "skipped": t['skipped'],
                "failed": t['failures']
            }


callback = PlayBookResultsCollector()

# PlaybookExecutor 執行playbook
passwords = dict()
playbook = PlaybookExecutor(playbooks=['touch.yml'],  # 若是有多個劇本則在列表中寫入
                            inventory=inventory,
                            variable_manager=variable_manager,
                            loader=loader,
                            options=options,
                            passwords=passwords,
                            )
playbook._tqm._stdout_callback = callback # 此處調用與ad-hoc模式不一樣
playbook.run()

results_raw = {'skipped': {}, 'failed': {}, 'success': {}, "status": {}, 'unreachable': {}, "changed": {}}


for host, result in callback.task_ok.items():
    results_raw['success'][host] = result._result # _result屬性來獲取任務執行的結果
for host, result in callback.task_failed.items():
    results_raw['failed'][host] = result._result    
for host, result in callback.task_unreachable.items():
    results_raw['unreachable'][host] = result._result


print(results_raw)
ansible_api_k2.py
{
    'skipped': {},
    'failed': {},
    'success': {
        '192.168.102.101': {
            'changed': True,
            'end': '2019-03-03 21:49:44.851042',
            'stdout': '',
            'cmd': 'touch /tmp/touch.file',
            'rc': 0,
            'start': '2019-03-03 21:49:44.848321',
            'stderr': '',
            'delta': '0:00:00.002721',
            'invocation': {
                'module_args': {
                    'warn': True,
                    'executable': None,
                    '_uses_shell': True,
                    '_raw_params': 'touch /tmp/touch.file',
                    'removes': None,
                    'creates': None,
                    'chdir': None,
                    'stdin': None
                }
            },
            'warnings': ['Consider using file module with state=touch rather than running touch'],
            '_ansible_parsed': True,
            'stdout_lines': [],
            'stderr_lines': [],
            '_ansible_no_log': False,
            'failed': False
        }
    },
    'status': {},
    'unreachable': {},
    'changed': {}
}
輸出結果
相關文章
相關標籤/搜索