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:
- Install subversion & rsync to the server (these are needed)
- Delete old tag folder & export subversion tag folder defined in playbook
- Register all zips in tag to a variable
- Copy files to installation directory
- Grep and register user home to variable (apparently there is no easy way to get become_user home directory)
- Run CONCSUB on application server to submit concurrent request based on zip file name
- 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.