星期二, 2月 20, 2018

Ansible azure module - Dynamic inventory 小記

Ansible azure module - Dynamic inventory 小記

OS: openSUSE Leap 42.3 in Azure

今天來嘗試 使用 Ansible 的 Dynamic inventory 在 Azure

官方文件 Use Ansible to manage your Azure dynamic inventories

不過說真的, 個人不覺得一般的人類可以看完這個文件直接實作成功 :p

因為他是有些必要條件的
  • 安裝 Azure python SDK
  • 安裝 ansible 套件然後不能跟 python 衝突( 符合 python 套件需要 )
  • 下載 azure_rm.py
  • 已經設定好 ~/.azure/credentials ( 他寫在 azure_rm.py 裏面要逼死誰 ??  )
  • 手動處理一些例外狀況 …..

開始之前先紀錄自己的經驗( 血淚 )

Ansible and Python3

在安裝相關套件的時候, 大家會用 pip 指令( 官方也是寫 pip 喔 )

但是 pip 指令到底是 python2 or python3 ???

先用 which 指令查詢 pip 路徑

# which   pip
/usr/bin/pip

ls 一下, 發現他是個 link, 指向 /etc/alternatives/pip
# ls -l  /usr/bin/pip
lrwxrwxrwx 1 root root 21 Jan 14 19:24 /usr/bin/pip -> /etc/alternatives/pip

觀察檔案, 看起來是指向 pip3.4 ( 我想這就是有些慘案發生的原因 …  )
# cat   /etc/alternatives/pip
#!/usr/bin/python3
# EASY-INSTALL-ENTRY-SCRIPT: 'pip==7.1.2','console_scripts','pip3.4'
__requires__ = 'pip==7.1.2'
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
   sys.exit(
       load_entry_point('pip==7.1.2', 'console_scripts', 'pip3.4')()
   )

安裝 python-pip 套件 ( 非 python3-pip, 且預設 python3-pip 已經安裝 )

# zypper  install  python-pip
Loading repository data...
Reading installed packages...
Resolving package dependencies...

The following 6 NEW packages are going to be installed:
 python-appdirs python-packaging python-pip python-pyparsing python-setuptools python-six

6 new packages to install.
Overall download size: 2.0 MiB. Already cached: 0 B. After the operation, additional 9.1 MiB will be used.
Continue? [y/n/...? shows all options] (y):  Y

這個時候才會有 pip2 的指令

檢查 pip 版本
# pip2  --version
pip 7.1.2 from /usr/lib/python2.7/site-packages (python 2.7)

首要之務, 就是先升級 pip 版本
# pip2  install  --upgrade  pip

# pip2  install  --upgrade  pip
Collecting pip
 Downloading pip-9.0.1-py2.py3-none-any.whl (1.3MB)
   100% |████████████████████████████████| 1.3MB 94kB/s
Installing collected packages: pip
 Found existing installation: pip 7.1.2
   Uninstalling pip-7.1.2:
     Successfully uninstalled pip-7.1.2
Successfully installed pip-9.0.1

檢查 pip 版本為最新
# pip2  --version
pip 9.0.1 from /usr/lib/python2.7/site-packages (python 2.7)


安裝 ansible 以及 azure SDK
# pip2  install  ansible[azure]

怎麼驗證 ansible 有符合相對應的版本呢?
如果出現 相關資訊那就沒有問題
# ansible  --version
ansible 2.4.3.0
 config file = None
 configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
 ansible python module location = /usr/lib/python2.7/site-packages/ansible
 executable location = /usr/bin/ansible
 python version = 2.7.13 (default, Jan 03 2017, 17:41:54) [GCC]


如果是 pip 導向 pip3 安裝的 ansible 就會出現下列的錯誤訊息 ( 淚 ~ )

# ansible  --verison
ERROR! Unexpected Exception, this is probably a bug: unsupported operand type(s) for %: 'bytes' and 'bytes'
the full traceback was:

Traceback (most recent call last):
 File "/usr/bin/ansible", line 85, in <module>
   mycli = getattr(__import__("ansible.cli.%s" % sub, fromlist=[myclass]), myclass)
 File "/usr/lib/python3.4/site-packages/ansible/cli/__init__.py", line 38, in <module>
   from ansible.inventory.manager import InventoryManager
 File "/usr/lib/python3.4/site-packages/ansible/inventory/manager.py", line 44, in <module>
   IGNORED_EXTS = [b'%s$' % to_bytes(re.escape(x)) for x in C.INVENTORY_IGNORE_EXTS]
 File "/usr/lib/python3.4/site-packages/ansible/inventory/manager.py", line 44, in <listcomp>
   IGNORED_EXTS = [b'%s$' % to_bytes(re.escape(x)) for x in C.INVENTORY_IGNORE_EXTS]
TypeError: unsupported operand type(s) for %: 'bytes' and 'bytes'

好吧, 下一步就是下載 azure_rm.py

使用 wget 指令取得 azure_rm.py
# wget  https://raw.githubusercontent.com/ansible/ansible/devel/contrib/inventory/azure_rm.py

給與執行的權限
# chmod  a+x  azure_rm.py

開始執行第一次測試 ( 按照文件上面 )
針對 sakanatest 的資源群組 進行 ping 模組測試
# ansible  -i  azure_rm.py  sakanatest  -m  ping
[WARNING]:  * Failed to parse /root/azure_rm.py with script plugin: Inventory script (/root/azure_rm.py) had an execution error: Failed to get
credentials. Either pass as parameters, set environment variables, or define a profile in ~/.azure/credentials.

恩, 他可愛的 ~/.azure/credentials 說明是寫在 azure_rm.py 裏面

請參考這篇文章 http://sakananote2.blogspot.tw/2018/02/ansible-azure-module.html 建立你的驗證資訊

有了 ~/.azure/credentials 那就再來一次吧

# ansible  -i  azure_rm.py   sakanatest  -m  ping
The authenticity of host '52.179.3.77 (52.179.3.77)' can't be established.
ECDSA key fingerprint is SHA256:XsRhBadLUetPIn9wWb2AQQ03E3eg+YaEITxumPmX4o0.
Are you sure you want to continue connecting (yes/no)? The authenticity of host '13.90.214.129 (13.90.214.129)' can't be established.
ECDSA key fingerprint is SHA256:bS5jxhey+ybnCoKNawzzAXy0QOj7Am2ZGOd+0NOkekU.
Are you sure you want to continue connecting (yes/no)? yes

這邊會失敗的原因是我建立 VM 的時候是使用密碼的方式
嘗試加入 --ask-pass 方式來執行
# ansible  -i  azure_rm.py --ask-pass sakanatest  -m ping
SSH password:
test01 | FAILED! => {
   "msg": "to use the 'ssh' connection type with passwords, you must install the sshpass program"
}
test02 | FAILED! => {
   "msg": "to use the 'ssh' connection type with passwords, you must install the sshpass program"
}

被告知沒有裝 sshpass 套件, 那就裝吧
# zypper  install  sshpass

再次嘗試
# ansible  -i  azure_rm.py --ask-pass sakanatest  -m ping

SSH password:
test02 | FAILED! => {
   "msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host's fingerprint to your known_hosts file to manage this host."
}
test01 | UNREACHABLE! => {
   "changed": false,
   "msg": "Authentication failure.",
   "unreachable": true
}

因為我剛剛加入 SSH 金鑰的時候只加入一把, 就會發現兩個錯誤訊息
  • test02 VM 金鑰沒有加入到 ~/.ssh/known_host 檔案
  • test01 VM 驗證錯誤

test01 VM 驗證錯誤應該是我是用 root 身份執行, 預設應該也是用 root 進行 ssh 連線
嘗試加上 -u 的選項指定使用者來試試看

# ansible  -i  azure_rm.py  --ask-pass  -u  sakana  sakanatest  -m ping
SSH password:
test02 | FAILED! => {
   "msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host's fingerprint to your known_hosts file to manage this host."
}
test01 | SUCCESS => {
   "changed": false,
   "ping": "pong"
}

Test02 的部份, 解決方式大概就是
  • 將 金鑰加入 ~/.ssh/known_hosts
  • 在 ansible.cfg 內設定不用檢查 key ( 不建議, 但是實驗性質應該還好 )

建立一個 ansible.cfg, 設定不檢查 host key
# vi  ansible.cfg

[defaults]
host_key_checking = False
再次嘗試就發現成功了, 針對 sakanatest 資源群組的所有主機進行 ping 動作

# ansible  -i  azure_rm.py  --ask-pass  -u  sakana  sakanatest  -m ping

SSH password:
test01 | SUCCESS => {
   "changed": false,
   "ping": "pong"
}
test02 | SUCCESS => {
   "changed": false,
   "ping": "pong"
}

最後最重要的是記得看一次 azure_rm.py 透過 api 撈出來的主機資訊

# ./azure_rm.py   --pretty

又跨出一小步, 農曆年假也結束了 QQ



Reference



~ enjoy it

星期六, 2月 17, 2018

Ansible azure module 測試小記 - 使用 vars_prompt 建立多 VM in Azure

Ansible azure module 測試小記 - 使用 vars_prompt 建立多 VM in Azure

OS:  openSUSE Leap 42.3 in Azure

測試模組
  • azure_rm_virtualmachine

上次的文章 http://sakananote2.blogspot.tw/2018/02/ansible-azure-module.html 使用 azure_rm_virtualmachine 建立 VM in Azure

但是建立的 VM 相關設定是寫死的, 每次要建立 VM 要去修改 yml 檔案, 所以接下來就改寫上次的 azure_create_vm.yml , 使用 vars_prompt 方式來讓新增 VM 有彈性

azure_create_vm.yml 內容如下

---
# Azure VM 相關測試
# edit by sakana 2018/2/17
- name: use when conditionals and setup module
 hosts: localhost
 connection: local
#
 vars_prompt:
   - name: "resource_group"
     prompt: "Enter resource group name"
     private: no
     default: sakanatest

   - name: "admin_username"
     prompt: "Enter admin username"
     private: no
     default: sakana

   - name: "admin_password"
     prompt: "Enter admin password"
     private: yes
     
   - name: "sequence_start"
     prompt: "Enter sequence start number"
     private: no
     default: 1

   - name: "sequence_end"
     prompt: "Enter sequence end number, Max is 99"
     private: no
     default: 10

   - name: "vm_size"
     prompt: "Enter VM size"
     private: no
     default: Basic_A1

   - name: "image_offer"
     prompt: "Enter image offer"
     private: no
     default: openSUSE-Leap

   - name: "image_publisher"
     prompt: "Enter image publisher"
     private: no
     default: SUSE

   - name: "image_sku"
     prompt: "Enter image sku"
     private: no
     default: 42.3

   - name: "image_version"
     prompt: "Enter image version"
     private: no
     default: latest

 tasks:
  - name: Create Azure test VM
# 可以用 with_sequence 方式, %0x 為序號, x是16進制, 所以我用 u 10進制
# 如果是 %02x 就是 2位數, 例如 server00
# 如果只設定 server%0x , 但是超出1位數, 例如 1 to 10, 最後一個會變成 servera
# stride=2 代表間隔是 2
#      with_sequence: start=1 end=10 stride=1 format=server%02u
    with_sequence: start={{ sequence_start }} end={{ sequence_end }} stride=1 format=test%02u
    azure_rm_virtualmachine:
      resource_group: "{{ resource_group }}"
# 這邊的 "{{ item }}" 對應到上面的 with_sequence
      name: "{{ item }}"
      admin_username: "{{ admin_username }}"
      admin_password: "{{ admin_password }}"
# 這邊可以對應到已經有的儲存體
# 建立VM的時候會對應到儲存體, 如果只是實驗用, 可以對應到已經存在的儲存體
# 好處是移除的時候不用再手動移除
# 這個 storage_account 是已經建立好的, 請對應到已經存在儲存體
#       storage_account: sakanatestdiag34
# 經實驗 vm_size 是必須的
      vm_size: "{{ vm_size }}"
#
# image 相關資訊可以使用 az vm image list --output table 查詢
      image:
        offer: "{{ image_offer }}"
        publisher: "{{ image_publisher }}"
        sku: "{{ image_sku }}"
        version: "{{ image_version }}"
#


使用 ansible-playbook 指令執行 azure_create_vm.yml , 因為剛剛有設定 default 值, 所以大概就是指定建立 VM 的數量就好

$ ansible-playbook     azure_create_vm.yml

Enter resource group name [sakanatest]:
Enter admin username [sakana]:
Enter admin password:
Enter sequence start number [1]:
Enter sequence end number, Max is 99 [10]: 2
Enter VM size [Basic_A1]:
Enter image offer [openSUSE-Leap]:
Enter image publisher [SUSE]:
Enter image sku [42.3]:
Enter image version [latest]:

這樣以後建立實驗機器就方便多了

同樣方法也來改寫 azure_remove_vm.yml , 先來嘗試移除單一VM, 下次來建立移除多 VM

azure_remove_vm.yml 內容如下

---
# Azure VM 相關測試
# edit by sakan 2018/2/17
- name: use when conditionals and setup module
 hosts: localhost
 vars_prompt:
   - name: "vm_name"
     prompt: "Enter VM name your want to remove"
     private: no

 tasks:
  - name: Remove Azure test VM
    azure_rm_virtualmachine:
      resource_group: sakanatest
      name: "{{ vm_name }}"
      state: absent


今天先這樣

~ enjoy it