1automating Oracle Database Administration Practical Examples With Ansible Ilmar Kerm PDF
1automating Oracle Database Administration Practical Examples With Ansible Ilmar Kerm PDF
42% 70%
Employees: Offices: Nationalities: Brands:
1,400 15 52 11
Our A portfolio of
brands within
brands
sportsbook,
casino and
games
© Kindred Group plc 2017
Where we operate
Blog: https://ilmarkerm.eu
Email: [email protected]
Twitter: @ilmarkerm
WHOAMI: Mikael Sandström
Blog: https://oravirt.wordpress.com
Email: [email protected]
Twitter: @oravirt
Ansible for Oracle use cases
• Easy
‒ Setting up database environment infrastructure, OS
‒ Installation of RDBMS software
‒ Automation of routine OS tasks
• Medium
‒ Push of the button datacenter deployment
‒ Initial creation of databases, pushing out initial configuration
‒ Automation of routine DBA tasks: patching, creating tablespaces, …
‒ One time tasks needing high level of orchestration – upgrades, …
‒ Implementing missing features from Oracle
‒ Enforcing common security settings
• Advanced
‒ All database configuration and changes deployed as version controlled code
‒ Easy to review and audit, repeatable
Agenda
• We expect that you are familiar with Ansible
• Things we cover
‒ Setting up Ansible environment for Oracle DB use: inventory, modules, cxOracle
‒ Handling Ansible inventory for database usage
‒ Creating/managing users and roles, syncing with Active Directory
‒ Services, tablespaces, resource manager, DBMS_SCHEDULER, AWR settings, INIT.ORA
parameters, ASM diskgroups
‒ User privileges, including grants to entire target schema
‒ Gathering facts about databases
‒ Managing passwords in playbooks
‒ Practical playbook deployment: execution, scheduling, configuration
• Things we do not cover, because every other Ansible presentation does these
‒ What is Ansible (check the first bullet point)
‒ Managing OS
‒ Installing Oracle RDBMS/Grid software
‒ Creating databases/clusters (we will create PDBs though)
Introducing Oracle modules for Ansible
• Modules for administering Oracle database infrastructure
• Hosted in Github
‒ https://github.com/oravirt/ansible-oracle-modules
• Currently not part of Ansible standard modules
‒ Work in progress
• Written in Python
• Require cx_Oracle
‒ Needed where the modules are executed
‒ cx_Oracle needs an Oracle client
‒ If run locally on ‘control-machine’ Instant Client is fine, otherwise just install on
the database host
‒ pip or yum/rpm
Introducing Oracle modules for Ansible
• Currently manages:
‒ Users and roles, including synchronization from AD/LDAP
‒ Grants: system and object privileges, including wildcards
‒ Tablespaces
‒ Parameters
‒ Services
‒ ASM diskgroups and volumes
‒ Pluggable databases
‒ DBMS_SCHEDULER jobs, windows and schedules
‒ Resource manager consumer groups, including mappings by user profile
‒ AWR snapshot settings
• Helper modules:
‒ Gathering database facts
‒ Executing SQL
Setting up – playbook structure
|____ansible.cfg | | |____tasks
|____site.yml | | | |____main.yml
|____build-host.yml | | |____templates
|____db-config.yml | | | |____oracle-seclimits.conf.j2
|____group_vars | |____oracle-asm-diskgroups
git clone https://github.com/oravirt/ansible-oracle-modules library
| |____doag | | |____defaults
| | |____doag.yml | | | |____main.yml
| | |____passwords.yml | | |____tasks
|____library | | | |____main.yml
| |____oracle_asmdg
| |____oracle-database
| |____oracle_awr
| | |____defaults
| |____oracle_facts
| | | |____main.yml
| |____oracle_ldapuser
| | |____tasks
| |____oracle_parameter
| | | |____main.yml
| |____...
| | |____templates
|____roles
| | | |____dbca.rsp.j2
| |____host | | | |____netca.rsp.j2
| | |____defaults
| | | |____main.yml
Ansible inventory
• Inventory describes for Ansible where the servers are
• Inventory only describes hosts
• Hosts can be divided into groups
• NB! Hosts may not exactly map into databases
Inventory and databases [Potential problem]
• One config file per db
group_vars/db1
- Inventory
[db1]
host1.example.com
- Inventory
[db1]
host1.example.com
[db2]
host1.example.com
• You might get unexpected results (variables might not come from the configuration you expected)
Inventory and databases [Solutions]
• Separate inventory files, one config per inventory
$ cat inventory/db1
[db1]
host1.example.com
$ cat inventory/db2
[db2]
host1.example.com
and target the config with ‘ansible-playbook … -i inventory/db1’ etc
• Use one DNS CNAME per database, same concept as fake hosts
• Use one database per host
Inventory (random thoughts)
• Try to keep the inventories as standard as possible (for as long as possible)
• Maybe keep inventory in its own repository (to avoid duplication, if many different
repos for management).
‒ Possible to softlink, or just point playbook to inventory
• If environment is large, external service registry could be needed
‒ Dynamic inventory script, like for AWS
Setting up scenarios – common variables
oracle_base: /u01/app/oracle
oracle_home: "{{ oracle_base }}/product/{{ oracle_db.version }}/db"
oracle_env:
ORACLE_HOME: "{{ oracle_home }}"
LD_LIBRARY_PATH: "{{ oracle_home }}/lib“
user: system
oracle_db:
name: orcl
passwd: "{{ oracle_passwd }}” #<- Password taken from external file
version: 12.2.0.1
cdb: true
db_dest: +DATA
fra_dest: +DATA
pdb:
- appdb1
- appdb2
Scenario: Setting init.ora parameters 1/2 variables
init_parameters:
- name: db_recovery_file_dest_size - name: audit_trail
value: 60G value: XML
- name: db_recovery_file_dest scope: spfile
value: “{{ oracle_db.fra_dest }}” - name: sec_case_sensitive_logon
- name: db_create_file_dest value: TRUE
value: “{{ oracle_db.db_dest }}” - name: sec_max_failed_login_attempts
- name: filesystemio_options value: 3
value: setall - name: sql92_security
scope: spfile value: TRUE
- name: optimizer_adaptive_features scope: spfile
state: absent
Scenario: Setting init.ora parameters 2/2 task
- name: Set parameters
local_action:
module: oracle_parameter
hostname: “{{ inventory_hostname }}”
service_name: “{{ oracle_db.name }}”
user: “{{ oracle_db.user }}”
password: “{{ oracle_db.passwd }}”
name: “{{ item.name }}”
value: "{{ item.value }}"
state: “{{ item.state | default('present') }}”
scope: “{{ item.scope | default('both') }}”
environment: "{{ oracle_env }}"
with_items: "{{ init_parameters }}"
tags: param
Scenario: Creating PDB-s
- name: Create pdb
local_action:
module: oracle_pdb
hostname: "{{ inventory_hostname }}"
username: sys
password: "{{ oracle_db.passwd }}"
service_name: "{{ oracle_db.name }}"
mode: sysdba
name: "{{ item }}"
datafile_dest: "{{ oracle_db.db_dest }}"
state: present
environment: "{{ oracle_env }}“
with_items: “{{ oracle_db.pdb }}”
tags: pdb
Scenario: Creating database users 1/3 variables
dba_user:
- schema: dbauser
schema_password_hash: "{{dbauser_pwhash}}"
default_tablespace: dbauser_data
default_temp_tablespace: temp
grants:
- dba
roles:
- name: approle1
role_grants:
- create session
- create table
- select any dictionary
Scenario: Creating database users 2/3 task
- name: Create DBA user
local_action:
module: oracle_user
hostname: “{{ inventory_hostname }}”
service_name: “{{ oracle_db.name }}”
user: “{{ oracle_db.user }}”
password: “{{ oracle_db.passwd }}”
schema: “{{ item.0.schema }}”
schema_password_hash: “{{ item.0.schema_password_hash }}”
state: “{{ item.0.state | default(‘present’) }}”
default_temp_tablespace: “{{ item.0.default_temp_tablespace }}”
default_tablespace: “{{ item.0.default_tablespace }}”
grants: “{{ item.1 }}”
update_password: on_create
environment: "{{ oracle_env }}"
with_subelements:
- "{{ dba_user }}"
- grants
tags: users
Scenario: Creating database users 3/3 task
- name: Create application role - name: Add grants to role
local_action: local_action:
module: oracle_role module: oracle_grants
hostname: “{{ inventory_hostname }}” hostname: “{{ inventory_hostname }}”
service_name: “{{ oracle_db.name }} service_name: “{{ oracle_db.name }}”
user: “{{ oracle_db.user }}” user: “{{ oracle_db.user }}”
password: “{{ oracle_db.passwd }}” password: “{{ oracle_db.passwd }}”
role: “{{ item.name }}” role: “{{ item.name }}”
state: present grants: "{{ item.role_grants }}"
environment: "{{ oracle_env }}" state: present
with_items: "{{ roles }}" environment: "{{ oracle_env }}"
tags: role with_items: "{{ roles }}"
tags: role,grant
Scenario: Syncing users and roles from AD
- name: oracle_ldapuser
local_action:
module: oracle_ldapuser
### Target Oracle database connection information is cut from this slide
### LDAP parameters
ldap_connect: "ldap://mycompany.domain:389"
ldap_binddn: [email protected]
ldap_bindpassword: Ansible2017
ldap_user_basedn: OU=Users,OU=Demo,DC=ansible,DC=test
# The following filter means that objectClass is person, member of one specific group and account is not disabled
ldap_user_filter: (&(objectClass=person)(memberOf=CN=prod_db,OU=Groups,DC=ansible,DC=test)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))
ldap_username_attribute: sAMAccountName
### New user parameters
user_profile: LDAP_USER
All synced users must have
user_grants:
a common dedicated profile!
- create session
- create table
group_role_map:
- {dn: "CN=HR,OU=Groups,OU=Demo,DC=ansible,DC=test", group: "department_hr"}
- {dn: "CN=IT,OU=Groups,OU=Demo,DC=ansible,DC=test", group: "department_it"}
deleted_user_mode: lock Users missing from LDAP query
environment: "{{ oracle_env }}"
will be locked or deleted.
Scenario: Maintaining wildcard privileges
- name: Manage what objects DEPARTMENT_HR can access
local_action:
module: oracle_privs:
### Target Oracle database connection information is cut from this slide
roles:
- DEPARTMENT_HR SELECT owner, object_name
privs: FROM all_objects
- SELECT WHERE (owner||’.’||object_name LIKE
- FLASHBACK ‘HR.%’ OR owner||’.’||object_name =
objs: ‘HRREST.COUNTRIES’)
- HR.% AND object_type IN (‘TABLE’,’VIEW’)
- HRREST.COUNTRIES
objtypes:
- TABLE
- VIEW Existing extra privileges not
state: present matching the privs + objects
environment: "{{ oracle_env }}" list will be revoked!
Scenario: Managing resource manager
sys_password: Oracle123
dbauser_password: Oracle456
$ cat passwords.yml
$ANSIBLE_VAULT;1.1;AES256
37306631393231363334396666643466613062373336623836383333653963376463366234353130
3962383634356134663061313162386136386234616138380a616630626535613131353431356536
66623831316637306432363763333231323139363535666137666333353463633763633333383963
3535386137633165660a376435613736666663396233626531346530343462333865306137386434
35303466646564313131386565386364333762646130316439343764356366643034623563633061
32373832376136303834356664373534643631303439656434613761633732653433646536346231
343062396162376366326561333537343736
Scenario: Create job in all PDB 1/3 variables
pdb_json_query: pdb[?OPEN_MODE=='READ WRITE'].NAME
exclude_pdb:
- PDB$SEED
common_job:
name: DBAUSER.SEND_SLOW_SQL_REPORT
job_type: plsql_block
job_action: DBA_REPORTS_PKG.SEND_SLOW_SQL_REPORT
repeat_interval: FREQ=DAILY;BYHOUR=8
Scenario: Create job in all PDB 2/3 tasks