deploy/ansible/roles-sap/3.3-bom-processing/tasks/bom_processor.yaml (156 lines of code) (raw):
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
---
# /*---------------------------------------------------------------------------8
# | |
# | BOM Validation role |
# | |
# | Assumptions |
# | target_media_location exists on disk |
# | |
# | Inputs: |
# | target_media_location Default {{ target_media_location }}|
# | download_directory |
# | bom_name |
# | sapbits_location_base_path |
# | sapbits_bom_files |
# | sapbits_sas_token |
# | sapbits_access_key |
# | S_user |
# | S_password: |
# | download_directory: Default /mnt/downloads |
# | |
# |Locals: |
# | _bom |
# | item |
# | result |
# | |
# | BOM Fields: |
# | download |
# | archive |
# | permissions |
# | |
# | |
# | Steps: |
# | 01) Register BOM |
# | 02) Create static download directories |
# | 03) Create dynamic extract directories |
# | 04) Download media from bom |
# | 05) Extract files - SAPCAR |
# | 06) Extract files - UNRAR/UNAR |
# | 07) Extract files - UNZIP |
# | 08) Purge BOM file from Ansible Controller - TBD |
# |
# +------------------------------------4--------------------------------------*/
- name: "3.3 BoM Processing: - Register BoM"
ansible.builtin.include_role:
name: roles-sap/3.3.1-bom-utility
tasks_from: bom-register
vars:
inventory_dir: "{{ download_directory }}/bom"
task_prefix: "BOM Processing: "
# 02) Create static download directories
- name: "3.3 BoM Processing: - Create SAP download directories"
ansible.builtin.file:
path: "{{ item.path }}"
state: directory
mode: 0755
loop:
- path: "{{ target_media_location }}/tmp"
- path: "{{ target_media_location }}/downloads"
- path: "{{ target_media_location }}/download_basket"
# 03) Create dynamic extract directories
- name: "3.3 BoM Processing: - Create BOM directories"
ansible.builtin.file:
path: "{{ target_media_location }}/{{ item.extractDir }}"
state: directory
mode: 0755
loop: "{{ bom.materials.media | flatten(levels=1) }}"
when: not ((item.extractDir is undefined) or (item.extractDir == ''))
# Download Files
# ------------------<DEBUGGING>-------------------
- name: "3.3 BoM Processing: - Check if dynamic BOM download was performed successfully."
block:
- name: "3.3 BoM Processing: - Check if the item has dynamic property"
ansible.builtin.fail:
msg: "INSTALL:0023:Error while downloading BOM contents. Invalid BOM structure detected."
when:
- item.download is undefined or item.download
- item.dynamic is defined or item.archive is undefined
loop: "{{ bom.materials.media | flatten(levels=1) }}"
when:
- is_executed_by_acss
- name: "3.3 BoM Processing: - List files"
ansible.builtin.debug:
msg:
- "URL : {{ sapbits_location_base_path }}/{{ sapbits_bom_files }}/archives/{{ item.archive }}\
{% if sapbits_sas_token is not undefined %}?{{ sapbits_sas_token }}{% endif %}"
- "DEST: {{ target_media_location }}/{% if item.filename is undefined %}{{ item.archive }}{% else %}{{ item.filename }}{% endif %}"
- "MODE: {% if item.permissions is undefined %}0644{% else %}{{ item.permissions }}{% endif %}"
verbosity: 2
loop: "{{ bom.materials.media | flatten(levels=1) }}"
when:
- item.download is undefined or item.download
# ------------------</DEBUGGING>------------------
- name: "3.3 BoM Processing: - Set Python version {{ distribution_id }}"
ansible.builtin.set_fact:
python_version: 'python2'
when: (ansible_distribution | lower ~ ansible_distribution_major_version) in ['sles_sap12']
# 04) Download media from bom
# Loop through BOM media files and download to correct location
# validate checksum while downloading the files.
# For checksum validation, if we need to worry about portability, only the
# sha1 algorithm is available on all platforms and python versions.
# also, when we pass checksum if the file exists in destination it will be
# deleted if the checksum does not match and will be downloaded from URL
- name: "3.3 BoM Processing: - Creates temporary download directory"
become: true
ansible.builtin.file:
path: "{{ tmp_directory }}/tmp"
state: directory
mode: 0775
- name: "3.3 BoM Processing: - Download Files on {{ distribution_id }}"
ansible.builtin.get_url:
url: "{{ sapbits_location_base_path }}/{{ sapbits_bom_files }}/archives/{{ item.archive | string | trim }}\
{% if sapbits_sas_token is defined %}?{{ sapbits_sas_token }}{% endif %}"
dest: "{{ target_media_location }}/{% if item.path is undefined %}downloads{% else %}{{ item.path }}{% endif %}/\
{% if item.filename is undefined %}{{ item.archive }}{% else %}{{ item.filename }}{% endif %}"
mode: "{% if item.permissions is undefined %}0644{% else %}{{ item.permissions }}{% endif %}"
tmp_dest: "{{ target_media_location }}/tmp"
checksum: "{% if item.checksum is defined %}{% if item.checksum | trim | length > 1 %}sha256:{{ item.checksum | upper }}{% endif %}{% endif %}"
validate_certs: false
register: result
until: result is succeeded
retries: 2
loop: "{{ bom.materials.media | flatten(levels=1) }}"
when:
- item.download is undefined or item.download
- item.archive is defined
- item.archive | trim | length > 1
- distribution_id in ['suse15', 'redhat8', 'redhat9', 'sles_sap15' ]
delay: 5
vars:
ansible_python_interpreter: "{{ python_version }}"
- name: "3.3 BoM Processing: - Download Files on {{ distribution_id }}"
ansible.builtin.get_url:
url: "{{ sapbits_location_base_path }}/{{ sapbits_bom_files }}/archives/{{ item.archive | string | trim }}\
{% if sapbits_sas_token is not undefined %}?{{ sapbits_sas_token }}{% endif %}"
dest: "{{ target_media_location }}/{% if item.path is undefined %}downloads{% else %}{{ item.path }}{% endif %}/\
{% if item.filename is undefined %}{{ item.archive }}{% else %}{{ item.filename }}{% endif %}"
mode: "{% if item.permissions is undefined %}0644{% else %}{{ item.permissions }}{% endif %}"
checksum: "{% if item.checksum is defined %}{% if item.checksum | trim | length > 1 %}sha256:{{ item.checksum | upper }}{% endif %}{% endif %}"
tmp_dest: "{{ target_media_location }}/tmp"
validate_certs: false
register: result
until: result is succeeded
retries: 2
delay: 5
loop: "{{ bom.materials.media | flatten(levels=1) }}"
when:
- item.download is undefined or item.download
- distribution_id != 'suse15'
- distribution_id != 'sles_sap15'
- distribution_id != 'redhat8'
- distribution_id != 'redhat9'
- name: "3.3 BoM Processing: - Download result"
ansible.builtin.debug:
var: result
verbosity: 2
# 05) Extract files - SAPCAR
- name: "3.3 BoM Processing: - Extract File, SAPCAR"
ansible.builtin.command: "{{ target_media_location }}/downloads/SAPCAR -manifest SIGNATURE.SMF \
-xf {{ target_media_location }}/{% if item.path is undefined %}downloads{% else %}{{ item.path }}{% endif %}/\
{% if item.filename is undefined %}{{ item.archive }}{% else %}{{ item.filename }}{% endif %}"
args:
chdir: "{{ target_media_location }}/{{ item.extractDir }}"
creates: "{{ target_media_location }}/{{ item.extractDir }}/ \
{% if item.creates is defined %}{{ item.creates }}{% else %}NOT_DEFINED{% endif %}"
loop: "{{ bom.materials.media | flatten(levels=1) }}"
when:
- item.extract is not undefined
- item.extract
- ( item.filename is undefined and (item.archive | regex_search('[^.]+(?=\\.*$)') | upper=="SAR") ) or
( item.filename is defined and (item.filename | regex_search('[^.]+(?=\\.*$)') | upper=="SAR") )
# 06) Extract files - UNRAR
# Note: SAP has started to distribute Schema files packed as RAR files or spanned solid archives with self extracting EXE files against Zip files as before.
# This requires WinRAR or opensource RAR extractor.
# RHEL does not distibuted unrar anymore https://access.redhat.com/solutions/28959
# RHEL recommends using unarchiver ( alias : unar ) in EPEL repository from Fedora as unrar from https://www.rarlab.com does not cplies with OpenSource Licenses.
# This also presents another problem as the archive files will get unpacked into /usr/sap/install/CD_EXPORT/<package_ID>/<files> and will cause setup to fail.
# This issue is now being handled by process_exe_archives.yaml
# - name: "3.3 BoM Processing: - Extract File, UNRAR"
# ansible.builtin.command: "{% if (ansible_os_family | upper) == 'REDHAT' %}unar -s -D{% else %}unrar x{% endif %} {{ target_media_location }}/{% if item.path is undefined %}downloads{% else %}{{ item.path }}{% endif %}/{% if item.filename is undefined %}{{ item.archive }}{% else %}{{ item.filename }}{% endif %}"
# args:
# chdir: "{{ target_media_location }}/{{ item.extractDir }}"
# creates: "{{ target_media_location }}/{{ item.extractDir }}/\
# {% if item.creates is defined %}{{ item.creates }}{% else %}NOT_DEFINED{% endif %}"
# loop: "{{ bom.materials.media | flatten(levels=1) }}"
# when:
# - item.extract is not undefined
# - item.extract
# - ( item.filename is undefined and (item.archive |regex_search('[^.]+(?=\\.*$)')|upper=="RAR") ) or
# ( item.filename is defined and (item.filename|regex_search('[^.]+(?=\\.*$)')|upper=="RAR") ) or
# ( item.filename is undefined and (item.archive |regex_search('[^.]+(?=\\.*$)')|upper=="EXE") ) or
# ( item.filename is defined and (item.filename|regex_search('[^.]+(?=\\.*$)')|upper=="EXE") )
# 07) Extract files - UNZIP
- name: "3.3 BoM Processing: - Extract File, UNZIP"
ansible.builtin.unarchive:
src: "{{ target_media_location }}/{% if item.path is undefined %}downloads{% else %}{{ item.path }}{% endif %}/\
{% if item.filename is undefined %}{{ item.archive }}{% else %}{{ item.filename }}{% endif %}"
dest: "{{ target_media_location }}/{{ item.extractDir }}"
remote_src: true
creates: "{{ target_media_location }}/{{ item.extractDir }}/{% if item.creates is defined %}\
{{ item.creates }}{% else %}NOT_DEFINED{% endif %}"
loop: "{{ bom.materials.media | flatten(levels=1) }}"
when:
- item.extract is not undefined
- item.extract
- ( item.filename is undefined and (item.archive |regex_search('[^.]+(?=\\.*$)')|upper=="ZIP") ) or
( item.filename is defined and (item.filename|regex_search('[^.]+(?=\\.*$)')|upper=="ZIP") ) or
( item.filename is undefined and (item.archive |regex_search('[^.]+(?=\\.*$)')|upper=="TGZ") ) or
( item.filename is defined and (item.filename|regex_search('[^.]+(?=\\.*$)')|upper=="TGZ") )
# 07) Extract files - EXE
# - name: "3.3 BoM Processing: - Extract File, UNRAR"
# ansible.builtin.command: unrar x "{{ target_media_location }}/{% if item.path is undefined %}downloads{% else %}{{ item.path }}{% endif %}/\
# {% if item.filename is undefined %}{{ item.archive }}{% else %}{{ item.filename }}{% endif %}"
# args:
# chdir: "{{ target_media_location }}/{{ item.extractDir }}"
# creates: "{{ target_media_location }}/{{ item.extractDir }}/\
# {% if item.creates is defined %}{{ item.creates }}{% else %}NOT_DEFINED{% endif %}"
# loop: "{{ bom.materials.media|flatten(levels=1) }}"
# when:
# - item.extract is not undefined
# - item.extract
# - ( item.filename is undefined and (item.archive |regex_search('[^.]+(?=\\.*$)')|upper=="EXE") ) or
# ( item.filename is defined and (item.filename|regex_search('[^.]+(?=\\.*$)')|upper=="EXE") )
# 08) Extract files - EXE
- name: "3.3 BoM Processing: - Extract File, EXE"
ansible.builtin.include_tasks: "process_exe_archives.yaml"
loop: "{{ bom.materials.media | flatten(levels=1) }}"
when:
- item.extract is defined
- item.extract
- ( item.filename is undefined and (item.archive |regex_search('[^.]+(?=\\.*$)')|upper=="EXE") ) or
( item.filename is defined and (item.filename|regex_search('[^.]+(?=\\.*$)')|upper=="EXE") )
# -------------------------------------+---------------------------------------8
#
# Description: Process BOM dependencies.
# Call BOM processor, passing dependent BOM names.
#
# bom_processor.yaml
# Gather Dependencies
- name: "3.3 BoM Processing: - Gather all dependencies"
ansible.builtin.set_fact:
current_dependencies: "{{ bom.materials.dependencies | default([]) }}"
# Process Dependencies
- name: "3.3 BoM Processing: - Process each dependency"
ansible.builtin.include_tasks: "bom_processor.yaml"
vars:
bom_name: "{{ current_dep.name }}"
dependencies_processed: true
loop: "{{ current_dependencies | flatten(levels=1) }}"
loop_control:
loop_var: current_dep
when:
- current_dependencies | length > 0
- dependencies_processed is not defined
# -------------------------------------+---------------------------------------8
# # 08) Purge BOM file from Ansible Controller
# - name: "Ensure {{ bom_name }} is absent"
# ansible.builtin.file:
# path: "{{ inventory_dir }}/{{ bom_name }}.yaml"
# state: absent
# delegate_to: localhost
# -------------------------------------+---------------------------------------8
...