2. Ansible
a fictional device capable of instantaneous or faster than light
communication, that can send and recieve messages over any
distance or obstacle with no delay.
3. Ansible
• but no science fiction today ...
• configuration management tool
• implemented in Python
• requires ssh and Python on the target host
• comes with a plethora of modules, which form the basic building
blocks for playbooks
4. module processing
ansible
control host
Playbook : oracle_user.yml
---
- name: do some oracle stuff
hosts: oracleservers
gather_facts: False
tasks:
- name: create user test
become: true
become_user: oracle
oracle_user:
database_name: XE
user_name: test
password: test
#!/opt/python/bin/python
# -*- coding: utf-8 -*-
ANSIBALLZ_WRAPPER = True
import os
import os.path
import sys
import __main__
scriptdir = None
database host
oraclexe
ssh
1
2
3
4
{'changed': false, 'failed': true, 'msg': 'could not reach the host'}
5
module : oracle_user
#!/opt/python/bin/python
from ansible.module_utils.basic import AnsibleModule
import os
import cx_Oracle
def create_user(cursor, user_name, password):
create_user_statement = '''
1.process playbook
2.generate python script
3.copy python script to target host(s)
4.execute script on target host(s)
5.parse the script‘s output
5. expected output
{'changed': false, 'failed': true, 'msg': 'could not reach the host'}
• changed indicates that host state has been changed by the module
• failed indicates that the module has not completed successfully
• msg expand on the reason of the failure
7. let‘s get playing
root@ansible:~/playbooks# cat oracle_user.yml
---
- name: do some oracle stuff
hosts: oracleservers
gather_facts: False
tasks:
- name: create user test
become: true
become_user: oracle
oracle_user:
database_name: XE
user_name: test
password: test
environment:
LD_LIBRARY_PATH: /u01/app/oracle/product/11.2.0/xe/lib
9. error handling
try:
sysdba_connection = cx_Oracle.connect('/', mode=cx_Oracle.SYSDBA)
cursor = sysdba_connection.cursor()
except cx_Oracle.DatabaseError as exc:
error, = exc.args
formatted_error = error.message.replace('n', ' ')[:40]
error_msg='unable to connect to database {} due to {}'.format(
database_name,
formatted_error,
)
module.fail_json(msg=error_msg)
10. error handling in action
root@ansible:~/playbooks# ansible-playbook oracle_user.yml
PLAY [do some oracle stuff] ****************************************************
TASK [create schema test] ******************************************************
fatal: [oraclexe]: FAILED! => {
"changed": false,
"failed": true
}
MSG:
unable to connect to database XA due to ORA-01034: ORACLE not available ORA-2710
to retry, use: --limit @/root/playbooks/oracle_schema.retry
PLAY RECAP *********************************************************************
oraclexe : ok=0 changed=0 unreachable=0 failed=1
root@ansible:~/playbooks#
12. Idempotence as code
if user_exists(cursor=cursor, user_name=user_name, password=password):
module.exit_json(changed=False)
else:
if module.check_mode:
module.exit_json(changed=True)
create_user_result = create_user(
cursor=cursor,
user_name=user_name,
password=password,
)
cursor.close()
if not create_user_result['status']:
module.fail_json(msg=create_user_result['msg'])
else:
module.exit_json(changed=True, msg=create_user_result['msg'])
13. Idempotence in action
root@ansible:~/playbooks# ansible-playbook oracle_user.yml
PLAY [do some oracle stuff]
****************************************************
TASK [create user test]
******************************************************
ok: [oraclexe]
PLAY RECAP
*********************************************************************
oraclexe : ok=1 changed=0 unreachable=0 failed=0
root@ansible:~/playbooks#
14. check mode
• will not make any changes
• but reports on the possible outcome
15. check mode as code
supports_check_mode=True,
.
.
if user_exists(cursor=cursor, user_name=user_name, password=password):
module.exit_json(changed=False)
else:
if module.check_mode:
module.exit_json(changed=True)
create_user_result = create_user(
cursor=cursor,
user_name=user_name,
password=password,
)
cursor.close()
if not create_user_result['status']:
module.fail_json(msg=create_user_result['msg'])
else:
module.exit_json(changed=True, msg=create_user_result['msg'])
16. check mode in action
root@ansible:~/playbooks# ansible-playbook oracle_user.yml --check
PLAY [do some oracle stuff] ****************************************************
TASK [create user test] ********************************************************
changed: [oraclexe]
PLAY RECAP *********************************************************************
oraclexe : ok=1 changed=1 unreachable=0 failed=0
root@ansible:~/playbooks#
SQL> select username from dba_users where username='TEST';
no rows selected
SQL>
17. the final curtain
root@ansible:~/playbooks# ansible-playbook oracle_user.yml
PLAY [do some oracle stuff] ****************************************************
TASK [create user test] ********************************************************
changed: [oraclexe]
PLAY RECAP *********************************************************************
oraclexe : ok=1 changed=1 unreachable=0 failed=0
root@ansible:~/playbooks#
SQL> select username from dba_users where username='TEST';
USERNAME
------------------------------
TEST
SQL>
18. references
• Hochstein L. and Moser R.(2017). Ansible Up & Running. O‘Reilly.
• Ansible Module Development Walkthrough. [online] Available at:
http://docs.ansible.com/ansible/latest/dev_guide/developing_modules_gener
al.html