Happy new year! I’ll continue with Ansible topic with one more post as it has helped our small operations team quite a lot lately.

We still run Oracle e-Business Suite 12.1.3 and the amount of customizations we have is really high(No surprise there!). Due to some historical reasons initially we were loading custom objects to eBS via shell scripts. As time passed this was changed so we used concurrent requests to install those custom objects.

Basically what happens is the concurrent looks for specific named zip object from installation directory and if it exists it executes the shell script. This method is no way perfect but it has worked for us and nobody really had time to improve the script.

In addition to this we always had to go to version control system, checkout the zips for specific tag/release and then upload them to installation directory. Lot of manual and quite static tasks!

So Ansible to the rescue. Using Ansible we found really simple way to reduce manual tasks without touching (yet) the actual installation method. As of now we still use subversion but are already in process on switching to Gitlab and making some changes on deploying the code.

If I break the tasks what Ansible does on high level:

  1. Install subversion & rsync to the server (these are needed)
  2. Delete old tag folder & export subversion tag folder defined in playbook
  3. Register all zips in tag to a variable
  4. Copy files to installation directory
  5. Grep and register user home to variable (apparently there is no easy way to get become_user home directory)
  6. Run CONCSUB on application server to submit concurrent request based on zip file name
  7. Delete old tag folder

Once again as there is lot of passwords involved we have used ansible-vault as well for variables.

1. Install subversion & rsync

Here we first define the startdate if we would like to schedule the requests but next step is to install subversion & rsync via yum. Really basic but I think it is best to have these here because otherwise you would always need to check if they exist or not.


---
- include: define_startdate.yml
when: sch_date is defined

- name: Install subversion and rsync to Server
yum: name="{{item}}"
state=latest
update_cache=yes
with_items:
- subversion
- rsync

2. Delete old tag folder & Export the subversion tag

Again really basic things. Remove directory and export the tag defined in the playbook.


- name: Delete tag folder {{tag}} if exists
file:
path: "/tmp/{{tag}}"
state: absent

- name: Export Subversion tag {{tag}}
subversion:
repo: svn://{{testsvn}}/{{tag}}
dest: /tmp/{{tag}}

3. Register all zips in tag to a variable

Here I look the earlier created tag which contains zip files, look all of them and register them into variable.


- name: Register zips to a variable
find:
paths: "/tmp/{{tag}}/"
patterns: "*.zip"
register: install_zip

4. Copy files to installation directory

As I want only to copy the zip files from subversion export directory to the installation directory I found rsync to be good for that purpose. With rsync you need to use delegate_to parameter so it is done on destination server.


- name: Copy files from tag to installation folder
synchronize:
mode: push
src: /tmp/{{tag}}/
dest: "{{ricef_dir}}"
rsync_opts:
- "--include=*.zip"
delegate_to: "{{ inventory_hostname }}"

5. Grep and register user home directory

As I don’t want to login with apps user and instead use become_user this was one way to get the user home variable registered. This is needed for the concurrent request execution to have environment variables loaded.


- name: grep and register
shell: >
egrep "^{{ ap_user }}:" /etc/passwd | awk -F: '{ print $6 }'
changed_when: false
register: user_home

6. Run CONCSUB to submit concurrent requests

I have changed the three different types of customizations to TYPE1, TYPE2 and TYPE3 but we have three different customization areas and zip files always contain their respective type in the name.

Each type loops now through (with_items) the files we earlier registered in the variable install_zip. When the item matches to specific type it submits the CONCSUB (when part).

Also we submit this using the application owner user (ap_user) and source the shell when submitting the CONCSUB. All other variables are defined in the group_vars file.

- name: Install TYPE1 zips
shell: source "{{user_home.stdout}}"/.bash_profile && CONCSUB apps/"{{apps_pass}}" SYSADMIN "System Administrator" "{{apps_user}}" \
WAIT=N CONCURRENT XBOL XBOCOD "{{run_date|default ('')}}" '$TYPE1_TOP/install' "{{item.path | basename}}" "{{type1_pass}}" '"{{db_host}}"' '"{{db_port}}"' \
'"{{db_sid}}"'
with_items: "{{install_zip.files}}"
when: item.path | search("type1")
become: true
become_user: "{{ap_user}}"

- name: Install TYPE2 zips
shell: source "{{user_home.stdout}}"/.bash_profile && CONCSUB apps/"{{apps_pass}}" SYSADMIN "System Administrator" "{{apps_user}}" \
WAIT=N CONCURRENT XBOL XBOCOD "{{run_date|default ('')}}" '$TYPE2_TOP/install' "{{item.path | basename}}" "{{type2_pass}}" '"{{db_host}}"' '"{{db_port}}"' \
'"{{db_sid}}"'
with_items: "{{install_zip.files}}"
when: item.path | search("type2")
become: true
become_user: "{{ap_user}}"

- name: Install TYPE3 zips
shell: source "{{user_home.stdout}}"/.bash_profile && CONCSUB apps/"{{apps_pass}}" SYSADMIN "System Administrator" "{{apps_user}}" \
WAIT=N CONCURRENT XBOL XBOCOD "{{run_date|default ('')}}" '$TYPE3_TOP/install' "{{item.path | basename}}" "{{type3_pass}}" '"{{db_host}}"' '"{{db_port}}"' \
'"{{db_sid}}"'
with_items: "{{install_zip.files}}"
when: item.path | search("type3")
become: true
become_user: "{{ap_user}}"

7. Remove tag folder after execution

This is just for cleanup.


- name: Removing temporary files
file:
path: "/tmp/{{tag}}"
state: absent

Summary

We have another playbook when installing single customization but it follows the same logic. This one is used to load all customizations for specific release and is called using ansible-playbook:

ansible-playbook tag2UAT.yml –ask-vault-pass –extra-vars “tag=REL_2017_12_1 apps_user=MY_APPS_USER”

So the only variables I pass are tag and my own username. All passwords and other environment variables are defined in ansible-vault file group_vars/UAT and so on. If I would want to schedule the concurrents I would pass one more variable for the date.

Even though this is just basic level scripting it has helped us a lot to reduce manual tasks and automate tasks which are error prone.

Leave a Reply

Your email address will not be published. Required fields are marked *