科科科,繼續吧~(到day29都是這些 = =)
幾乎參考都來自ansible官網手冊
基本一定要會的:wait_for,uri,register,when
介紹一點for特定軟體&工具的,讓大家體驗一下:pip,mysql_db,mysql_user
(就是有非常多modules啦,列幾個讓大家體驗一下,其他modules就會很好上手)
所以如果貴公司在選擇資料庫、作業系統、公有雲時,可以考慮ansible有modules的那些
如果都支援,還要看支援的modules數量
azure、gcp、aws都支援
helm、k8s、route53、grafana、docker
node.js(npm)
下次如果有業務到貴公司推銷軟硬體,先查看看有沒有modules,也是一種指標喔
https://docs.ansible.com/ansible/latest/modules/list_of_windows_modules.html
https://docs.ansible.com/ansible/latest/modules/pip_module.html
# Install specified python requirements.
- pip:
requirements: /my_app/requirements.txt
# Install multi python packages with version specifiers
- pip:
name:
- django>1.11.0,<1.12.0
- bottle>0.10,<0.20,!=0.11
# Install specified python requirements in indicated (virtualenv).
- pip:
requirements: /my_app/requirements.txt
virtualenv: /my_app/venv
# Path to the requirements file
# Path to the virtualenv,如果virtualenv path是存在的,會回傳success
# Install (Bottle) while ensuring the umask is 0022 (to ensure other users can use it)
- pip:
name: bottle
umask: "0022" # 設權限
become: True # 作設權限要升權
https://docs.ansible.com/ansible/latest/modules/mysql_db_module.html
#先把mysql跑起來
- name: ensure mysql started
service: name=mysql state=started enabled=yes
- name: Create a new database with name 'bobdata'
mysql_db:
name: bobdata # 建資料庫
state: present # 如果資料庫已經存在,不知道會怎樣?
- name: create database
mysql_db:
name={{ db_name }} # 或者用變數帶
state=present
# Copy database dump file to remote host and restore it to database 'my_db'
- name: Copy database dump file
copy:
src: dump.sql.bz2
dest: /tmp # 把資料備出來
- name: Restore database
mysql_db:
name: my_db
state: import # 再restore成my_db
target: /tmp/dump.sql.bz2
- name: Dump all databases to hostname.sql
mysql_db:
state: dump # dump所有資料庫
name: all
target: /tmp/{{ inventory_hostname }}.sql
- name: Import file.sql similar to mysql -u <username> -p <password> < hostname.sql
mysql_db:
state: import
name: all
target: /tmp/{{ inventory_hostname }}.sql
https://docs.ansible.com/ansible/latest/modules/mysql_user_module.html#examples
紙上談兵不太準,可能要多嘗試
# Removes anonymous user account for localhost
- mysql_user:
name: ''
host: localhost
state: absent # 刪掉匿名帳號
# Removes all anonymous user accounts
- mysql_user:
name: ''
host_all: yes
state: absent
# Create database user with name 'bob' and password '12345' with all database privileges
- mysql_user:
name: bob
password: 12345
priv: '*.*:ALL'
state: present # 建帳號,給所有的權八裂
# Create database user with name 'bob' and previously hashed mysql native password
# mysql> SELECT PASSWORD('bob');
# '*EE0D72C1085C46C5278932678FBE2C6A782821B4' with all database privileges
- mysql_user:
name: bob
password: '*EE0D72C1085C46C5278932678FBE2C6A782821B4'
encrypted: yes # 上面的password欄位是`mysql_native_password` hash
priv: '*.*:ALL'
state: present
# Creates database user 'bob' and password '12345' with all database privileges and 'WITH GRANT OPTION'
- mysql_user:
name: bob
password: 12345
priv: '*.*:ALL,GRANT'
state: present
# 既有user加權限
- mysql_user:
name: bob
append_privs: true
priv: '*.*:REQUIRESSL'
state: present
# Revoke all privileges for user 'bob' and password '12345'
- mysql_user:
name: bob
password: 12345
priv: "*.*:USAGE" # 所有bob有的權限
state: present # 去掉
# 權限字串的格式
# mydb.*:INSERT,UPDATE/anotherdb.*:SELECT/yetanotherdb.*:ALL
# 用login_unix_socket連線
- mysql_user:
name: root
password: abc123
login_unix_socket: /var/run/mysqld/mysqld.sock
https://docs.ansible.com/ansible/latest/modules/wait_for_module.html
active_connection_states
TCP connection states的list
Default:
[u'ESTABLISHED', u'FIN_WAIT1', u'FIN_WAIT2', u'SYN_RECV', u'SYN_SENT', u'TIME_WAIT']
- name: sleep for 300 seconds and continue with play
wait_for: timeout=300 # 最多等300秒
delegate_to: localhost
# 驗證8000 port is listening
- name: Wait for port 8000 to become open on the host, don't start checking for 10 seconds
wait_for:
port: 8000 timeout =1(沒寫預設是300秒)
delay: 10 # 先等10秒再check
- name: verify mysql is listening on 3306
wait_for: host=mysqlserver port=3306 timeout=1
- name: Waits for port 8000 of any IP to close active connections, don't start checking for 10 seconds
wait_for:
host: 0.0.0.0 # 所有ip
port: 8000
delay: 10 # 1、先等10秒
state: drained
- name: Wait for port 8000 of any IP to close active connections, ignoring connections for specified hosts
wait_for:
host: 0.0.0.0
port: 8000
state: drained # 斷掉所有連線,除了exclude_hosts的
exclude_hosts: 10.2.1.2,10.2.1.3 # 除外
- name: Wait until the file /tmp/foo is present before continuing
wait_for:
path: /tmp/foo
- name: Wait until the string "completed" is in the file /tmp/foo before continuing
wait_for:
path: /tmp/foo
search_regex: completed # 等到/tmp/foo有completed字串
- name: Wait until the lock file is removed
wait_for:
path: /var/lock/file.lock
state: absent
- name: Wait until the process is finished and pid was destroyed
wait_for:
path: /proc/3466/status
state: absent
- name: Output customized message when failed
wait_for:
path: /tmp/foo # 等到出現/tmp/foo,輸出msg
state: present
msg: Timeout to find file /tmp/foo
# Don't assume the inventory_hostname is resolvable and delay 10 seconds at start
# inventory_hostname可能是無法解析的
# 如果ssh連不到inventory_hostname(等300秒)
- name: Wait 300 seconds for port 22 to become open and contain "OpenSSH"
wait_for:
port: 22
host: '{{ (ansible_ssh_host|default(ansible_host))|default(inventory_hostname) }}'
search_regex: OpenSSH
delay: 10
connection: local
https://docs.ansible.com/ansible/latest/modules/uri_module.html
- name: 用 http get url,如果正常傳回status 200
uri:
url: http://www.example.com
# Check that a page returns a status 200 and fail if the word AWESOME is not
# in the page contents.
# 如果content裡有AWESOME,就fail
- uri:
url: http://www.example.com
return_content: yes
register: this
failed_when: "'AWESOME' not in this.content"
# Login to a form based webpage, then use the returned cookie to
# access the app in later tasks
# 試著對form based的網頁login
- uri:
url: https://your.form.based.auth.example.com/index.php
method: POST
body_format: form-urlencoded
body:
name: your_username
password: your_password
enter: Sign in
status_code: 302
register: login
# Same, but now using a list of tuples
- uri:
url: https://your.form.based.auth.example.com/index.php
method: POST
body_format: form-urlencoded
body:
- [ name, your_username ]
- [ password, your_password ]
- [ enter, Sign in ]
status_code: 302
register: login
- uri:
url: https://your.form.based.auth.example.com/dashboard.php
method: GET
return_content: yes
headers:
Cookie: "{{ login.set_cookie }}" # header設cookie,再去get
# 有用jenkins的朋友可以試試
- name: Queue build of a project in Jenkins
uri:
url: http://{{ jenkins.host }}/job/{{ jenkins.job }}/build?token={{ jenkins.token }}
method: GET
user: "{{ jenkins.user }}"
password: "{{ jenkins.password }}"
force_basic_auth: yes
status_code: 201
# 上傳檔案
- name: POST from contents of local file
uri:
url: "https://httpbin.org/post"
method: POST
src: file.json
- name: POST from contents of remote file
uri:
url: "https://httpbin.org/post"
method: POST
src: /path/to/my/file.json
remote_src: true
https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#register-variables
簡單常用的,可用在templates、action lines、when等地方
- name: test play
hosts: all
tasks:
- shell: cat /etc/motd
register: motd_contents # /etc/motd就會存到motd_contents
- shell: echo "motd contains the word hi"
when: motd_contents.stdout.find('hi') != -1 # 用stdout(標準輸出串流)操作
- name: registered variable usage as a loop list
hosts: all
tasks:
- name: retrieve the list of home directories
command: ls /home
register: home_dirs # 如果是list,就可以用stdout_line或stdout.split()跑Loop
- name: add home dirs to the backup spooler
file:
path: /mnt/bkspool/{{ item }}
src: /home/{{ item }}
state: link
loop: "{{ home_dirs.stdout_lines }}"
# same as loop: "{{ home_dirs.stdout.split() }}"
- name: check registered variable for emptiness
hosts: all
tasks:
- name: list contents of directory
command: ls mydir
register: contents
- name: check contents for emptiness
debug:
msg: "Directory is empty"
when: contents.stdout == "" # 檢查目錄是不是空的
類似if...then,條件語句,非常常用
https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#the-when-statement
# 如果是Debian系列的話…
tasks:
- name: "shut down Debian flavored systems"
command: /sbin/shutdown -t now
when: ansible_facts['os_family'] == "Debian"
# note that all variables can be directly in conditionals without double curly braces
# https://docs.ansible.com/ansible/2.7/user_guide/playbooks_variables.html
# 變數:ansible_facts,跟system有關的資訊
# 有2種方式可以看
# 利用debug輸出
- debug: var=ansible_facts
# 原始資訊
ansible hostname -m setup
例如:ubuntu的
{
"ansible_all_ipv4_addresses": [
"REDACTED IP ADDRESS"
],
"ansible_all_ipv6_addresses": [
"REDACTED IPV6 ADDRESS"
],
"ansible_architecture": "x86_64",
"ansible_bios_date": "09/20/2012",
"sr0": {
"holders": [],
"host": "IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01)",
"model": "VMware IDE CDR10",
"partitions": {},
....
{{ ansible_facts['devices']['sda']['model'] }}
{{ ansible_facts['hostname'] }}
- hosts: whatever
gather_facts: no # 可以省很多時間!!
/etc/ansible/facts.d
tasks:
- name: "shut down CentOS 6 and Debian 7 systems"
command: /sbin/shutdown -t now
when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or
(ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")
tasks:
- command: /bin/false
register: result
ignore_errors: True
- command: /bin/something
when: result is failed
# In older versions of ansible use ``success``, now both are valid but succeeded uses the correct tense.
# 現在應該要用 true | false
- command: /bin/something_else
when: result is succeeded # 指令回傳的result
- command: /bin/still/something_else
when: result is skipped
# 用來介斷變數
vars:
epic: true
tasks:
- shell: echo "This certainly is epic!"
when: epic # 或者加not => not epic
# 檢查變數有沒有定義
tasks:
- shell: echo "I've got '{{ foo }}' and am not afraid to use it!"
when: foo is defined
- fail: msg="Bailing out. this play requires 'bar'"
when: bar is undefined
# 用來當loop的終止條件
tasks:
- command: echo {{ item }}
loop: [ 0, 2, 4, 6, 8, 10 ]
when: item > 5