自動化運維開發項目

前言:

從宏觀環境來看互聯網用戶正在飛速發展,在我國互聯網的普及率已接近了60%;html

互聯網用戶的上漲勢必會對網站的規模和性能帶來更大的要求,因此就須要1個龐大的系統 支撐起海量用戶的併發訪問;前端

對於運維人員來講咱們須要 以一種更加自動化的方式 加速運維效率應對突發流量,以及更加可靠的技術手段保障系統穩定運行;python

 2大核心功能:mysql

資產自動化掃描、發現  (CMDB)nginx

Ansible自動化任務執行 (批量執行任務)git

 

1、總體功能設計

資產自動化掃描發現github

使用Python程序掃描、發現企業內部的全部資產(實體機+虛擬機【KVM+ESX+Docker】+網絡設備+其餘),當資產信息變動(設備升級、資產下線)自動發現並完成數據庫資產變動記錄; sql

Ansible自動化任務執行docker

基於Ansible的ad-hoc和playbook方式實現批量主機任務執行;shell

 

 

 

2、掃描出網絡中存活的主機

 

想要作CMDB就須要知道您所在公司到底有多少資產?都有那些統計方式呢?

 

0.人工錄入

服務器變動人工干涉維護;

 

1.程序自動發現

使用nmap網絡掃描工具,掃描公司內網每一個網絡中存活的主機列表。

 

  

3、硬件/系統信息獲取

經過paramiko登陸主機列中服務器,調用shell命令,經過awk、send截取指定內容;

1.獲取主機名

 hostname

2.獲取mac地址

Linux系統:

cat /sys/class/net/[^vtlsb]*/address

EXSI:

esxcfg-vmknic -l|awk '{print $8}' | grep ':'

 通用型

cat /sys/class/net/[^vtlsb]*/address || esxcfg-vmknic -l|awk '{print $8}' | grep ':'

3.系統版本

 cat /etc/issue  || cat /etc/reahat-release

4.服務機型

dmidecode -s system-product-name  PS:安裝 yum -y install dmidecode

5.SN(服務器惟一標識)

dmidecode -s system-serial-number

以上信息均可以基於paramiko遠程執行命令返回信息結果(不包含 docker和網絡設備);

 

6.獲取網絡設備、docker容器的信息

6.1 獲取網絡設備的硬件信息

對於網絡設備管理人員咱們除了使用ssh協議(TCP/22)以外還要使用Telnet協議(TCP/23)

若是想要獲取網絡設備的信息能夠經過 snmap(簡單網絡管理協議)

使用python snmap模塊做爲客戶端去鏈接網絡設備 並獲取網絡設備信息;

pip install pysnmp
from pysnmp.entity.rfc3413.oneliner import cmdgen
cg=cmdgen.CommandGenerator()
ret=cg.getCmd(cmdgen.CommunityData('snmpt','public',0), #,安全my-agent、社區名public、snmp協議版本,之間用逗號隔開, snmp協議版本:0表明 2C 1
        cmdgen.UdpTransportTarget(('172.17.10.112',161 )),'.1.3.6.1.2.1.1.1.0')     #ip 端口 OID,一個OID對應一種設備(好比網卡、磁盤等,在不一樣機器上同種設備的OID是同樣的)

# print(ret)
'''
(None, 0, 0, 錯誤信息
[執行結果]
'''
print( ret[-1])

for i in  ret[-1]:
    print(i)
使用pysnmp模塊獲取網絡設備信息

注意:

 OID:1個OID對應 1種服務器硬件信息(好比網卡、磁盤等,在不一樣機器上同種設備的OID是同樣的),不一樣廠商網絡設備 的OID可見官網

 

6.2獲取docker容器的信息

 

安裝docker容器

shell獲取docker容器(端口、容器ID、鏡像ID)。 

[root@localhost zhanggen]# docker ps | awk -F '->'  '{print $1}' | grep -v 'CONTAINER' |awk 'BEGIN{FS~/s+/;}{print $NF " "$1" "$2;}' |sed  s/0.0.0.0:// 
5166 43958ff0fbaa 78a959232453
[root@localhost zhanggen]# 
import paramiko,time
ssh = paramiko.SSHClient()
ssh._policy = paramiko.AutoAddPolicy()
ssh.connect(hostname='192.168.226.139',port=22, username='root',password='123.com')

docker_list_cmd="""docker ps | awk -F '->'  '{print $1}' | grep -v 'CONTAINER' |awk 'BEGIN{FS~/s+/;}{print $NF " "$1" "$2;}' |sed s/0.0.0.0://"""
stdin,stdout,stderr=ssh.exec_command(docker_list_cmd)
docker_info=stdout.read().decode('utf-8').split('\n')[:-1]
for row in docker_info:
    docker_info_dict = {}
    docker_info_dict['dcoker_port']=row.split(' ')[0]
    docker_info_dict['docker_container_id'] = row.split(' ')[1]
    docker_info_dict['dcoker_image_id'] = row.split(' ')[2]
    print(docker_info_dict)


# {'dcoker_port': '5188', 'docker_container_id': 'd69a0f80a4d2', 'dcoker_image_id': '78a959232'}
# {'dcoker_port': '5166', 'docker_container_id': '43958ff0fbaa', 'dcoker_image_id': '78a959232453'}
python獲取docker信息

 

6.2 登陸宿主機 獲取宿主機kvm虛擬機信息

 

cat /sys/class/net/vnet*/address  #查看到全部虛擬機的網卡mac地址

 

6.3.ESXI物理機的掃描

pyVmomi模塊 

 

 

3、Ansible模塊執行自動化任務

自動化任務能夠提高運維效率、避免人爲操做錯誤;

Ansible是Python中一套模塊、能夠基於Unix平臺作系統管理、自動化批量命令、定時任務執行等功能,注意本文基於ansible 2.6.3;

 

 

那麼Ansible有什麼優點呢?我能夠經過paramiko+線程作自動化、批量執行任務啊!

Ansible是python中一套比較完整現成的模塊而且兼容不一樣系統例如 EXSI、docker多進程併發;

Ansible包含衆多子模塊 包含shell、定時任務、用戶管理、MySQL直接鏈接管理;

pip intstall ansible  #安裝Ansible

 

[root@cmdb ansible]# ansible --version 
ansible 2.6.3
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/usr/share/my_modules']
  ansible python module location = /usr/local/python3/lib/python3.6/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.6.1 (default, Mar 15 2018, 14:09:21) [GCC 4.4.7 20120313 (Red Hat 4.4.7-18)]
[root@cmdb ansible]# 

 

 1.Ansible的配置文件

/etc/ansible/ansible.cfg
1.0: 主配置文件

執行全局性、默認的配置文件例如:設置鏈接服務器的默認端口、用戶、併發數據量

/etc/ansible/hosts
1.1:默認主機資產清單文件

配置Ansible 鏈接主機、端口、用戶、密碼

[root@cmdb tmp]# export ANSIBLE_CONFIG=/tmp/ansible.cfg
[root@cmdb tmp]# ansible --version
ansible 2.6.3
  config file = /tmp/ansible.cfg
  configured module search path = ['/usr/share/my_modules']
  ansible python module location = /usr/local/python3/lib/python3.6/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.6.1 (default, Mar 15 2018, 14:09:21) [GCC 4.4.7 20120313 (Red Hat 4.4.7-18)]
[root@cmdb tmp]# export ANSIBLE_CONFIG=/etc/ansible/ansible.cfg 
[root@cmdb tmp]# ansible --version
ansible 2.6.3
  config file = /etc/ansible/ansible.cfg
1.2:更改Ansible默認配置文件路徑

PS:Ansible讀取主配置文件的優先級

export ANSIBLE_CONFIG=聲明的路徑

./ansible.cfg:當前執行ansible命令所在路徑 

~/ansible.cfg:用戶家目錄下尋找

/etc/ansible/ansible.cfg

 1.3:ansible.cfg文件詳解

inventory   = /etc/ansible/hosts        #資源清單文件的路徑
library = /usr/share/my_modules/ #ansible執行時加載的其餘子模塊
forks  = 10 #併發進程最大支持數量
sudo_user =root #設置命令執行的用戶
remote_port = 22 #執行命令時 默認鏈接端口
host_key_checking = True #設置第一次鏈接遠程主機的時候是否檢查主機的祕鑰
timeout = 30 #鏈接超時的時間
log_path = /var/log/ansible.log #ansible日誌的路徑
private_key_file=/path/to/file.pem #在使用ssh公鑰私鑰登陸系統時候,使用的密鑰路徑。

更多

1.4:hosts文件配置

hosts配置文件主要記錄 遠程主機IP、ansible_sudo_user、ansible_sudo_pass

[Hytest]                      #主機組
10.150.29.163 ansible_sudo_pass='Best@123'  #使用ansible.cfg中默認的用戶、密碼 
10.150.29.155 ansible_sudo_pass='Best@123'
10.150.29.154 ansible_sudo_pass='Best@123'
10.150.29.162 ansible_sudo_pass='Best@123'
10.150.29.157 ansible_sudo_pass='Best@123'
10.150.29.156 ansible_sudo_pass='Best@123'
10.150.29.160 ansible_sudo_pass='Best@123'
10.150.29.161 ansible_sudo_pass='Best@123'
10.150.29.164 ansible_sudo_pass='Best@123'
10.150.29.158 ansible_sudo_pass='Best@123'
10.150.29.159 ansible_sudo_pass='Best@123'
10.150.29.165 ansible_sudo_pass='Best@123'
10.150.29.152 ansible_sudo_pass='Best@123'

 

二、Ansible經常使用命令

[root@cmdb ansible]# ansible --version                     #查看Ansible相關信息

ansible 2.6.3
config file = /etc/ansible/ansible.cfg
configured module search path = ['/usr/share/my_modules']
ansible python module location = /usr/local/python3/lib/python3.6/site-packages/ansible
executable location = /usr/bin/ansible
python version = 3.6.1 (default, Mar 15 2018, 14:09:21) [GCC 4.4.7 20120313 (Red Hat 4.4.7-18)]

[root@cmdb ansible]# ansible all --list-hosts        #列出全部能夠遠程登陸的遠程主機(不區分主機組)
[root@cmdb ansible]# ansible Hytest --list-hosts     #列出某個主機組的主機
ansible all -a 'ls'                                  #批量執行命令

 

3:Ansible的ad-hoc模式

在Ansible中一共有兩種模式分別是:ad-hoc模式 、 paybook模式

ad-hoc模式:   適用於短、簡、快的 任務執行場景(臨時命令);

paybook模式: 適用於命令比較複雜的 任務執行場景,任務能夠持久化保存成劇本;

 

ad-hoc模式的命令使用

ansible <host-pattern> [option] cmd

 

host-pattern:匹配IP地址或主機組支持正則表示式

[root@cmdb ~]# ansible Hytest -a 'ls'              #匹配組
[root@cmdb ~]# ansible 10.150.29.* -a 'ls'               #按IP作正則匹配

 配置別名

[Hybris]
zhanggen ansible_shh_ip=10.150.25.199 ansible_sudo_pass='Hybris$BS^_199'

執行

[root@cmdb ansible]# ansible zhangg* -a 'ls'           #按別名匹配執行

 

4: ad-hoc模式經常使用的模塊

 查看 Ansible ad-hoc模式所支持的模塊

[root@cmdb ansible]# ansible-doc -l

 

使用 -m 參數加載Ansible支持的模塊

[root@cmdb /]# ansible 192.168.1.18 -m shell -a "echo $HOSTNAME"  #加載 shell模塊   
[root@cmdb ~]# ansible test -m copy -a "src=/tmp/zhanggen.txt dest=/tmp/" -f 1 -l 192.168.1.18

-f 開啓1個進程 -l 從test機組中篩選主機
192.168.1.18 | SUCCESS => { "changed": false, "checksum": "3ee88a74d3722b336a69c428d226f731435c71ba", "dest": "/tmp/zhanggen.txt", "gid": 0, "group": "root", "mode": "0644", "owner": "root", "path": "/tmp/zhanggen.txt", "size": 7, "state": "file", "uid": 0 } [root@cmdb ~]#

 

setup模塊批量 獲取系統信息

[root@cmdb ~]# ansible test -m setup  -f 1 -l 192.168.1.18

-a  "filter=ansible_distribution" 添加過濾器

[root@cmdb ~]# ansible test -m setup -a "filter=ansible_distribution" -f 1 -l 192.168.1.18192.168.1.18 | SUCCESS => {
    "ansible_facts": {
        "ansible_distribution": "RedHat"
    },
    "changed": false
}
[root@cmdb ~]# 

 

yum模塊批量安裝應用

[root@cmdb ~]# ansible test -m yum -a "name=nginx state=present" -f 1 -l 192.168.1.18 
#state=present 若是已經安裝nginx則不會再進行安裝更新
#state=latest 比對安裝最新的版本
#state=removed yum remove

 

service模塊批量啓、停服務

[root@cmdb ~]# ansible test -m service -a "name=mysql state=restarted" -f 1 -l 192.168.1.18192.168.1.18 | SUCCESS => {
    "changed": true,
    "name": "mysql",
    "state": "started"
}

 

git模塊批量下載代碼

若是你開發了CMDB彙報客戶端,如何讓1000臺主機安裝上它呢?This is a way.

[root@cmdb ~]# ansible test -m git -a "repo=https://github.com/zhanggen3714/zhanggen_audit.git dest=/zhanggen/ version=First" -f 1 -l 192.168.1.18

 

 

5:playbook模式

 

什麼是Ansible的playbook模式?

 

playbook就是劇本的意思

play:定義主機的角色

task:定義的是具體執行的任務

playbook:1個playbook能夠包含N個play,1個play包含N個task。

 

相比 ad-hoc, playbook的優點?

a.功能比adhoc模式更全面; The Playbook mode is more powerfull than the Ad-hoc mode.

b.控制依賴 

c.展現直觀

d.持久使用

 

playbook的配置語法

A.基本使用

ansible-playbook playbook.yml [options] 

 生成劇本.yml配置文件

---
- hosts : 192.168.1.18
  remote_user : root
  vars :
      touch_file : zhanggen.txt
  tasks:
      - name : touch file
        shell : "touch /tmp/{{touch_file}}"

查看該劇本中可執行的主機

[root@cmdb ansible]# ansible-playbook -i hosts --list-hosts f1.yml 
playbook: f1.yml
  play #1 (192.168.1.18): 192.168.1.18    TAGS: []
    pattern: ['192.168.1.18']
    hosts (1):
      192.168.1.18

執行劇本

[root@cmdb ansible]# ansible-playbook -i hosts f1.yml  #-i 指定主機清單的路徑 劇本配置文件.yml
PLAY [192.168.1.18] ***************************************************************************************

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

TASK [touch file] *****************************************************************************************
 [WARNING]: Consider using the file module with state=touch rather than running touch.  If you need to use
command because file is insufficient you can add warn=False to this command task or set
command_warnings=False in ansible.cfg to get rid of this message.

changed: [192.168.1.18]

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

 

六、playbook的使用

語法

yaml文件以 「---」做爲文檔的開始的標誌;

區分大小寫;

使用空白符縮進表示層級關係(只能使用 空格 不能是table鍵),能夠是 空格個數不限能夠是4個空格能夠是1個;

 

yaml支持的數據類型

字典: {name:zhanggen }

列表:-Apple -Orange -Strawberry -Mango 

數字、布爾、字符串

 

 

yaml格式轉成json格式

 

 點我嘛~

 

 

 

Playbook劇本中變量的 定義方式

 

A.在劇本中引用

myname:zhanggen   name:"{{ myname }}"

 

B.extra-vars執行參數  賦值給劇中 指定變量

每次都把變量定義在文件裏面這也太費勁了,因而--extra參數出現了;

[root@cmdb ansible]# ansible-playbook -i hosts f1.yml --extra-vars "touch_file=aaa"

 

C.經過在資產清單文件(hosts)中定義變量

[test]
192.168.1.18
10.150.22.211

[test:vars]
touch_file=whatdidIsay
/etc/ansibl/hosts

 

D.regist關機鍵字 獲取1個指定命令的 輸出結果到 1個自定義變量中

---
- hosts : 192.168.1.18
  remote_user : root
  vars :
      touch_file : zhanggen.txt
  tasks:
      - name : get_current_time
        command : date
        register: current_time #把 date命令的輸出結果 聲明爲變量current_time
      - name : touch file
        shell: "echo {{current_time.stdout}}>/tmp/{{touch_file}}" #把current_time 輸出到 文件中!
 

 

 playbook中的條件判斷、循環語句

playbook不只支持變量的聲明、還支持條件判斷和循環語句

 

when條件判斷

---
- hosts : 192.168.1.18
  remote_user : root
  tasks:
  - name : "touch_file"
    command : "touch /tmp/this_is_{{ansible_distribution}}_system"
    when : (ansible_distribution == "RedHat" and 1 == 1) or (ansible_distribution == "CentOS" and 1 == 1)

 

循環語句

 

 

with_items循環列表

---
- hosts : 192.168.1.18
  remote_user : root
  tasks:
  - name : add_server_user
    user : name={{ item.name }} state=present groups={{ item.groups }} #加載user模塊添加2個用戶:test_user01--->whee組 test_user02--->root組
    with_items:
      - { name: 'test_user01', groups: 'wheel'}        #循環列表 - { name: 'test_user02', groups: 'root'}

 

with_dict 循環字典

---
- hosts : 192.168.1.18
  remote_user : root
  tasks:
  - name : add_server_user
    user : name={{ item.key }} state=present groups={{ item.value }}  #key value
    with_dict:                                                     
      {'test_user01':'wheel','test_user02':'root'}

 

 with_fileglob 循環目錄下的文件

---
- hosts : 192.168.1.18
  remote_user : root
  tasks:
    - file : dest=/tmp/ state=directory    #加載文件模塊
    - copy : src={{item}} dest=/tmp/ owner=root mode=600  #設置源文件路徑 目標主機文件路徑 屬組 權限
      with_fileglob:                      #設置循環的路徑
        - /tmp/*  
[root@cmdb ansible]# ansible-playbook f1.yml 
[DEPRECATION WARNING]: DEFAULT_SUDO_USER option, In favor of Ansible Become, which is a generic framework. See become_user. , use 
become instead. This feature will be removed in version 2.8. Deprecation warnings can be disabled by setting 
deprecation_warnings=False in ansible.cfg.

PLAY [192.168.1.18] ***************************************************************************************************************

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

TASK [file] ***********************************************************************************************************************
ok: [192.168.1.18]

TASK [copy] ***********************************************************************************************************************
changed: [192.168.1.18] => (item=/tmp/zhanggen)
changed: [192.168.1.18] => (item=/tmp/yum_save_tx-2018-12-19-15-24PpuYlP.yumtx)
changed: [192.168.1.18] => (item=/tmp/yum_save_tx-2018-12-19-15-27baIMAT.yumtx)
changed: [192.168.1.18] => (item=/tmp/ansible.cfg)
changed: [192.168.1.18] => (item=/tmp/yum_save_tx-2018-12-19-16-179EqSv3.yumtx)
changed: [192.168.1.18] => (item=/tmp/yum_save_tx-2018-12-19-15-16eArxQ9.yumtx)
changed: [192.168.1.18] => (item=/tmp/yum_save_tx-2018-12-19-16-000PcZKT.yumtx)
changed: [192.168.1.18] => (item=/tmp/zhanggen.txt)
changed: [192.168.1.18] => (item=/tmp/yum_save_tx-2018-12-19-16-16zpp5v3.yumtx)

PLAY RECAP ************************************************************************************************************************
192.168.1.18               : ok=3    changed=1    unreachable=0    failed=0   
執行過程

 

循環+判斷混合

---
- hosts : 192.168.1.18
  remote_user : root
  tasks:
    - debug: msg="{{item.key}}"     #debug模式打印
      with_dict: { "zhanggen":{'math':25,'chinese':27},'Martin':{'englist':80,'chinese':90} }
      when : item.value.chinese >=60  #判斷
[root@cmdb ansible]# ansible-playbook f1.yml 

PLAY [192.168.1.18] ***************************************************************************************************************

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

TASK [debug] **********************************************************************************************************************
skipping: [192.168.1.18] => (item={'key': 'zhanggen', 'value': {'math': 25, 'chinese': 27}}) 
ok: [192.168.1.18] => (item={'key': 'Martin', 'value': {'englist': 80, 'chinese': 90}}) => {
    "msg": "Martin"
}

PLAY RECAP ************************************************************************************************************************
192.168.1.18               : ok=2    changed=0    unreachable=0    failed=0   

[root@cmdb ansible]# 
執行結果

 

ignore_errors異常處理

---
- hosts : 192.168.1.18
  remote_user : root
  tasks:
    - name: ignore false
      command: /bin/false
      ignore_errors : yes #處理異常錯誤
    - name: touch a file
      file: path=/tmp/test06 state=touch mode=0700 owner=root group=root

執行結果

[root@cmdb ansible]# ansible-playbook f1.yml 

PLAY [192.168.1.18] *******************************************************************************************************

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

TASK [ignore false] *******************************************************************************************************
fatal: [192.168.1.18]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.003266", "end": "2018-12-29 08:17:25.302094", "msg": "non-zero return code", "rc": 1, "start": "2018-12-29 08:17:25.298828", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring 處理掉錯誤

TASK [touch a file] *******************************************************************************************************
changed: [192.168.1.18]

PLAY RECAP ****************************************************************************************************************
192.168.1.18               : ok=3    changed=2    unreachable=0    failed=0   

 

failed_when 根據條件判斷主動拋出異常

---
- hosts: 192.168.1.18
  remote_user: root
  tasks:
    - name: get_process
      shell: ps -ef|wc -l
      register: process_count
    #- debug: msg="{{process_count.stdout}}"   
      failed_when: process_count.stdout|int > 3     #進程數據量大於 3 拋出異常,小於三 往下進行
    - name: touch_a_file
      file: path=/tmp/test06 state=touch mode=0700 owner=root group=root

 

 changed_when: false 隱藏前端輸出的changed信息

---
- hosts: 192.168.1.18
  remote_user: root
  tasks:
    - name: get_process
      shell: touch /tmp/change_test
      changed_when: false
[root@cmdb ansible]# ansible-playbook f1.yml 
[DEPRECATION WARNING]: DEFAULT_SUDO_USER option, In favor of Ansible Become, which is a generic framework. See 
become_user. , use become instead. This feature will be removed in version 2.8. Deprecation warnings can be disabled by 
setting deprecation_warnings=False in ansible.cfg.

PLAY [192.168.1.18] *******************************************************************************************************

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

TASK [get_process] ********************************************************************************************************
 [WARNING]: Consider using the file module with state=touch rather than running touch.  If you need to use command because
file is insufficient you can add warn=False to this command task or set command_warnings=False in ansible.cfg to get rid
of this message.

ok: [192.168.1.18]

PLAY RECAP ****************************************************************************************************************
192.168.1.18               : ok=2    changed=0    unreachable=0    failed=0   
執行結果

 

7.playbooks標籤的使用

 playbook中的tasks是由1個個子任務(name)組成的,咱們能夠經過對這些子任務打標籤的方式控制 執行哪些子任務,不執行哪些子任務!

 

7.0:給playbooks中的name子任務打好標籤

---
- hosts: 192.168.1.18
  remote_user: root
  tasks:
    - name: create_file1 0 1
      shell: touch /tmp/file1.txt
      tags:
      - cfile0 - cfile1
    - name: create_file2 2
      shell: touch /tmp/file2.txt
      tags:
       - cfile2

 

7.1: -t 指定執行那些cfile2子任務

root@cmdb ansible]# ansible-playbook f1.yml -t cfile2

 

7.2:--skip-tags指定跳過那些子任務

[root@cmdb ansible]# ansible-playbook f1.yml --skip-tags cfile2

 

8.playbook中的include語法

include方法能夠把playbook分佈式存放,提升靈活性,功能相似 C中include python中 import 語法

---
- hosts: 192.168.1.18
  remote_user: root
  tasks:
  - include_tasks: /tmp/touchf1.yml
   - include_tasks: /tmp/touchf2.yml
---
- name: createfile1
  shell: touch /tmp/file1.txt
/tmp/touchf1.yml
---
- name: createfile1
  shell: touch /tmp/file2.txt
/tmp/touchf2.yml

 

 

 4、Python調用Ansible的API

 0.Ansible python API的6個類

from ansible.parsing.dataloader import DataLoader  # 用於讀取yaml、json格式的文件
from ansible.vars.manager import VariableManager   # 讀取host中變量信息
from ansible.inventory.manager import InventoryManager # 導入資產文件
from ansible.playbook.play import Play              #存儲hosts的角色信息
from ansible.executor.task_queue_manager import TaskQueueManager #ansibile 底層調用到得任務隊列
from ansible.plugins.callback import CallbackBase               #狀回調態

 

1.資源資產配置清單操做

from ansible.parsing.dataloader import DataLoader  # 用於讀取yaml、json格式的文件
from ansible.vars.manager import VariableManager   # 讀取host中變量信息
from ansible.inventory.manager import InventoryManager # 導入資產文件
from ansible.playbook.play import Play              #存儲hosts的角色信息
from ansible.executor.task_queue_manager import TaskQueueManager #ansibile 底層調用到得任務隊列
from ansible.plugins.callback import CallbackBase               #狀回調態

#InventoryManager:操做host主機清單中的主機信息
loader=DataLoader()
inventory=InventoryManager(loader=loader,sources=['/etc/ansible/hosts'])
# print(inventory.get_groups_dict()) #查看host信息 (主機組---對應的機器)
# print(inventory.get_hosts()) #查看全部主機IP
# print(inventory.get_host('192.168.1.18')) #篩選查看單個主機
# inventory.add_host(host='8.8.8.8',port=22,group='test') #在現有主機中添加主機

# VariableManager:操做host主機清單中的變量信息
VM= VariableManager(loader=loader,inventory=inventory)
host=inventory.get_host('192.168.1.18')
VM.get_vars() #查看變量
VM.set_host_variable(host=host,varname='ansible_ssh_pass',value='xxxxxx1234') #設置單個主機的變量信息,host對象必須爲對象
VM.extra_vars={'extra_variable01':1,'extra_variable02':2,}                #設置擴展全局變量

 

 2.ad-hoc模式調用

 python3.6.1 ---> ansible 2.6.3

from collections import namedtuple
from ansible.executor.task_queue_manager import TaskQueueManager  #經過調用
from ansible.inventory.manager import InventoryManager  # 導入資產文件
from ansible.parsing.dataloader import DataLoader  # 用於讀取yaml、json格式的文件
from ansible.playbook.play import Play  # 存儲hosts的角色信息
from ansible.vars.manager import VariableManager  # 讀取host中變量信息


loader = DataLoader()
inventory = InventoryManager(loader=loader, sources=['/etc/ansible/hosts'])
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', 'listtags', 'sudo', 'syntax',
                      'sudouser',
                      'diff'])
options = Options(connection='smart', remote_user=None, ask_sudo_pass=False,ack_pass=None,sudo=None,sudouser=None,
                  module_path=None, forks=100, become=None, become_method=None,
                  become_user=None, check=False, diff=False, syntax=None, listtags=None, listhosts=None, verbosity=5)

# play執行對象和模塊
play_source = dict(
    name="Ansible Play ad-hoc test",
    hosts='192.168.1.18,',           #執行任務的主機 多個以,隔開
    gather_facts='no',                # 執行任務以前去獲取基本信息
    tasks=[                            # 加載模塊
        dict(action=dict(module='shell', args='ls'), register='shell_out'),         #1個任務1個字典
        dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}')))    #2個任務2個字典
    ]
)

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,
    # stdout_callback=results_callback,  # Use our custom callback instead of the ``default`` callback plugin
)
rest = tqm.run(play=play)

 

3.playbook模式調用

 

from collections import namedtuple
from ansible.executor.playbook_executor import PlaybookExecutor  # PlaybookExecutor 調用執行ansible的playbook 模式
from ansible.inventory.manager import InventoryManager  # 導入資產文件
from ansible.parsing.dataloader import DataLoader  # 用於讀取yaml、json格式的文件
from ansible.vars.manager import VariableManager  # 讀取host中變量信息

loader = DataLoader()
inventory = InventoryManager(loader=loader, sources=['/etc/ansible/hosts'])
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', 'sudo', 'syntax',
                      'sudouser', 'diff'])
options = Options(connection='smart', remote_user=None, ask_sudo_pass=False, ack_pass=None, sudo=None, sudouser=None,
                  module_path=None, forks=100, become=None, become_method=None,
                  become_user=None, check=False, diff=False, syntax=None, listtags=None,listtasks=None,listhosts=None, verbosity=5) # listtasks

passwords = dict()  # 密碼

# 執行 ansible的 playbook模式就須要 使用
play_book = PlaybookExecutor(playbooks=['/etc/ansible/f1.yml'],inventory=inventory, variable_manager=variable_manager,
                            loader=loader, options=options, passwords=passwords)
play_book.run()

 

4. 重寫 CallbackBase自定製ansible輸出json格式數據

from collections import namedtuple
from ansible.executor.task_queue_manager import TaskQueueManager  #經過TaskQueueManager調用ansible的ad-hoc模式
from ansible.inventory.manager import InventoryManager  # 導入資產文件
from ansible.parsing.dataloader import DataLoader  # 用於讀取yaml、json格式的文件
from ansible.playbook.play import Play  # 存儲hosts的角色信息
from ansible.vars.manager import VariableManager  # 讀取host中變量信息


loader = DataLoader()
inventory = InventoryManager(loader=loader, sources=['/etc/ansible/hosts'])
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', 'listtags', 'sudo', 'syntax',
                      'sudouser',
                      'diff'])
options = Options(connection='smart', remote_user=None, ask_sudo_pass=False,ack_pass=None,sudo=None,sudouser=None,
                  module_path=None, forks=100, become=None, become_method=None,
                  become_user=None, check=False, diff=False, syntax=None, listtags=None, listhosts=None, verbosity=5)

# play執行對象和模塊
play_source = dict(
    name="Ansible Play ad-hoc test",
    hosts='192.168.1.18,',           #執行任務的主機 多個以,隔開
    gather_facts='no',                # 執行任務以前去獲取基本信息
    tasks=[                            # 加載模塊
        dict(action=dict(module='shell', args='ls'), register='shell_out'),         #1個任務1個字典
        dict(action=dict(module='debug', args=dict(msg='{{shell_out.stdout}}')))    #2個任務2個字典
    ]
)

play = Play().load(play_source, variable_manager=variable_manager, loader=loader)

passwords = dict()#密碼

from ansible.plugins.callback import CallbackBase


# 重寫CallbackBas類定製 ansible 輸出格式
class MyCallback(CallbackBase):
    def __init__(self,*args,**kwargs):
        super(CallbackBase,self).__init__(*args,**kwargs)
        self.host_ok={}
        self.host_uncreachable={}
        self.host_failed={}

    def v2_runner_on_unreachable(self, result):
        self.host_uncreachable[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, ignore_errors=False):
        self.host_failed[result._host.get_name()] = result

my_callback=MyCallback()

tqm = TaskQueueManager( #運行
    inventory=inventory,
    variable_manager=variable_manager,
    loader=loader,
    options=options,
    passwords=passwords,
    stdout_callback=my_callback,  # Use our custom callback instead of the ``default`` callback plugin
)
tqm.run(play=play)

#從 mycallback對象中 獲取執行結果
resault={'success':{},'failed':{},'uncreachable':{}}

for h,r in my_callback.host_ok.items():
    print(h,r)
    resault['success'][h]=r._result

for h,r in my_callback.host_failed.items():
    resault['failed'][h]=r._result

for h,r in my_callback.host_uncreachable.items():
    resault['uncreachable'][h]=r._result

print(resault)

 

 

 

 

 

 

 

GitHub地址

相關文章
相關標籤/搜索