顯示具有 Ansible 標籤的文章。 顯示所有文章
顯示具有 Ansible 標籤的文章。 顯示所有文章

2019年8月29日 星期四

Packer build image on AWS - Part III

Packer integration with Ansible

Pre-requirement

Don't forget to install ansible
  • Install pip
# apt-get install python-pip
  • Install ansible
# pip install ansible==2.8.3
  • Check ansible version
# ansible --version
ansible 2.8.3

Create Ansible Directory

Packer
├── ISO_Ubuntu_Server_xenial_16.04.6.json
├── ansible
│   ├── all.yml
│   ├── ansible.cfg
│   └── roles
│       └── install-offical-nginx
│           ├── README.md
│           ├── defaults
│           │   └── main.yml
│           ├── files
│           ├── handlers
│           │   └── main.yml
│           ├── meta
│           │   └── main.yml
│           ├── tasks
│           │   └── main.yml
│           ├── templates
│           ├── tests
│           │   ├── inventory
│           │   └── test.yml
│           └── vars
│               └── main.yml
├── http
│   └── preseed.cfg
└── output

13 directories, 12 files
  • Check ansible.cfg file
[defaults]
inventory      = ./inventory
roles_path      = ./roles
host_key_checking = False
retry_files_enabled = False
gathering = smart

fact_caching = jsonfile
fact_caching_connection = ./cache
fact_caching_timeout = 60

#strategy = mitogen_linear
#strategy_plugins = ./mitogen/ansible_mitogen/plugins/strategy/

callback_whitelist = profile_tasks
[callback_profile_tasks]
task_output_limit = 60


[privilege_escalation]
become=True
become_user=root
  • Check all.yml file
---
- hosts: all
  become: True
  roles:
  - install-offical-nginx
  • Check ISO_Ubuntu_Server_xenial_16.04.6.json file
{
  "variables":{
  "vm_description": "Ubuntu Server Image",
  "vm_version": "0.0.1",
  "cpus": "2",
  "memory": "2048",
  "disk_size": "8192",
  "vm_name": "ubuntu",
  "iso_url": "http://ftp.ubuntu-tw.org/mirror/ubuntu-releases/16.04.6/ubuntu-16.04.6-server-amd64.iso",
  "iso_checksum": "16afb1375372c57471ea5e29803a89a5a6bd1f6aabea2e5e34ac1ab7eb9786ac",
  "iso_checksum_type": "sha256",
  "ssh_username": "ubuntu",
  "ssh_password": "ubuntu",
  "s3_bucket_name": "packer-images"
  },
  "provisioners": [
    {
      "type": "ansible",
      "user": "ubuntu",
      "playbook_file": "./ansible/all.yml"
    }
  ],
  "builders": [
    {
      "type": "virtualbox-iso",
      "output_directory": "builds",
      "format": "ova",
      "guest_os_type": "Ubuntu_64",
      "iso_url": "{{user `iso_url`}}",
      "iso_checksum": "{{user `iso_checksum`}}",
      "iso_checksum_type": "{{user `iso_checksum_type`}}",
      "ssh_username": "{{user `ssh_username`}}",
      "ssh_password": "{{user `ssh_password`}}",
      "ssh_port": 22,
      "ssh_wait_timeout": "2000s",
      "disk_size": "{{user `disk_size`}}",
      "keep_registered": "true",
      "shutdown_command": "echo {{user `ssh_password`}} | sudo -S shutdown -P now",
      "vboxmanage": [
        ["modifyvm", "{{.Name}}", "--cpus", "{{user `cpus`}}"],
        ["modifyvm", "{{.Name}}", "--memory", "{{user `memory`}}"]
      ],
      "http_directory": "./http/",
      "boot_wait": "10s",
      "boot_command": [
        "<enter><wait><f6><esc><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
        "<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
        "<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
        "<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
        " /install/vmlinuz<wait>",
        " noapic<wait>",
        " preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg auto<wait>",
        " locale=en_US<wait>",
        " kbd-chooser/method=us<wait>",
        " keyboard-configuration/modelcode=pc105<wait>",
        " keyboard-configuration/layout=US<wait>",
        " keyboard-configuration/variant=US<wait>",
        " netcfg/get_hostname=ubuntu<wait>",
        " fb=false <wait>",
        " debconf/frontend=noninteractive<wait>",
        " console-setup/ask_detect=false<wait>",
        " initrd=/install/initrd.gz -- <wait>",
        "<enter><wait>"
      ]
    }
  ],
  "post-processors": [
    {
      "type": "amazon-import",
      "keep_input_artifact": true,
      "s3_bucket_name": "{{user `s3_bucket_name`}}",
      "ami_name": "ubuntu-16.04.6",
      "license_type": "BYOL",
      "tags": {
        "Description": "Packer Import "
      }
    }
  ]
}

Check ISO_Ubuntu_Server_xenial_16.04.6.json is validated via Packer

  • Check the file is validate via Packer CLI
# packer validate ISO_Ubuntu_Server_xenial_16.04.6.json
Template validated successfully.
You can build right now.

2019年8月5日 星期一

Ansible Failed - Failed to lock apt for exclusive operation

Manage Node

  • System Information
ProductName:    Mac OS X
ProductVersion: 10.14.5
BuildVersion:   18F132
  • Ansible Verison
ansible 2.8.3
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/Users/nobody/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /Library/Python/2.7/site-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 2.7.10 (default, Feb 22 2019, 21:55:15) [GCC 4.2.1 Compatible Apple LLVM 10.0.1 (clang-1001.0.37.14)]

Remote Node

  • System Information
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.6 LTS
Release:    16.04
Codename:   xenial

Playbook

---
- hosts: test
  become: True
  roles:
    - { role: common }

Roles

# tree roles/common
roles/common
├── README.md
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── tasks
│   ├── install_packages.yml
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

8 directories, 9 files
cat roles/common/tasks/install_packages.yml
---
- name: Apt Update
  apt:
    force_apt_get: yes
    update_cache: yes
    cache_valid_time: 3600


- name: Ensure install software-properties-common
  apt:
    name: software-properties-common
    state: present
    force_apt_get: yes

Error Messages

  • First error message
[WARNING]: Updating cache and auto-installing missing dependency: python-apt
  • Fixed first error
login remote node
$ sudo apt-get isntall -y python-apt
  • Second error error
Failed to lock apt for exclusive operation
  • Fixed second error
Add parameter to apt task
cache_valid_time: 3600

2019年7月22日 星期一

Ansible 判斷空字串

Ansible Tips

  • 判斷空字串
- name: Do something with my_var.
  shell: "check do_something_with {{ my_var }}"
  when: my_var != ''
  • 舊方法
    when: my_var != ''
    使用 ansible-lint 會噴警告
    [602] Don't compare to empty string
    /roles/projects/tasks/main.yml:195
            - my_var.stdout != ""
  • 新方法
    when: my_var | length > 0
    除了上面講的新方法,還可以用另外一招,就是使用 .ansible-lint,將上述警告的代碼 602 加入至此檔案,加入後再次執行 ansible-lint 就不會在噴警告了。
Reference:

2017年7月17日 星期一

Cisco ASA - paramiko is required but does not appear to be installed

最近在試 Cisco ASA 5512X 這個型號,就想說能不能用 Ansible 來管設定,所以就先從簡單的 show version 的指令開始測試。
OS / ENVIRONMENT
macOS Sierra
Version 10.12.5
ANSIBLE VERSION
ansible 2.3.1.0
  config file =
  configured module search path = Default w/o overrides
  python version = 2.7.13 (default, Apr  4 2017, 08:46:44) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)]
ANSIBLE CONFIGURATION
ansible inventory - hosts
asa           ansible_host=192.168.1.1   
---
- hosts: asa
  connection: local
  gather_facts: yes
  tasks:
    - name: run show version on remoter devices
      asa_command:
        provider:
          host: IP
          username: USERNAME
          password: PASSWORD
          authorize: yes
          auth_pass: PASSWORD
          timeout: 30
        commands:
          - show version
      register: version
    - name: show version
      debug:
        var: version.stdout_lines
      with_items: version.results

STEPS TO REPRODUCE

ansible-playbook -i hosts asa.yml -vvv
No config file found; using defaults

PLAYBOOK: asa.yml *************************************************************************************************
1 plays in asa.yml

PLAY [cisco] ******************************************************************************************************
META: ran handlers

TASK [Show Version] ***********************************************************************************************
task path: /Users/daniel/work/tenmax/lab/asa.yml:6
Using module file /usr/local/lib/python2.7/site-packages/ansible/modules/network/asa/asa_command.py
 ESTABLISH LOCAL CONNECTION FOR USER: daniel
 EXEC /bin/sh -c 'echo ~ && sleep 0'
 EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /Users/daniel/.ansible/tmp/ansible-tmp-1500340664.8-207253128376700 `" && echo ansible-tmp-1500340664.8-207253128376700="` echo /Users/daniel/.ansible/tmp/ansible-tmp-1500340664.8-207253128376700 `" ) && sleep 0'
 PUT /var/folders/5w/tkr8l6gn7zs76_8n1z6jg_r80000gn/T/tmpMpIKV3 TO /Users/daniel/.ansible/tmp/ansible-tmp-1500340664.8-207253128376700/asa_command.py
 EXEC /bin/sh -c 'chmod u+x /Users/daniel/.ansible/tmp/ansible-tmp-1500340664.8-207253128376700/ /Users/daniel/.ansible/tmp/ansible-tmp-1500340664.8-207253128376700/asa_command.py && sleep 0'
 EXEC /bin/sh -c '/usr/bin/python /Users/daniel/.ansible/tmp/ansible-tmp-1500340664.8-207253128376700/asa_command.py; rm -rf "/Users/daniel/.ansible/tmp/ansible-tmp-1500340664.8-207253128376700/" > /dev/null 2>&1 && sleep 0'
fatal: [cisco]: FAILED! => {
    "changed": false,
    "failed": true,
    "invocation": {
        "module_args": {
            "auth_pass": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "authorize": true,
            "commands": [
                "show version"
            ],
            "context": null,
            "host": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "interval": 1,
            "match": "all",
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "port": null,
            "provider": {
                "auth_pass": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                "authorize": true,
                "host": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                "username": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
            },
            "retries": 10,
            "ssh_keyfile": null,
            "timeout": 10,
            "transport": null,
            "username": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "wait_for": null
        }
    },
    "msg": "paramiko is required but does not appear to be installed.  It can be installed using  `pip install paramiko`"
}
    to retry, use: --limit @/Users/daniel/work/tenmax/lab/asa.retry

PLAY RECAP ********************************************************************************************************
cisco                      : ok=0    changed=0    unreachable=0    failed=1
執行後,會看到有錯誤 
"msg": "paramiko is required but does not appear to be installed.  It can be installed using  `pip install paramiko`"
實際上,我已經裝了,後來詢問谷歌大神後,發現會出現這樣的問題原因是,有可能你的作業系統裡,有安裝多個不同的版本的 Python ,所以要解決這個問題的話,就是去指定你的Pythonn解釋器,目前ansible都還是以Python2.X版的為主,接下來在 inventory file裡面去新增 ansible_python_interpreter,這樣就解決了。
asa           ansible_host=192.168.1.1     ansible_python_interpreter=/usr/bin/python 
Reference:

Cisco ASA timeout trying to send command: enable

Same issue here with asa_command

SUMMARY

簡單地說,就是目前還不能用,我已經有發issue給ansible了,詳請可以參考下面的鏈結
ISSUE TYPE
  • Bug Report
COMPONENT NAME
  • asa_command
ANSIBLE VERSION
ansible 2.3.1.0
  config file =
  configured module search path = Default w/o overrides
  python version = 2.7.13 (default, Apr  4 2017, 08:46:44) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)]
CONFIGURATION
hostsasa ansible_host=192.168.1.1 ansible_python_interpreter=/usr/bin/python 
---
- hosts: asa
  connection: local
  gather_facts: yes
  tasks:
    - name: run show version on remoter devices
      asa_command:
        provider:
          host: IP
          username: USERNAME
          password: PASSWORD
          authorize: yes
          auth_pass: PASSWORD
          timeout: 30
        commands:
          - show version
      register: version
    - name: show version
      debug:
        var: version.stdout_lines
      with_items: version.results
OS / ENVIRONMENT
Darwin Danielde-MacBook-Pro.local 15.6.0 Darwin Kernel Version 15.6.0: Tue Apr 11 16:00:51 PDT 2017; root:xnu-3248.60.11.5.3~1/RELEASE_X86_64 x86_64
STEPS TO REPRODUCE
$ ansible-playbook -i hosts asa.yml -vvv
No config file found; using defaults

PLAYBOOK: asa.yml *************************************************************************************************************
1 plays in asa.yml

PLAY [asa] ********************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************
Using module file /usr/local/lib/python2.7/site-packages/ansible/modules/system/setup.py
<192 .168.1.1=""> ESTABLISH LOCAL CONNECTION FOR USER: daniel
<192 .168.1.1=""> EXEC /bin/sh -c 'echo ~ && sleep 0'
<192 .168.1.1=""> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /Users/daniel/.ansible/tmp/ansible-tmp-1500304102.91-122764280426260 `" && echo ansible-tmp-1500304102.91-122764280426260="` echo /Users/daniel/.ansible/tmp/ansible-tmp-1500304102.91-122764280426260 `" ) && sleep 0'
<192 .168.1.1=""> PUT /var/folders/03/ns9kvh215g12x_h6gyq7f7tr0000gn/T/tmpGAqiRu TO /Users/daniel/.ansible/tmp/ansible-tmp-1500304102.91-122764280426260/setup.py
<192 .168.1.1=""> EXEC /bin/sh -c 'chmod u+x /Users/daniel/.ansible/tmp/ansible-tmp-1500304102.91-122764280426260/ /Users/daniel/.ansible/tmp/ansible-tmp-1500304102.91-122764280426260/setup.py && sleep 0'
<192 .168.1.1=""> EXEC /bin/sh -c '/usr/local/bin/python /Users/daniel/.ansible/tmp/ansible-tmp-1500304102.91-122764280426260/setup.py; rm -rf "/Users/daniel/.ansible/tmp/ansible-tmp-1500304102.91-122764280426260/" > /dev/null 2>&1 && sleep 0'
ok: [asa]
META: ran handlers

TASK [run show version on remoter devices] ************************************************************************************
task path: /Users/daniel/work/lab/asa.yml:6
Using module file /usr/local/lib/python2.7/site-packages/ansible/modules/network/asa/asa_command.py
<192 .168.1.1=""> ESTABLISH LOCAL CONNECTION FOR USER: daniel
<192 .168.1.1=""> EXEC /bin/sh -c 'echo ~ && sleep 0'
<192 .168.1.1=""> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /Users/daniel/.ansible/tmp/ansible-tmp-1500304104.0-136124011056732 `" && echo ansible-tmp-1500304104.0-136124011056732="` echo /Users/daniel/.ansible/tmp/ansible-tmp-1500304104.0-136124011056732 `" ) && sleep 0'
<192 .168.1.1=""> PUT /var/folders/03/ns9kvh215g12x_h6gyq7f7tr0000gn/T/tmpdXRCx3 TO /Users/daniel/.ansible/tmp/ansible-tmp-1500304104.0-136124011056732/asa_command.py
<192 .168.1.1=""> EXEC /bin/sh -c 'chmod u+x /Users/daniel/.ansible/tmp/ansible-tmp-1500304104.0-136124011056732/ /Users/daniel/.ansible/tmp/ansible-tmp-1500304104.0-136124011056732/asa_command.py && sleep 0'
<192 .168.1.1=""> EXEC /bin/sh -c '/usr/local/bin/python /Users/daniel/.ansible/tmp/ansible-tmp-1500304104.0-136124011056732/asa_command.py; rm -rf "/Users/daniel/.ansible/tmp/ansible-tmp-1500304104.0-136124011056732/" > /dev/null 2>&1 && sleep 0'
fatal: [asa]: FAILED! => {
    "changed": false,
    "failed": true,
    "invocation": {
        "module_args": {
            "auth_pass": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "authorize": true,
            "commands": [
                "show version"
            ],
            "context": null,
            "host": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "interval": 1,
            "match": "all",
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "port": null,
            "provider": {
                "auth_pass": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                "authorize": true,
                "host": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                "timeout": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                "username": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
            },
            "retries": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "ssh_keyfile": null,
            "timeout": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "transport": null,
            "username": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "wait_for": null
        }
    },
    "msg": "timeout trying to send command: enable"
}
    to retry, use: --limit @/Users/daniel/work/lab/asa.retry

PLAY RECAP ********************************************************************************************************************
asa                        : ok=1    changed=0    unreachable=0    failed=1
How to fix this issue ?
Reference:

2017年7月7日 星期五

透過 Ansible 來執行 Cisco Router 的指令 (簡易版)

OS Environment

macOS Sierra
version 10.12.5

Ansible Version

ansible 2.3.1.0
  config file =
  configured module search path = Default w/o overrides
  python version = 2.7.13 (default, Dec 18 2016, 07:03:39) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)]

cisco.yml

---
- hosts: cisco
  connection: local
  gather_facts: yes
  tasks:
    - name: run show version on remoter devices
      ios_command:
        provider:
          host: FQDN or IP
          username: 使用者
          password: ssh的連線密碼
          authorize: yes
          auth_pass: 特權模式密碼
        commands:
          - show version
      register: version
    - name: show version
      debug:
        var: version.stdout_lines
      with_items: version.results
authorize 跟 auth_pass 要一起使用,因為這是要進入 特權模式
重點還是要看官方的用法,下面只是參考而已,有些寫法未來可能會被拔掉
這是我執行某一個寫法的時候吐的訊息
 [WARNING]: argument username has been deprecated and will be removed in a future version

 [WARNING]: argument host has been deprecated and will be removed in a future version

 [WARNING]: argument password has been deprecated and will be removed in a future version
Reference:

2017年2月18日 星期六

使用 Register 自定二個變數,要在同一個 task 裡去執行

OS Environment

CentOS Linux release 7.3.1611 (Core)

Ansible Version

ansible 2.2.0.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides

task.yml

- name: Get Blob Name Path
  shell: az storage blob list -o table -c {{ BLOB_CONTAINER }} --account-name {{ backup_account }} --account-key {{ backup_key }} |  grep -Eo '{{restorebuildnumber.content}}.tar.gz|{{ restorebuildnumber.content }}/*/.*.gz'
  register: blobname

- name: Get Tar File Name
  shell: az storage blob list -o table -c {{ BLOB_CONTAINER }} --account-name {{ backup_account }} --account-key {{ backup_key }} |  grep -Eo '{{restorebuildnumber.content}}.tar.gz|{{ restorebuildnumber.content }}/*/.*.gz' | cut -d'/' -f3
  register: tarfilename

- name: Download {{ restorebuildnumber.content }}.tar.gz
  shell: az storage blob download -c {{ BLOB_CONTAINER }} -n {{ item.0 }} -f /tmp/{{restorebuildnumber.content}}/{{ item.1 }} --account-name {{ backup_account }} --account-key {{ backup_key }}
  with_together:
    -  "{{ blobname.stdout_lines }}"
    -  "{{ tarfilename.stdout_lines }}"
這個的重點是用 with_together 就可以達成目的了
Reference:

使用『差集』來排除不需要的檔案

OS Environment

CentOS Linux release 7.3.1611 (Core)

Ansible Version

ansible 2.2.0.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides

使用情境說明

先去抓所有的tar檔後,註冊一個變數AllTarFileName,再echo需要排除的檔名,並且也把它註冊成一個變數TarName,之後就可以在解tar檔時,使用差集的方式,將不需要的檔案做排除。

task.yml

- name: Get All Tar Files Name
  shell: az storage blob list -o table -c {{ BLOB_CONTAINER }} --account-name {{ BACKUP_ACCOUNT }} --account-key {{ BACKUP_KEY }} |  grep -Eo '{{RestoreBuildNumber.content}}.tar.gz|{{ RestoreBuildNumber.content }}/*/.*.gz' | cut -d'/' -f3
  register: AllTarFileName

- name: Get {{RestoreBuildNumber.content}}.tar.gz Name
  shell: echo '{{ RestoreBuildNumber.content }}.tar.gz'
  register: TarName

- name: Unarchive {{RestoreBuildNumber.content}}.tar.gz To /tmp/{{RestoreBuildNumber.content}}/data/
  shell: tar -zxvf /tmp/{{RestoreBuildNumber.content}}/{{item}} -C /tmp/{{RestoreBuildNumber.content}}/data/
  with_items:
    - "{{TarName.stdout_lines }}"

- name: Unarchive All Archives Tar Files
  shell: tar -zxvf /tmp/{{RestoreBuildNumber.content}}/{{item}} -C /tmp/{{RestoreBuildNumber.content}}/backups/
  with_items:
    - "{{ AllTarFileName.stdout_lines | difference(TarName.stdout_lines) }}"
Reference:
感謝 Ansible Taiwan - Jim T. Tang 大大的建議。

2016年5月31日 星期二

Ansible 使用 mysql_db & mysql_user 模組

這次剛好有機會使用ansible的資料庫模組,所以就紀錄一下筆記

首先在官網 ansible_document ,點選 Module Index 這裡就有提供很多模組可以使用,這次我使用的是Database Modules,點進來後就找 mysql_db & mysql_user,這是我這次主要用的二個模組。
第一次建立資料庫無非就是下列四件事:
  1. 修改root密碼
  2. 新建資料庫
  3. 新建使用者
  4. 給使用者特定的權限
先介紹一下我使用的環境
SYSTEM VERSION

Control machine:CentOS Linux release 7.2.1511 (Core)
Remote machine: CentOS Linux release 7.1.1503 (Core)
ANSIBLE VERSION

ansible 2.1.0.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
STEPS TO REPRODUCE

---
- name: Setup | Percona XtraDB Cluster
  hosts: db
  tasks:
    - name: Setup | Percona yum Repository
      yum: name=http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm state=present

    - name: Setup | Install EPEL Repository
      yum: name=epel-release update_cache=yes state=present

    - name: Setup | Install Percona-XtraDB-Cluster-56 Package
      yum: name=Percona-XtraDB-Cluster-56 update_cache=yes state=present

    - name: Setup | Install Requirement Packages
      yum: name={{ item }} state=present  update_cache=yes
        # 裝這二個套件主要是要讓控制端主機要有MySQL的libary,這樣才能與遠端的主機裡的資料庫做溝通,如果沒有的話就會出現 "the python mysqldb module is required"
     with_items:
        - mysql-devel    # 本機端的libary
        - MySQL-python   # 給python用的libary

    - name: Setup | Create Mysql Data Directories
      file: path={{ item }} state=directory recurse=yes owner=mysql group=mysql mode=0755
      with_items:
        - /var/log/mysql

    - name: Setup | Mysql Configuration
      # 使用 Jinja2 的範本,來做設定檔的維護
      template: src=./templates/my_cnf_test.j2 dest=/etc/my.cnf
      # 這個變數會套進剛剛設定的my_cnf_test.j2
      vars:
        - gcomm_list: 192.168.1.100
      # notify 是用來觸發事件,通常會跟handlers一起使用,而且只會跑一次,在此劇本目前只會觸發二件事,一個啟動mysql service,另一個是更新root密碼
      notify:
        - restart_mysql
        - Update MySQL root password
        - Create Database

  # handlers 事件處理器,也就是被notify所調用
  handlers:
    - name: restart_mysql
      service: name=mysql@bootstrap.service  state=restarted

    - name: Update MySQL root password
      run_once: true
      mysql_user:
      # 有驗証的登入使用者
        login_user=root
      # 登入者的密碼
        login_password="\n"
      # 建立使用者的名字或是已存在的使用者
        name=root
      # 設定密碼
        password='123456789'
      # 設定權限; 語法是: 資料庫.資料表:權限1,權限2
      # 小建議,如果是設定權限時,最好是用雙引號包起來,避免會有語法上的錯誤
        priv=*.*:ALL,GRANT
      # host預設就是localhost,如果有要連別的主機就可以用這選項
        host={{ item }}
      # present=安裝 absent=移除
        state=present
      # 檢查MySQL允許用root/NOPASSWORD登入之前嘗試提供憑証(這個不設也可以用)
        check_implicit_admin=True
      with_items:
        - localhost

    - name: Setup | Create MySQL Database
      mysql_db:
      # 有驗証的登入使用者
        login_user=root
      # 使用者的登入密碼
        login_password='123456789'
      # 建立資料庫的名稱
        name=Apple
      # present=安裝 absent=移除
        state=present
templates/my_cnf_test.j2
[mysqld]
# Path to Galera library
wsrep_provider=/usr/lib64/libgalera_smm.so
# Cluster connection URL
wsrep_cluster_address=gcomm://{{ gcomm_list }}
# In order for Galera to work correctly binlog format should be ROW
binlog_format=ROW
# MyISAM storage engine has only experimental support
default_storage_engine=InnoDB
# This changes how |InnoDB| autoincrement locks are managed and is a requirement for Galera
innodb_autoinc_lock_mode=2
ACTUAL RESULTS

PLAY [Setup | Percona XtraDB Cluster] **************************************************

TASK [setup] *******************************************************************
ok: [db]

TASK [Setup | Percona yum Repository] ******************************************
changed: [db]

TASK [Setup | Install EPEL Repository] *****************************************

changed: [db]

TASK [Setup | Install Percona-XtraDB-Cluster-56 Package] ***********************
changed: [db]

TASK [Setup | Install Requirement Packages] ************************************
changed: [db] => (item=[u'mysql-devel', u'MySQL-python'])

TASK [Setup | Create Mysql Data Directories] ***********************************
changed: [db] => (item=/var/log/mysql)

TASK [Setup | Mysql Configuration] *********************************************
changed: [db]

RUNNING HANDLER [restart_mysql] ************************************************
changed: [db]

RUNNING HANDLER [Update MySQL root password] ***********************************
changed: [db] => (item=localhost)

RUNNING HANDLER [Create MySQL Database] ****************************************
changed: [db]

PLAY RECAP *********************************************************************
db                         : ok=10   changed=9    unreachable=0    failed=0