国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

ansible2.0 playbook api運維應用

dreamans / 913人閱讀

摘要:寫在前面是一個非常棒的運維工具,可以遠程批量執行命令上傳文件等自動化運維操作,由于要搞配置管理,初始化等批量操作,而自己對相對熟悉因此選擇了。

寫在前面:

ansible是一個非常棒的運維工具,可以遠程批量執行命令、上傳文件等自動化運維操作,由于要搞配置管理,初始化等批量操作,而自己對ansible相對熟悉,因此選擇了ansible playbook。
不過在調用playbook api的過程中,發現原始api并不能滿足我的需求,網絡上多數文檔還是1.0版本,因此下載了2.0源碼查看,重寫了部分類。因此這里總結學習,也給有相同需求的朋友參考

ansible-playbook使用 一、ansible-playbook簡單介紹

playbook字面意思看就是劇本,其實也很形象,ansible-playbook就是事先定義好很多task(任務)放在.yml文件中,執行的時候就像劇本一樣,依次往下演(執行)

#/tmp/xx.yml

---
- hosts: all    #hosts中指定

  tasks:
    - name: "ls /tmp"         #- name:任務名稱,下面是任務過程
      shell: "ls /tmp/"

ansible-playbook執行:

二、ansible-playbook api介紹

ansible-playbook apiansible官方提供接口,用于在python代碼中更靈活的使用,但官方只提供了ansible-api的參考文檔,且2.0以后變化較大,api編寫更復雜,但更為靈活

官方參考: http://docs.ansible.com/ansib...

一個基本的ansible-playbook api調用

# -*- coding:utf-8 -*-
# 描述:
# V1 WZJ 2016-12-20
from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars import VariableManager
from ansible.inventory import Inventory
from ansible.executor.playbook_executor import PlaybookExecutor

# 用來加載解析yaml文件或JSON內容,并且支持vault的解密
loader = DataLoader()
    
# 管理變量的類,包括主機,組,擴展等變量,之前版本是在 inventory中的
variable_manager = VariableManager()

# 根據inventory加載對應變量,此處host_list參數可以有兩種格式:
# 1: hosts文件(需要),
# 2: 可以是IP列表,此處使用IP列表
inventory = Inventory(loader=loader, variable_manager=variable_manager,host_list=["172.16.1.121"])
variable_manager.set_inventory(inventory)

# 設置密碼,需要是dict類型
passwords=dict(conn_pass="your password")

# 初始化需要的對象
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"])
# 初始化需要的對象
options = Options(connection="smart", 
                       remote_user="root",
                       ack_pass=None,
                       sudo_user="root",
                       forks=5,
                       sudo="yes",
                       ask_sudo_pass=False,
                       verbosity=5,
                       module_path=None,  
                       become=True, 
                       become_method="sudo", 
                       become_user="root", 
                       check=None,
                       listhosts=None,
                       listtasks=None, 
                       listtags=None, 
                       syntax=None)

# playbooks就填寫yml文件即可,可以有多個,以列表形式
playbook = PlaybookExecutor(playbooks=["/tmp/xx.yml"],inventory=inventory,
              variable_manager=variable_manager,
              loader=loader,options=options,passwords=passwords)
# 開始執行
playbook.run()

執行上面腳本:

可以發現,這個api調用執行雖然成功了,但是并沒有什么詳細輸出(這個跟一個名叫CallbackBase的類有關)

重寫palybook api

1 為什么重寫?
在實際應用中,有許多地方是不太滿足需求的
1.比如inventory有host group(主機組)的概念,但是默認都放在all組里面去了,導致在編寫yml的時候,無法對不同IP組進行不同的操作
2.console輸出結果有時候需要自定義
3.調用api需要更為靈活

當然除了以上需求外,還有一些其它意義,比如閱讀源碼有助于熟悉ansible的工作方式,也提升自己的腳本能力

注意:所謂重寫只是在源碼的基礎上繼承并修改了部分代碼,有可能導致ansible不穩定的情況,另外只有在有中文注釋的地方才是重寫內容

2 ansible源碼文件簡單介紹
源碼下載地址:https://github.com/ansible/an...

其實ansible我們所用到的源碼都在lib里面,而需要關注的也主要是三個文件夾和一些類:

用于解析和聚合host,group等環境變量: lib/ansible/inventory/__init__.py 中 Inventory

用于console輸出: lib/ansible/plugins/callback/default.py 中 CallbackModule

用于playbook的解析工作: lib/executor/playbook_executor.py 中 PlaybookExecutor

playbook底層用到的任務隊列:lib/executor/task_queue_manager.py 中 TaskQueueManager

幾個重寫的類的樹狀圖:

一、Inventory類重寫

1.修改可以為IP傳入group name
2.額外的自定義參數,如:{"test":1000}

# -*- coding:utf-8 -*-
# 描述:
# V1 WZJ 2016-12-20 Inventory重寫封裝api基本功能
import fnmatch

from ansible.compat.six import string_types, iteritems

from ansible import constants as C
from ansible.errors import AnsibleError

from ansible.inventory.dir import InventoryDirectory, get_file_parser
from ansible.inventory.group import Group
from ansible.inventory.host import Host
from ansible.module_utils._text import to_bytes, to_text
from ansible.parsing.utils.addresses import parse_address
from ansible.plugins import vars_loader
from ansible.utils.vars import combine_vars
from ansible.utils.path import unfrackpath

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

HOSTS_PATTERNS_CACHE = {}
from ansible.inventory import Inventory
class YunweiInventory(Inventory):
    """重寫Inventory"""
    def __init__(self, loader, variable_manager, group_name, ext_vars=None,host_list=C.DEFAULT_HOST_LIST):

        # the host file file, or script path, or list of hosts
        # if a list, inventory data will NOT be loaded
        # self.host_list = unfrackpath(host_list, follow=False)
        # 傳入的hosts
        self.host_list  = host_list
        # 傳入的項目名也是組名
        self.group_name = group_name
        # 傳入的外部變量,格式為字典
        self.ext_vars   = ext_vars
        # caching to avoid repeated calculations, particularly with
        # external inventory scripts.

        self._vars_per_host    = {}
        self._vars_per_group   = {}
        self._hosts_cache      = {}
        self._pattern_cache    = {}
        self._group_dict_cache = {}
        self._vars_plugins     = []

        self._basedir = self.basedir()

        # Contains set of filenames under group_vars directories
        self._group_vars_files = self._find_group_vars_files(self._basedir)
        self._host_vars_files = self._find_host_vars_files(self._basedir)

        # to be set by calling set_playbook_basedir by playbook code
        self._playbook_basedir = None

        # the inventory object holds a list of groups
        self.groups = {}

        # a list of host(names) to contain current inquiries to
        self._restriction = None
        self._subset = None

        # clear the cache here, which is only useful if more than
        # one Inventory objects are created when using the API directly
        self.clear_pattern_cache()
        self.clear_group_dict_cache()

        self.parse_inventory(host_list)

    def parse_inventory(self, host_list):
    
        if isinstance(host_list, string_types):
            if "," in host_list:
                host_list = host_list.split(",")
                host_list = [ h for h in host_list if h and h.strip() ]
    
        self.parser = None
    
        # Always create the "all" and "ungrouped" groups, even if host_list is
        # empty: in this case we will subsequently an the implicit "localhost" to it.
    
        ungrouped = Group("ungrouped")
        all = Group("all")
        all.add_child_group(ungrouped)
    
        # 加一個本地IP
        local_group = Group("local")
    
        # 自定義組名
        zdy_group_name = Group(self.group_name)
        self.groups = {self.group_name:zdy_group_name,"all":all,"ungrouped":ungrouped,"local":local_group}
        #self.groups = dict(all=all, ungrouped=ungrouped)
    
        if host_list is None:
            pass
        elif isinstance(host_list, list):
            # 默認添加一個本地IP
            (lhost, lport) = parse_address("127.0.0.1", allow_ranges=False)
            new_host = Host(lhost, lport)
            local_group.add_host(new_host)
    
            for h in host_list:
                try:
                    (host, port) = parse_address(h, allow_ranges=False)
                except AnsibleError as e:
                    display.vvv("Unable to parse address from hostname, leaving unchanged: %s" % to_text(e))
                    host = h
                    port = None
    
                new_host = Host(host, port)
                if h in C.LOCALHOST:
                    # set default localhost from inventory to avoid creating an implicit one. Last localhost defined "wins".
                    if self.localhost is not None:
                        display.warning("A duplicate localhost-like entry was found (%s). First found localhost was %s" % (h, self.localhost.name))
                    display.vvvv("Set default localhost to %s" % h)
                    self.localhost = new_host
                # 為組添加host
                zdy_group_name.add_host(new_host)
                # 為主機組添加額外參數
                # 添加外部變量
                if self.ext_vars and isinstance(self.ext_vars,dict):
                    for k,v in self.ext_vars.items():
                        zdy_group_name.set_variable(k,v)
                        local_group.set_variable(k,v)
    
        elif self._loader.path_exists(host_list):
            # TODO: switch this to a plugin loader and a "condition" per plugin on which it should be tried, restoring "inventory pllugins"
            if self.is_directory(host_list):
                # Ensure basedir is inside the directory
                host_list = os.path.join(self.host_list, "")
                self.parser = InventoryDirectory(loader=self._loader, groups=self.groups, filename=host_list)
            else:
                self.parser = get_file_parser(host_list, self.groups, self._loader)
                vars_loader.add_directory(self._basedir, with_subdir=True)
    
            if not self.parser:
                # should never happen, but JIC
                raise AnsibleError("Unable to parse %s as an inventory source" % host_list)
        else:
            display.warning("Host file not found: %s" % to_text(host_list))
    
        self._vars_plugins = [ x for x in vars_loader.all(self) ]
    
        # set group vars from group_vars/ files and vars plugins
        for g in self.groups:
            group = self.groups[g]
            group.vars = combine_vars(group.vars, self.get_group_variables(group.name))
            self.get_group_vars(group)
    
        # get host vars from host_vars/ files and vars plugins
        for host in self.get_hosts(ignore_limits=True, ignore_restrictions=True):
            host.vars = combine_vars(host.vars, self.get_host_variables(host.name))
            self.get_host_vars(host)
二、collback重寫,用于自定義輸出

1.以callback.default.CallbackModule為基類繼承
2.自定義了輸出格式,正確輸出情況,不需要的輸出就忽略了,只留下幾個有用的stdout
3.最后的輸出結果:

#-*- coding:utf-8 -*-
# 描述:
# V1 WZJ 2016-12-19 CallBack重寫封裝api基本功能,用于console輸出

import json
from ansible import constants as C
from ansible.plugins.callback.default import CallbackModule

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

class YunweiCallback(CallbackModule):
    """重寫console輸出日志"""

    # 重寫2.0版本正確stdout
    def v2_runner_on_ok(self, result):

        if self._play.strategy == "free" and self._last_task_banner != result._task._uuid:
            self._print_task_banner(result._task)

        self._clean_results(result._result, result._task.action)
        #delegated_vars = result._result.get("_ansible_delegated_vars", None)
        delegated_vars = self._dump_results(result._result)
        #delegated_vars = result._result
        #n_delegated_vars = self._dump_results(result)
        #print n_delegated_vars
        self._clean_results(result._result, result._task.action)
        if result._task.action in ("include", "include_role"):
            return
        elif result._result.get("changed", False):
            if delegated_vars:
                # 自定義輸出
                zdy_msg = self.zdy_stdout(json.loads(delegated_vars))
                if zdy_msg:
                    msg = "changed: [%s]%s" % (result._host.get_name(), zdy_msg)
                else:
                    msg = "changed: [%s -> %s]" % (result._host.get_name(), delegated_vars)
            else:
                msg = "changed: [%s]" % result._host.get_name()
            color = C.COLOR_CHANGED
        # 判斷是否是第一步 setup
        elif result._result.get("ansible_facts",False):
            msg = "ok: [ %s | %s ]" % (str(result._host),str(result._host.get_groups()))
            color = C.COLOR_OK
        else:
            if delegated_vars:
                # 自定義輸出
                zdy_msg = self.zdy_stdout(json.loads(delegated_vars))
                if zdy_msg:
                    msg = "ok: [%s]%s" % (result._host.get_name(), zdy_msg)
                else:
                    msg = "ok: [%s -> %s]" % (result._host.get_name(), delegated_vars)
            else:
                msg = "ok: [%s]" % result._host.get_name()
            color = C.COLOR_OK

        if result._task.loop and "results" in result._result:
            self._process_items(result)
        else:
            self._display.display(msg, color=color)

        self._handle_warnings(result._result)

    # 自定義輸出,格式清晰一些
    def zdy_stdout(self,result):
        msg = ""
        if result.get("delta",False):
            msg += u"	執行時間:%s"%result["delta"]
        if result.get("cmd", False):
            msg += u"
執行命令:%s"%result["cmd"]
        if result.get("stderr",False):
            msg += u"
錯誤輸出:
%s"%result["stderr"]
        if result.get("stdout",False):
            msg += u"
正確輸出:
%s"%result["stdout"]
        if result.get("warnings",False):
            msg += u"
警告:%s"%result["warnings"]
        return msg
三、封裝PlaybookExecutor

1.封裝為更容易調用的playbook api調用
2.定制化一部分參數

# -*- coding:utf-8 -*-
# 描述:
# V1 WZJ 2016-12-19 PlayBook重寫封裝api基本功能

import json
from ansible import constants as C
from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars import VariableManager
from ansible.playbook.play import Play
from ansible.executor.task_queue_manager import TaskQueueManager
from ansible.executor.playbook_executor import PlaybookExecutor
from callback import YunweiCallback
from ansible.utils.ssh_functions import check_for_controlpersist

# 調用自定義Inventory
from inventory import YunweiInventory as Inventory 
try:
    from __main__ import display
except ImportError:
    from ansible.utils.display import Display
    display = Display()


class YunweiPlaybookExecutor(PlaybookExecutor):
    
    """重寫PlayBookExecutor"""
    def __init__(self, playbooks, inventory, variable_manager, loader, options, passwords, stdout_callback=None):
        self._playbooks        = playbooks
        self._inventory        = inventory
        self._variable_manager = variable_manager
        self._loader           = loader
        self._options          = options
        self.passwords         = passwords
        self._unreachable_hosts = dict()

        if options.listhosts or options.listtasks or options.listtags or options.syntax:
            self._tqm = None
        else:
            self._tqm = TaskQueueManager(inventory=inventory, variable_manager=variable_manager, loader=loader, options=options, passwords=self.passwords, stdout_callback=stdout_callback)

        # Note: We run this here to cache whether the default ansible ssh
        # executable supports control persist.  Sometime in the future we may
        # need to enhance this to check that ansible_ssh_executable specified
        # in inventory is also cached.  We can"t do this caching at the point
        # where it is used (in task_executor) because that is post-fork and
        # therefore would be discarded after every task.
        check_for_controlpersist(C.ANSIBLE_SSH_EXECUTABLE)


class PlayBookJob(object):
  """封裝一個playbook接口,提供給外部使用"""
  def __init__(self,playbooks,host_list,ssh_user="bbs",passwords="null",project_name="all",ack_pass=False,forks=5,ext_vars=None):
    self.playbooks = playbooks
    self.host_list = host_list
    self.ssh_user  = ssh_user
    self.passwords = dict(vault_pass=passwords)
    self.project_name = project_name
    self.ack_pass  = ack_pass
    self.forks     = forks
    self.connection="smart"
    self.ext_vars  = ext_vars

    ## 用來加載解析yaml文件或JSON內容,并且支持vault的解密
    self.loader    = DataLoader()

    # 管理變量的類,包括主機,組,擴展等變量,之前版本是在 inventory中的
    self.variable_manager = VariableManager()

    # 根據inventory加載對應變量
    self.inventory = Inventory(loader=self.loader, 
                               variable_manager=self.variable_manager,
                               group_name=self.project_name,  # 項目名對應組名,區分當前執行的內容
                               ext_vars=self.ext_vars,
                               host_list=self.host_list)

    self.variable_manager.set_inventory(self.inventory)

    # 初始化需要的對象1
    self.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"
                             ])

    # 初始化需要的對象2
    self.options = self.Options(connection=self.connection, 
                                remote_user=self.ssh_user,
                                ack_pass=self.ack_pass,
                                sudo_user=self.ssh_user,
                                forks=self.forks,
                                sudo="yes",
                                ask_sudo_pass=False,
                                verbosity=5,
                                module_path=None,  
                                become=True, 
                                become_method="sudo", 
                                become_user="root", 
                                check=None,
                                listhosts=None,
                                listtasks=None, 
                                listtags=None, 
                                syntax=None
                               )

    # 初始化console輸出
    self.callback = YunweiCallback()

    # 直接開始
    self.run()

  def run(self):
    pb = None
    pb = YunweiPlaybookExecutor(
        playbooks            = self.playbooks,
        inventory            = self.inventory,
        variable_manager     = self.variable_manager,
        loader               = self.loader,
        options              = self.options,
        passwords            = self.passwords,
        stdout_callback      = self.callback
    )
    result = pb.run()

# daemo
if __name__ == "__main__":
    PlayBookJob(playbooks=["xx.yml"],
                host_list=["10.45.176.2"],
                ssh_user="root",
                project_name="test",
                forks=20,
                ext_vars=None
                )
參考:

ansible-api官方文檔:http://docs.ansible.com/ansib...
一個非常好的ansible2.0 api調用文檔,相見恨晚:https://serversforhackers.com...
ansible源碼:https://github.com/ansible/an...

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/38309.html

相關文章

  • ansible2.0 playbook api運維應用

    摘要:寫在前面是一個非常棒的運維工具,可以遠程批量執行命令上傳文件等自動化運維操作,由于要搞配置管理,初始化等批量操作,而自己對相對熟悉因此選擇了。 寫在前面: ansible是一個非常棒的運維工具,可以遠程批量執行命令、上傳文件等自動化運維操作,由于要搞配置管理,初始化等批量操作,而自己對ansible相對熟悉,因此選擇了ansible playbook。不過在調用playbook api...

    wangtdgoodluck 評論0 收藏0
  • Ansible運維工具

    摘要:與最大的區別是無需在被控主機部署任何客戶端代理,默認直接通過通道進行遠程命令執行或下發配置相同點是都具備功能強大靈活的系統管理狀態配置,兩者都提供豐富的模板及,對云計算平臺大數據都有很好的支持。臨時禁止使用庫。強制更新的緩存。 概述 運維工具按需不需要有代理程序來劃分的話分兩類: agent(需要有代理工具):基于專用的agent程序完成管理功能,puppet, func, zabb...

    baoxl 評論0 收藏0
  • Ansible運維工具

    摘要:與最大的區別是無需在被控主機部署任何客戶端代理,默認直接通過通道進行遠程命令執行或下發配置相同點是都具備功能強大靈活的系統管理狀態配置,兩者都提供豐富的模板及,對云計算平臺大數據都有很好的支持。臨時禁止使用庫。強制更新的緩存。 概述 運維工具按需不需要有代理程序來劃分的話分兩類: agent(需要有代理工具):基于專用的agent程序完成管理功能,puppet, func, zabb...

    KevinYan 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<