Ansible for SAP, In Depth — HANA System Replication, NetWeaver, Kernel Patching and Landscape Automation
In a nutshell
SAP is the software that runs the finance, supply chain, manufacturing, and HR of a large share of the world’s biggest companies. The team that keeps it alive — installing the database, tuning the operating system, patching, and making sure the whole thing survives a datacentre failure — is called SAP basis. Their work is governed by hundreds of vendor rules (called SAP Notes), and a single missed setting can turn a routine Saturday-night patch into a six-hour outage that shows up in Monday’s board meeting.
Ansible turns that pile of rules into code. Instead of a basis engineer working down a five-page checklist by hand at 2 a.m., a playbook applies every setting the same way, every time, on every host. Think of it as the pre-flight checklist for a jumbo jet: pilots do not trust memory for something this consequential — they read the list and tick every item, every single flight. Ansible is that checklist, executed by a machine that never skips a line and never gets tired.
The trick that keeps you sane is to stand on the vendor’s shoulders. Red Hat and the community publish certified collections (redhat.sap_install, community.sap_libs) that already encode those hundreds of SAP Notes and wrap the SAP installers. You do not hand-write the kernel tuning; you call the role that knows it. The rest of this lesson shows how a real landscape — HANA, NetWeaver, HA clustering, patching, transports — is built and operated from that foundation.
Level: Advanced · Time: ~40 min read
SAP is the production landscape that scares most automation teams. The runbooks read like vendor documentation written in 2002, the OS prerequisites are five pages long, and a single mis-tuned kernel parameter manifests as a six-hour HANA recovery. Ansible, used carefully, makes it tractable: every SAP Note becomes a role, every SID a host group, every transport a job template, every patch wave a workflow.
This lesson is the specialist guide to automating the SAP basis function with Ansible: preparing OS hosts to SAP standards, installing HANA scale-up and scale-out, configuring HANA system replication (HSR) with Pacemaker, deploying NetWeaver ABAP/Java instances, running kernel and SPS patches, importing transports, and running the whole landscape from AAP without becoming the bottleneck for every basis change request.
We will be opinionated. The Red Hat-supported sap_install and sap_hana_install collections are the path that keeps you out of trouble; we will use them. The Linux Pacemaker stack is the cluster that SAP itself documents; we will use it. The vendor-specific stacks (HP Serviceguard, Veritas) exist but do not integrate with Ansible cleanly; we will not cover them.
Position in the curriculum. Tier 1–4 fluency required, plus the Tier 5 compliance, DR, and migrations lessons. SAP environments are usually all three combined: regulated (SOX/PCI), high-availability/DR-critical, and constantly migrating between hardware refreshes and HANA SPS upgrades.
Before you start — prerequisites and outcomes
This is one of the most advanced lessons in the course. It assumes you are already comfortable with the Ansible fundamentals and can read a role without translating every line.
You should already be able to:
- Write and structure roles (tasks, defaults, handlers,
include_role/import_role) and split a project into small, rerunnable playbooks. - Model an estate with inventory groups and
group_vars/host_vars, and reason about variable precedence. - Encrypt secrets with Ansible Vault and keep them out of plaintext and logs (
no_log). - Control rollout with
serial,delegate_to, and rolling strategies — the patterns behind one-instance-at-a-time patching. - Handle disconnected estates using the air-gapped automation patterns (signed bundles, offline media) — SAP media handling reuses them directly.
After this lesson you will be able to:
- Lay out a repository that separates OS-prep, database, application, and orchestration into small playbooks that are cheap to rerun.
- Prepare a RHEL host to SAP-Note spec using the certified
redhat.sap_installpreconfigure roles — instead of transcribing Notes by hand. - Install HANA scale-up and wire two nodes into HANA System Replication (HSR) fronted by a Pacemaker cluster with STONITH.
- Deploy NetWeaver ASCS/ERS as a clustered pair and scale out PAS/AAS dialog instances idempotently.
- Patch the SAP kernel one instance at a time — ERS before ASCS, dialogs one-by-one — without taking the landscape down.
- Drive transports, run synthetic RFC smoke tests, and reason correctly about idempotency and check-mode for long, one-way, stateful installs.
If you are missing the prerequisites, read those lessons first — this one moves fast and does not re-teach them.
What “SAP automation” really covers
SAP basis is a small team supporting a sprawl of systems. The work splits into four buckets:
- OS preparation per SAP Notes: kernel parameters, swap, transparent huge pages, NUMA topology, filesystem layouts, NTP/chrony, SELinux rules, network MTUs. Driven by SAP Notes (e.g., 2009879 for RHEL 7, 2235581 for RHEL 8, 3108316 for RHEL 9). Every Note has a hundred line items.
- Database installation and patching: HANA installs, SPS upgrades, kernel patching, parameter tuning, HSR setup, backup/recovery configuration.
- Application server installation and patching: NetWeaver ABAP and Java stacks, kernel patches, transport imports, profile parameter management.
- Landscape orchestration: refresh of QA from production, system copy automation, transport imports across the landscape (DEV → QA → PRD), service start/stop coordination during patching.
Ansible handles all four; the key is to use the SAP-supported collections rather than reinventing the wheel. Three collections matter:
redhat.sap_install— installs and configures SAP NetWeaver (ABAP + Java).redhat.sap_hana_install— installs SAP HANA scale-up and scale-out.community.sap_install— community-maintained variants and helpers.redhat.sap_management— operations: start/stop, kernel patching, HSR setup, RHEL HA cluster.
These collections wrap sapinst, hdblcm, pcs, and the various SAP CLI tools, and bake in the conditionals from the SAP Notes. The collections are kept current with SAP releases by Red Hat — using them is how you avoid building a 5,000-line in-house “sap_role” that breaks every quarter.
How to read the collection landscape (beginner orientation). The names above are the logical building blocks this lesson uses; on a real machine you will meet a slightly different, evolving set. It helps to hold two categories in your head:
| You need to… | Reach for | What it is |
|---|---|---|
| Prepare the OS, install HANA/NetWeaver, build HA clusters | redhat.sap_install (roles like sap_general_preconfigure, sap_hana_preconfigure, sap_hana_install, sap_swpm, sap_ha_pacemaker_cluster) |
Red Hat’s certified, supported collection — the consolidated “do the heavy lifting” roles |
| Talk to a running SAP system (RFC, hdbsql, sapcontrol, apply a Note, run a task list) | community.sap_libs (modules like sap_pyrfc, sap_hdbsql, sap_control_exec, sap_snote, sap_task_list_execute, sapcar_extract) |
Community modules for day-2 operations against an installed system |
| Provision cloud/VM infrastructure under SAP | your cloud collection (amazon.aws, azure.azcollection, google.cloud) + ansible.posix, community.general |
The bottom layer the SAP roles sit on |
The exact collection and role names shift release to release (Red Hat has been consolidating several older, separately-named collections into redhat.sap_install). The durable idea is the split above: certified roles do the install; community modules operate the running system. We revisit versioning discipline in Going deeper.
A representative SAP landscape
For concreteness, the rest of this lesson assumes a typical mid-size production landscape:
- Three-tier HANA scale-up landscape: DEV (single-host HANA + ASCS/PAS/AAS NetWeaver), QA (mirror of PRD with 1/4 sizing), PRD (HANA HSR with two nodes + Pacemaker, ASCS/ERS HA cluster, four PAS+AAS dialog instances).
- SID conventions: HDB system ID for HANA (e.g.,
S4P= production S/4HANA,S4Q= QA,S4D= DEV). - OS: RHEL 9 with SAP HA solutions repo enabled (
rhel-9-for-x86_64-sap-solutions-rpms). - Storage: NetApp ONTAP for
/hana/data,/hana/log,/hana/shared; XFS on top. - Network: separate NICs for client traffic, HSR replication, internal NetWeaver, and admin.
- Identity: SAP service users (
<sid>adm,sapadm,sapsys) created consistently across hosts. - DR: HANA HSR cross-site, Pacemaker takeover, virtual IP failover.
This landscape is what 80% of enterprise SAP shops look like; the Ansible patterns scale to scale-out HANA and to S/4HANA Cloud private edition with minor adjustments.
The SAP repository layout
sap-automation/
├── ansible.cfg
├── collections/requirements.yml # redhat.sap_install,
│ # redhat.sap_hana_install,
│ # redhat.sap_management,
│ # community.sap_install,
│ # ansible.posix, community.general
├── inventory/
│ ├── prd/ # production
│ │ └── hosts.yml # hana_primary, hana_secondary, ascs, ers, pas, aas
│ ├── qa/ # quality assurance
│ └── dev/ # development
├── group_vars/
│ ├── all/
│ │ ├── sap_landscape.yml # SID, instance numbers, DB connect strings
│ │ └── vault.yml # sap_installer_password, hana_master_pw, sapsys gid
│ ├── hana/
│ │ ├── sap_hana_install.yml
│ │ └── hana_hsr.yml
│ ├── netweaver/
│ │ ├── sap_install.yml
│ │ └── ascs_ers_cluster.yml
│ └── all_sap/
│ └── os_prep.yml # SAP Notes-driven kernel/sysctl/limits/THP
├── playbooks/
│ ├── 00-os-prep.yml
│ ├── 10-hana-install-primary.yml
│ ├── 11-hana-install-secondary.yml
│ ├── 12-hana-hsr-enable.yml
│ ├── 13-hana-pacemaker.yml
│ ├── 20-netweaver-ascs-install.yml
│ ├── 21-netweaver-ers-install.yml
│ ├── 22-netweaver-pas-install.yml
│ ├── 23-netweaver-aas-install.yml
│ ├── 30-kernel-patch.yml
│ ├── 31-hana-sps-patch.yml
│ ├── 40-system-refresh-prd-to-qa.yml
│ ├── 50-transport-import.yml
│ └── 99-decommission.yml
└── roles/
├── sap_os_prep/ # wraps SAP Notes per RHEL major version
├── sap_storage_layout/
├── sap_users_groups/
├── sap_install_media_stage/
├── sap_hana_install_wrapper/ # wraps redhat.sap_hana_install with our defaults
├── sap_hana_hsr/
├── sap_pacemaker_cluster/
├── sap_netweaver_install_wrapper/
├── sap_kernel_patch/
├── sap_transport_import/
├── sap_validate/
└── sap_evidence/
The split is deliberate: small playbooks per phase (so a rerun is cheap), wrapper roles around the upstream collections (so we can layer in our defaults), and shared roles for OS prep, storage and users (so DEV/QA/PRD are built from the same code).
Two naming ideas earn their keep here for a beginner: the numeric playbook prefixes (00, 10, 11…) encode the order a landscape is built in — you can literally read the build sequence off ls; and the _wrapper suffix flags “this role calls a vendor role but adds our house defaults,” so nobody edits the vendor role directly.
OS preparation per SAP Notes
Every SAP installation begins with OS preparation. The relevant SAP Notes for RHEL 9 are 3108316 (general), 2002167 (NetApp NFS for HANA), 2382421 (Linux kernel parameters), and 1771258 (Linux NUMA layout). Each Note is a list of conditionals; together they fill several pages.
Rather than transcribe Notes manually, use redhat.sap_install.sap_general_preconfigure (and its sibling roles) which encode the Notes for you:
# playbooks/00-os-prep.yml
---
- name: SAP OS preparation (per SAP Notes)
hosts: all_sap
become: true
collections:
- redhat.sap_install
roles:
- role: sap_general_preconfigure
vars:
sap_general_preconfigure_modify_etc_hosts: false # we manage hosts via dnsmasq/cloud DNS
sap_general_preconfigure_kernel_parameters_2382421: true
sap_general_preconfigure_min_swap_space: 20480 # MB
- role: sap_hana_preconfigure
when: "'hana' in group_names"
vars:
sap_hana_preconfigure_kernel_parameters_NetApp: true
sap_hana_preconfigure_thp: never
sap_hana_preconfigure_numa_balancing: 0
- role: sap_netweaver_preconfigure
when: "'netweaver' in group_names"
Under the hood these roles set:
kernel.shmmax,kernel.shmallto large values.vm.swappiness=10,vm.dirty_ratio=10,vm.dirty_background_ratio=3.transparent_hugepage=never(HANA explicitly hates THP).tuned-adm profile sap-hana(orsap-netweaver).numa balancingdisabled on HANA hosts.- File limits in
/etc/security/limits.d/99-sap.conffor<sid>adm. - Selected SELinux booleans per SAP Note 2456406.
The tuned profiles are the most opinionated piece; they tune the entire kernel for SAP workloads. Run tuned-adm active after to verify.
Why this is the highest-leverage automation you own. These preconfigure roles are the one part of the stack that is genuinely idempotent and check-mode-friendly (see Going deeper). That means you can run them repeatedly, in --check mode, as a compliance probe — “is Note 2382421 still applied on all 40 hosts?” — not just as a one-time installer. When an auditor asks, the answer is a green playbook run, not a screenshot.
Storage layout
HANA has strict storage layout requirements. Every basis team has a story about a single mis-laid filesystem that took down a quarterly close. Use a dedicated role and lock the values down:
# roles/sap_storage_layout/tasks/main.yml
---
- name: Create HANA volume groups (LVM)
community.general.lvg:
vg: "vg_hana_{{ item.name }}"
pvs: "{{ item.pvs }}"
loop:
- { name: "data", pvs: "/dev/disk/by-id/{{ data_disk }}" }
- { name: "log", pvs: "/dev/disk/by-id/{{ log_disk }}" }
- { name: "shared", pvs: "/dev/disk/by-id/{{ shared_disk }}" }
- name: Create HANA logical volumes
community.general.lvol:
vg: "vg_hana_{{ item.vg }}"
lv: "lv_{{ item.name }}"
size: "{{ item.size }}"
state: present
loop:
- { vg: data, name: data, size: "{{ hana_data_size }}" }
- { vg: log, name: log, size: "{{ hana_log_size }}" }
- { vg: shared, name: shared, size: "{{ hana_shared_size }}" }
- name: Create HANA filesystems (XFS, 4K)
community.general.filesystem:
fstype: xfs
dev: "/dev/mapper/vg_hana_{{ item.vg }}-lv_{{ item.name }}"
opts: "-f -K -d agcount=64"
loop: "{{ hana_lvs }}"
- name: Mount HANA filesystems
ansible.posix.mount:
src: "/dev/mapper/vg_hana_{{ item.vg }}-lv_{{ item.name }}"
path: "{{ item.path }}"
fstype: xfs
opts: "noatime,inode64,nobarrier"
state: mounted
loop:
- { vg: data, name: data, path: "/hana/data/{{ sid }}" }
- { vg: log, name: log, path: "/hana/log/{{ sid }}" }
- { vg: shared, name: shared, path: "/hana/shared" }
The mount options matter: inode64 for large filesystems, noatime for performance, nobarrier only when underlying storage has battery-backed write cache (NetApp, modern enterprise SAN — never for cloud EBS without io2 Block Express). Read SAP Note 1944799 before deviating.
For cloud SAP (AWS X1/X2, Azure M-series, GCP m2/m3), the corresponding native disk products replace the LVM steps but the mount options stay the same.
HANA scale-up install
redhat.sap_hana_install wraps hdblcm with the exact answer-file format SAP expects. The role accepts a structured set of vars; you do not edit hdblcm arguments directly.
# playbooks/10-hana-install-primary.yml
---
- name: Install HANA on primary node
hosts: hana_primary
become: true
collections:
- redhat.sap_hana_install
vars:
sap_hana_install_software_directory: /sapmedia/HANA_2_SPS07
sap_hana_install_sid: "{{ sid }}"
sap_hana_install_instance_number: "00"
sap_hana_install_master_password: "{{ vault_hana_master_password }}"
sap_hana_install_use_master_password_for_users: true
sap_hana_install_system_usage: production
sap_hana_install_apply_license: true
sap_hana_install_license_path: /sapmedia/license/license-{{ sid }}.txt
sap_hana_install_components:
- server
- client
- studio
- xs
roles:
- role: sap_install_media_stage # ensures HANA media is on host (NFS/scratch)
- role: sap_hana_install_wrapper # invokes redhat.sap_hana_install role
- role: sap_hana_post_install # license, audit, parameters
The most frequent install bug is media that is not fully extracted; sap_install_media_stage should verify the SAR/EXE checksums and unpack to a known location before HANA install begins.
The post-install role applies parameters (global.ini, indexserver.ini) using redhat.sap_management.sap_hana_set_parameters. Common defaults set:
[persistence] log_mode = normal[multidb] mode = multidb(for MDC)[memorymanager] global_allocation_limit(per SAP sizing report)[trace] default = info
HANA System Replication (HSR)
HSR is the critical-path DR feature of HANA. It replicates redo logs from primary to secondary in three modes:
- Sync — primary commits only after secondary acknowledges. RPO=0, performance hit.
- SyncMem — secondary acknowledges in memory, no fsync. RPO ≈ 0, less performance hit.
- Async — secondary acknowledges after receive. RPO seconds, no performance hit.
At a glance, so a beginner can choose without re-reading the paragraph:
| Mode | Commit waits for | RPO (data loss) | Performance cost | Typical use |
|---|---|---|---|---|
sync |
secondary persisted to disk | 0 | Highest | Two datacentres on one campus; zero-data-loss mandated |
syncmem |
secondary received into memory | ≈ 0 | Moderate | Same-region HA pair — the common default |
async |
local commit only (fire-and-forget) | seconds | Lowest | Cross-region DR; accept some loss on a forced takeover |
replicationMode (the table above) is only half the picture. operationMode is the second axis: logreplay (secondary continuously replays redo → fast takeover, the modern default, and what the register command below uses) versus the older delta_datashipping (slower to take over). You almost always want logreplay.
For two-DC same-region HSR, use SyncMem; for cross-region, use Async with a clear understanding that some transactions will be lost on a forced failover.
Ansible automates HSR setup once HANA is installed on both nodes:
# playbooks/12-hana-hsr-enable.yml
---
- name: Enable HSR primary
hosts: hana_primary
become: true
tasks:
- name: Enable system replication on primary
ansible.builtin.command:
cmd: |
su - {{ sid_lc }}adm -c "
hdbnsutil -sr_enable --name=DC1
"
register: enable
changed_when: "'successfully enabled' in enable.stdout"
- name: Enable HSR secondary (after key copy)
hosts: hana_secondary
become: true
tasks:
- name: Stop HANA on secondary (must be down for register)
ansible.builtin.command:
cmd: su - {{ sid_lc }}adm -c "HDB stop"
- name: Copy SSFS keys from primary to secondary
ansible.posix.synchronize:
src: "/usr/sap/{{ sid }}/SYS/global/security/rsecssfs/"
dest: "/usr/sap/{{ sid }}/SYS/global/security/rsecssfs/"
delegate_to: "{{ groups['hana_primary'][0] }}"
- name: Register secondary with primary
ansible.builtin.command:
cmd: |
su - {{ sid_lc }}adm -c "
hdbnsutil -sr_register
--remoteHost={{ hostvars[groups['hana_primary'][0]].ansible_host }}
--remoteInstance={{ instance_number }}
--replicationMode=syncmem
--operationMode=logreplay
--name=DC2
"
register: register
- name: Start HANA on secondary
ansible.builtin.command:
cmd: su - {{ sid_lc }}adm -c "HDB start"
- name: Verify replication is in sync
hosts: hana_primary
become: true
tasks:
- name: Query HSR state
ansible.builtin.command:
cmd: |
su - {{ sid_lc }}adm -c "
python /usr/sap/{{ sid }}/HDB{{ instance_number }}/exe/python_support/systemReplicationStatus.py
"
register: hsr_state
retries: 30
delay: 10
until: "'Replication mode' in hsr_state.stdout and 'OPERATION MODE' in hsr_state.stdout"
The systemReplicationStatus.py query is the canonical “is HSR healthy?” check; the role retries until the status line shows the secondary as ACTIVE. Wire this into a periodic redhat.sap_management.sap_hana_check_hsr_status job in AAP that runs every 5 minutes and pages on degradation.
Pacemaker cluster for HANA HSR
The official Linux HA cluster for HANA on RHEL is Pacemaker with the SAPHana and SAPHanaTopology resource agents. redhat.sap_management.sap_ha_pacemaker_cluster wraps the entire setup:
# playbooks/13-hana-pacemaker.yml
---
- name: HANA Pacemaker HA
hosts: hana_cluster
become: true
collections:
- redhat.sap_management
vars:
sap_ha_cluster_node_list:
- "{{ groups['hana_primary'][0] }}"
- "{{ groups['hana_secondary'][0] }}"
sap_ha_cluster_authkey: "{{ vault_pcsd_password }}"
sap_ha_cluster_hacluster_password: "{{ vault_hacluster_password }}"
sap_ha_cluster_resource_stonith: fence_aws # or fence_vmware_rest, fence_ipmilan
sap_ha_cluster_resource_vip: "{{ hana_virtual_ip }}"
sap_ha_cluster_resource_vip_secondary: "{{ hana_secondary_vip }}"
sap_ha_cluster_sid: "{{ sid }}"
sap_ha_cluster_instance_number: "{{ instance_number }}"
roles:
- sap_ha_install_pacemaker
- sap_ha_pacemaker_cluster
- sap_ha_install_hana_hsr_angi # ANGI = Active Next Generation Implementation
The cluster:
- Runs SAPHanaTopology on every node, which monitors HANA and reports state to Pacemaker.
- Runs the SAPHana primitive in master/slave mode; the master is the primary, the slave is the secondary.
- Floats a virtual IP on the primary node — clients connect to the VIP, not to a hostname per node.
- Includes a STONITH agent (fence_aws for EC2, fence_vmware_rest for vSphere, fence_ipmilan for bare-metal). Without STONITH, the cluster will not start; do not disable it “for testing.”
The cluster takeover behaviour you actually care about:
- Primary node failure — Pacemaker detects, fences the dead node, promotes secondary, moves VIP. Application reconnects within ~30s.
- HSR replication failure — Pacemaker does NOT take over; it raises a flag. Manual intervention (re-establish HSR) required.
- Network partition — STONITH ensures only one node remains, preventing split brain.
- Manual operator-driven takeover —
pcs resource movetriggers a controlled failover; useful for kernel patching.
NetWeaver ASCS/ERS HA
NetWeaver also needs HA. The ASCS instance (Application Server Central Services) and the ERS instance (Enqueue Replication Server) form a clustered pair. They share NFS-mounted directories (/sapmnt, /usr/sap/<SID>/ASCS<NN>).
# playbooks/20-netweaver-ascs-install.yml
- hosts: ascs
become: true
collections:
- redhat.sap_install
vars:
sap_swpm_inifile_list:
- PRD-NW-ASCS-INI
sap_swpm_template_inifile: ascs.params.j2
roles:
- sap_install_media_stage
- sap_install # wraps SWPM (sapinst)
For the cluster:
# playbooks/21-netweaver-cluster.yml
- hosts: ascs_ers_cluster
become: true
collections:
- redhat.sap_management
vars:
sap_ha_cluster_resource_stonith: fence_vmware_rest
sap_ha_cluster_resource_vip: "{{ ascs_vip }}"
sap_ha_cluster_resource_vip_ers: "{{ ers_vip }}"
sap_ha_cluster_sid: "{{ sid }}"
sap_ha_cluster_ascs_instance_number: "00"
sap_ha_cluster_ers_instance_number: "10"
roles:
- sap_ha_install_pacemaker
- sap_ha_pacemaker_cluster_nw
The Pacemaker resources for NetWeaver:
SAPInstancefor ASCS, withSTART_PROFILEpointing at the central services profile.SAPInstancefor ERS, with the enqueue replicator profile.- A constraint that ASCS and ERS prefer different nodes (
locationrule withscore=-INFINITY). - A virtual IP for ASCS and one for ERS.
- An NFS shared filesystem resource (or NFS-handled-externally if using EFS/Azure Files).
Without ERS replication, an ASCS failover loses every uncommitted lock, which translates to user-visible “wait, I need to redo my entry” errors. ERS keeps the lock table mirrored.
Dialog instances (PAS, AAS)
The PAS (Primary Application Server) and AAS (Additional Application Server) are not clustered; they are scaled out behind the SAP Web Dispatcher or the load balancer. Ansible installs each instance idempotently:
# playbooks/22-netweaver-pas-install.yml
- hosts: pas
become: true
collections:
- redhat.sap_install
vars:
sap_swpm_inifile_list:
- PRD-NW-PAS-INI
roles:
- sap_install_media_stage
- sap_install
# playbooks/23-netweaver-aas-install.yml
- hosts: aas
become: true
collections:
- redhat.sap_install
vars:
sap_swpm_inifile_list:
- PRD-NW-AAS-INI
roles:
- sap_install_media_stage
- sap_install
The point is repeatability: when you scale out a fifth dialog instance during peak season, the playbook is the same one that built the first four. No “manual install with screenshots” runbook.
Kernel patching (SAP kernel, not Linux kernel)
The SAP kernel ships separately from the application stack. Patching is a quarterly-or-better activity. The pattern with Ansible:
# playbooks/30-kernel-patch.yml
- name: SAP kernel patch
hosts: sap_landscape
become: true
serial: 1 # one host at a time, controlled
collections:
- redhat.sap_management
tasks:
- import_role:
name: sap_kernel_patch
vars:
sap_kernel_patch_target_kernel: 7.94 # canonical version
sap_kernel_patch_media_dir: /sapmedia/kernel/7.94
sap_kernel_patch_pre_check: true
sap_kernel_patch_backup_old: true
sap_kernel_patch_post_validate: true
The sap_kernel_patch role:
- Stops the instance gracefully (
stopsapor systemd target). - Backs up
/sapmnt/<SID>/exeand/usr/sap/<SID>/SYS/exe. - Extracts the new kernel SAR files via
SAPCAR. - Updates symlinks.
- Runs
saproot.sh. - Starts the instance.
- Validates with
disp+work -Vand a basic transaction (SE38test program via SAP RFC if RFC creds available).
Patching is serial: 1 because you patch one instance at a time across the landscape — never simultaneously across an HA pair. For ASCS/ERS, you patch the ERS first (drains locks), failover, patch the ASCS, fail back. For PAS/AAS, you patch one dialog at a time so the load balancer drains and re-adds it cleanly.
Transport imports
SAP changes (development objects, configuration, customising) move across the landscape as transports: dev-side tp exports, QA-side imports, then PRD imports. Ansible can drive imports cleanly:
# playbooks/50-transport-import.yml
- hosts: ascs # CI host runs from the Application Server side
become_user: "{{ sid_lc }}adm"
collections:
- community.sap_install
vars:
transport_request: "PRDK900153"
transport_target_system: PRD
tasks:
- name: Add request to import queue
ansible.builtin.command:
cmd: |
tp addtobuffer {{ transport_request }} {{ transport_target_system }}
-Dpf=/usr/sap/trans/bin/TP_DOMAIN_PRD.PFL
register: add_buffer
- name: Import the request
ansible.builtin.command:
cmd: |
tp import {{ transport_request }} {{ transport_target_system }}
client=100
-Dpf=/usr/sap/trans/bin/TP_DOMAIN_PRD.PFL
U126 # ignore inactive imports as needed
register: tp_import
failed_when: tp_import.rc not in [0, 4] # 0 = clean, 4 = warnings
- name: Persist tp logs
ansible.builtin.fetch:
src: "/usr/sap/trans/log/{{ transport_request }}.{{ transport_target_system }}"
dest: "./tp-logs/"
flat: true
The interesting AAP-level orchestration is the change ticket gate: a survey job template asks for a CHG ticket number, calls ServiceNow to verify the ticket is in “Implement” state, and then dispatches the transport import. The ITSM and ChatOps lesson covers this pattern in detail.
System refresh (PRD → QA)
System refresh is the periodic operation of “make QA look like PRD again.” It is high-risk and historically very manual. Ansible automates the whole flow:
- Pre-refresh export of QA-only data (test users, test customising) that you want to preserve.
- HANA backup on PRD → restore on QA via
hdbsqlandrecoverSys.py. - Post-refresh import of QA-only data.
- Customising adjustments for QA (e.g., disable email outputs, redirect printers, mask sensitive tables).
- Smoke test with predefined transactions.
The Ansible role for this is large but the structure is simple: it is just a long playbook with many tasks, each guarded by tags so a partial re-run is feasible. The single most important rule: the refresh must be idempotent on retry, because the first attempt almost always finds something the team forgot.
Validation: synthetic transactions, not just service checks
After every patch, install, or HSR operation, run a synthetic SAP transaction. The community.sap_install.sap_rfc_call module wraps PyRFC to call any RFC-enabled function module:
- name: Smoke test — RFC ping
community.sap_install.sap_rfc_call:
sap_host: "{{ ascs_vip }}"
sap_sysnr: "00"
sap_client: "100"
sap_user: "{{ vault_smoke_test_user }}"
sap_password: "{{ vault_smoke_test_password }}"
function: "STFC_CONNECTION"
parameters:
REQUTEXT: "ansible-{{ ansible_date_time.epoch }}"
register: rfc
no_log: true
- name: Assert RFC works
ansible.builtin.assert:
that: rfc.return_value.ECHOTEXT == "ansible-{{ ansible_date_time.epoch }}"
STFC_CONNECTION is the canonical “round-trip” RFC; it proves the entire stack — from VIP to dispatcher to work process — is functional. After kernel patches, run this. After HSR takeover, run this. After every transport import, run this.
Module-name note (current collections). The example above uses the lesson’s
community.sap_install.sap_rfc_callnaming. On a current control node the community RFC module you will most often install iscommunity.sap_libs.sap_pyrfc, which takes aconnection:dict and afunction:/parameters:pair. The Practice challenges below use thecommunity.sap_libsnames so you have both spellings side by side — checkansible-galaxy collection listand the module--docfor the exact names in your environment before you copy either.
SAP-on-Cloud specifics
Ansible is the same; cloud-specific roles change. AWS, Azure, and GCP each have a “SAP on cloud” reference architecture that Ansible automates:
- AWS: X1/X2/u-* instances for HANA; EFS or FSx ONTAP for
/sapmnt; AWS Backup for HANA backup; Route 53 for VIP failover (oftenaws clifrom a Pacemaker resource agent). - Azure: M-series VMs; ANF (Azure NetApp Files) for
/hana/dataand/sapmnt; Azure Site Recovery for DR; Azure Load Balancer with floating IPs. - GCP: m2/m3 instances; Filestore for
/sapmnt; GCS for backups; internal TCP load balancer for VIPs.
Ansible roles wrap the cloud-specific provisioning steps; the SAP-specific roles (HANA install, NetWeaver, kernel patch) are unchanged. This is the pattern that makes Ansible a good fit: cloud-specific bottom layer + cloud-agnostic SAP layer on top.
For air-gapped SAP (defence sector, highly regulated banking core), SAP runs on private infrastructure and the air-gap discipline from the previous lesson applies: HANA media, kernel SAR files, and SPS bundles are all imported via signed bundles.
Going deeper
Everything above builds a landscape. This section is about the parts that separate a demo from a system a basis team trusts on a Saturday-night change window: idempotency on one-way installers, where check-mode helps and where it lies, the media/S-user problem, the certified path, scale, secrets, and collection versioning.
Why “idempotent” is hard for a HANA install
Ansible’s promise is idempotency: run the playbook twice, the second run changes nothing. But the underlying SAP tools — hdblcm, sapinst/SWPM — are not idempotent. Re-run hdblcm against an installed SID and it errors out (or worse, half-does something). The installer is a one-way gate, like pouring concrete.
So the idempotency lives in the wrapper, not the installer. The pattern: probe for existing state, then guard the install with when:.
# roles/sap_hana_install_wrapper/tasks/main.yml (excerpt)
- name: Detect an existing HANA installation
ansible.builtin.stat:
path: "/usr/sap/{{ sid }}/HDB{{ instance_number }}/exe/sapcontrol"
register: hana_present
- name: Install HANA only when it is not already present
ansible.builtin.include_role:
name: redhat.sap_install.sap_hana_install
when: not hana_present.stat.exists
The same idea makes a command:-driven service action idempotent. Never write a bare HDB start that always reports changed. Probe first, act conditionally, and set changed_when honestly:
- name: Probe HANA process state (read-only — never 'changed')
community.sap_libs.sap_control_exec:
sysnr: "{{ instance_number }}"
command: GetProcessList
register: hana_procs
changed_when: false
failed_when: false
- name: Start HANA only if it is not already GREEN
community.sap_libs.sap_control_exec:
sysnr: "{{ instance_number }}"
command: StartSystem
when: "'GREEN' not in (hana_procs.out | default(''))"
The two habits that make long installs safe to re-run: (1) a stat/probe task with changed_when: false in front of every irreversible step, and (2) register + changed_when/failed_when on every command/shell so Ansible’s idea of “changed” and “failed” matches reality rather than the exit code of su - <sid>adm -c ... (which is almost always 0).
Check mode: where it works and where it lies
--check (dry run) is a beginner’s favourite safety net. On SAP it is a split reality:
| Layer | --check behaviour |
What to do |
|---|---|---|
OS-prep roles (sap_*_preconfigure), sysctl, mounts, packages |
Honest — reports the drift it would fix | Run in --check as a compliance/drift probe on a schedule |
Install roles (hdblcm/SWPM wrappers), HSR register, cluster build |
Cannot meaningfully dry-run a real installer | Treat as non-check islands; rehearse on a sandbox SID |
A command: task runs nothing in check mode by default, so a play that is “green in check mode” may have skipped the entire install and told you nothing. Two guard rails:
- Mark tasks that must never run in check mode with
check_mode: falseonly when they are safe read-only probes; for genuinely mutating installer steps, gate the whole play behind an explicit--limit sandboxfirst. - Add an early
ansible.builtin.assertpreflight (RAM, repo, free space) — asserts do evaluate in check mode, so your dry run at least validates the environment even when it cannot validate the install.
The mental model: check-mode audits your OS-prep; it does not simulate your installs. Rehearsal on a throwaway SID is the substitute for a dry-run install.
Media handling and the S-user problem
SAP media (the HANA .SAR/.EXE bundles, kernel SAR files, SPS stacks) is enormous, versioned, and only downloadable from SAP’s portal authenticated by an S-user (a support-account login like S0001234567). This is the single biggest real-world friction, and it is where secrets most often leak.
Two sane patterns, in order of preference:
-
Pre-stage to an internal mirror (recommended). A basis engineer downloads media once to an internal artefact store / object bucket / NFS export. Hosts pull from there with an integrity check — no S-user ever touches a managed host. This is exactly the air-gapped bundle discipline.
- name: Stage HANA server media from the internal mirror (integrity-checked, idempotent) ansible.builtin.get_url: url: "https://artifacts.internal.example/sap/HANA_2_SPS07/IMDB_SERVER.SAR" dest: "/sapmedia/HANA_2_SPS07/IMDB_SERVER.SAR" checksum: "sha256:{{ hana_server_sar_sha256 }}" mode: "0640" - name: Extract the SAR with SAPCAR community.sap_libs.sapcar_extract: path: "/sapmedia/HANA_2_SPS07/IMDB_SERVER.SAR" dest: "/sapmedia/HANA_2_SPS07/extracted" binary_path: "/sapmedia/tools/SAPCAR"get_urlwithchecksum:is both idempotent (skips an already-correct file) and tamper-evident — the two properties that matter for “the install failed because the media was truncated,” which is the most common HANA install bug. -
Download by number with the
community.sap_launchpadcollection. For estates that must pull directly, the S-user credentials live only in Vault, are passed withno_log: true, and are never templated into a host file.# group_vars/all/vault.yml → ansible-vault encrypt this file. Values are PLACEHOLDERS. vault_sap_suser: "S0000000000" # your S-user id vault_sap_suser_password: "REPLACE_VIA_VAULT" # never a real secret in git
Whichever pattern you pick: checksum every artefact, extract to a deterministic path, and keep the S-user out of managed hosts and out of git.
Post-install config the idempotent way (Notes and task lists)
Once a system is running, day-2 configuration should stop shelling out and start using purpose-built, idempotent modules from community.sap_libs:
- name: Apply a corrective SAP Note (idempotent — skips if already implemented)
community.sap_libs.sap_snote:
conn_username: "DDIC"
conn_password: "{{ vault_ddic_password }}"
host: "{{ ascs_vip }}"
sysnr: "00"
client: "000"
snote_path: "/sapmedia/notes/0003089413.txt"
no_log: true
- name: Run a post-install ABAP task list (STC01 — idempotent by design)
community.sap_libs.sap_task_list_execute:
conn_username: "DDIC"
conn_password: "{{ vault_ddic_password }}"
host: "{{ ascs_vip }}"
sysnr: "00"
client: "000"
task_to_execute: "SAP_BASIS_SSL_CHECK"
no_log: true
sap_snote checks whether the Note is already implemented and no-ops if so — that is real idempotency for stateful application config, not a command: wrapper pretending. Task lists (transaction STC01) are the ABAP world’s own idempotent runbooks; driving them from Ansible means “post-install step 14” is versioned code, not a wiki page.
The certified reference architectures — and why you stay on them
SAP support is conditional. Run HANA on an un-certified stack and, when you open a priority-one ticket at hour three of an outage, the first response may be “not a supported configuration.” So the automation’s job is not just “install HANA” — it is “install HANA on the certified path and prove it.” Concretely that means:
- RHEL for SAP Solutions subscription (not plain RHEL) — it carries the
tunedsap-hana/sap-netweaverprofiles, the HA resource agents, and the extended update support SAP requires. - The certified resource agents: classic
SAPHanaSRor the newerSAPHanaSR-angi(“Active/Next-Generation Interface”) — the same ANGI role the Pacemaker play pulls in above. Mixing agent generations across a cluster is unsupported. - SAP-certified instance types on each cloud (AWS X/U-series, Azure M-series, GCP m-series) — sizing and the certification list are non-negotiable inputs, not tuning knobs.
The Ansible pay-off: the certified choices become variables with locked defaults in a wrapper role, so “are we still on the supported path?” is answered by reading group_vars, and drift away from it is a failed assertion, not a surprise during a Sev-1.
Performance and long-running tasks at landscape scale
The control node is almost never the bottleneck in SAP automation — the SAP hosts are (an hdblcm run is tens of minutes; an SPS upgrade can be hours). Two levers matter:
-
serialandorderfor controlled rollout (deep-dived in the serial/rolling strategies lesson).serial: 1plusorder: inventorylets you dictate ERS-before-ASCS, dialogs one at a time — the difference between a rolling patch and a full outage. -
async+pollfor tasks that outlive the SSH/connection timeout. A two-hour SPS upgrade run as a normal task will trip the persistent-connection timeout. Run it detached and poll:- name: Long-running SPS upgrade (survives connection timeouts) ansible.builtin.command: cmd: "/sapmedia/SPS/SUM/STARTUP confirm" # invoked by the wrapper role in practice async: 14400 # allow up to 4 hours poll: 60 # Ansible checks back every 60sSet
poll: 0to fire-and-forget and reap later withansible.builtin.async_status— useful when you kick off the same long step on many hosts and want them running in parallel rather than serialised behind one another.
forks and fact caching help a 200-host landscape’s fast phases (OS-prep, probes); they do nothing for the slow single-host installer steps — those are gated by the SAP tools, so plan windows around them.
Secrets: the SAP vault sprawl
SAP has an unusually large secret surface. A single production HANA + NetWeaver stack can involve: the HANA master password, the <sid>adm OS password, the DDIC/SYSTEM DB users, SYSTEM schema owner, the SAP* superuser, the S-user, pcsd/hacluster cluster passwords, the STONITH fence credential, and the backint backup credential. Every one of them is a plaintext-leak waiting to happen.
Discipline (built on the Vault lesson):
- Encrypt at rest with
ansible-vault, and split by environment with vault-ids (a separate key fordev,qa,prd) so a leaked DEV key never unlocks PRD. no_log: trueon every task that receives a secret (all thecommunity.sap_libscalls above use it) — otherwise the password lands in-voutput and AAP job logs.- Prefer AAP credentials / a secrets manager (HashiCorp Vault, cloud secret stores) over committed vault files for production, so rotation does not mean a git commit.
- Never pass a secret on a command line (
psexposes it); pass it as a module argument or an environment variable the module reads.
Pinning collections and tracking SAP releases
The SAP collections move fast because SAP does. Two consequences:
-
Pin versions in
collections/requirements.ymland treat a collection bump like a code change — test it on a sandbox SID before the landscape sees it.# collections/requirements.yml collections: - name: redhat.sap_install version: "1.4.1" - name: community.sap_libs version: ">=1.4.2" - name: ansible.posix - name: community.general -
A HANA SPS or S/4 release bump can require a collection bump — new answer-file fields, new parameters, new tuned settings land in the collection after SAP ships them. Read the collection changelog when you plan an SPS upgrade; “the playbook that worked last quarter” is not a guarantee across an SPS boundary.
-
Remember the consolidation: several older, separately-named Red Hat SAP collections have been folded into
redhat.sap_install. If a tutorial references a standaloneredhat.sap_hana_install-style collection andansible-galaxy collection listdoes not show it, look for the equivalent role insideredhat.sap_installbefore assuming it is missing.
Anti-patterns that destroy SAP automation
- Hand-edited
global.iniafter Ansible runs. Drift accumulates; the next Ansible run might silently revert your one-off fix. Useredhat.sap_management.sap_hana_set_parametersalways. - Skipping
sapinitandsapcontrolchecks before reboot. A reboot during HANA recovery is hours of pain. - Using
serial: 100%for kernel patches. All instances down at once. - No fence agent in Pacemaker. STONITH is mandatory; without it the cluster cannot guarantee single-master.
- Manual SSH key copies for HSR. Use the role; key drift means your secondary cannot register.
- Treating
<sid>admas just-another-user. It has very specific limits, profile, environment. Always create via the SAP role. - Mixing kernel patch with SPS upgrade in one window. Each is enough work; combining them quadruples your debug surface.
- Untested HSR takeover. A clean install with HSR doesn’t mean takeover works. Test it quarterly.
- Backups on the same storage as data. A NetApp aggregate failure takes both. Use a separate aggregate or replicate to a different site.
Common beginner mistakes
These are the misconceptions that trip up engineers new to SAP-on-Ansible — distinct from the operational anti-patterns above. Each is a wrong mental model and the right one to replace it with.
-
“The installer is idempotent, so I can just re-run the play.” No —
hdblcmand SWPM are one-way gates; re-running them against an installed SID errors or corrupts. Right model: the playbook is idempotent because your wrapper probes for existing state (stat/GetProcessList) and guards the install withwhen:. Idempotency lives in your role, never in the SAP binary. -
“
--checkwill show me what the HANA install would do.” It can’t simulate a real installer, andcommand:tasks run nothing in check mode — a “green” dry run may have skipped the entire install. Right model: check-mode is a drift probe for OS-prep; installs are non-check islands you rehearse on a throwaway sandbox SID. -
“I’ll put the HANA master password in
group_varsso it’s easy to reference.” That is a plaintext secret in git and in every-vlog. Right model: secrets live in Ansible Vault (or a secrets manager), split by environment with vault-ids, and every task that touches one setsno_log: true. -
“Ansible replaces the basis team.” It doesn’t — SAP basis knowledge (which Note, which parameter, which sizing) is the hard part. Right model: Ansible encodes and repeats what basis decides. The engineers define the Notes and parameters; Ansible executes them the same way every time, and turns tribal knowledge into reviewed code.
-
“A few
command:tasks are simpler than pulling in a giant collection.” You will reinvent answer-file generation, license handling, and hundreds of Note conditionals — badly. Right model: wrap the certified collection and layer your defaults on top. Customcommand:glue is for the last 5%, not the core install. -
“I can patch the whole landscape in one fast run.”
serial: 100%takes every instance down at once and loses locks. Right model: rolling and HA-aware —serial: 1withorder: inventory, ERS before ASCS, dialogs one at a time so the load balancer drains cleanly. -
“HSR is configured, so DR works.” A configured secondary is not a tested takeover — SSFS keys, VIP float, and application reconnect can all be broken while replication shows healthy. Right model: rehearse a forced takeover on a schedule (quarterly), driven by the same playbook, and end it with a synthetic RFC round-trip.
Practice challenges
Work these in order — they escalate from “get the collections on your box” to “gate a change on a live round-trip.” No licensed SAP media is required to write and lint them; where a step needs a running SAP system, treat it as a rehearsal against a sandbox SID. Each solution notes the one idea it is teaching.
1. (Beginner) Pin and install the SAP collections.
Write a collections/requirements.yml that pins the collections this lesson uses, then install them.
<details> <summary>Solution</summary>
# collections/requirements.yml
collections:
- name: redhat.sap_install
version: "1.4.1"
- name: community.sap_libs
version: ">=1.4.2"
- name: ansible.posix
- name: community.general
ansible-galaxy collection install -r collections/requirements.yml
ansible-galaxy collection list | grep -Ei 'sap|posix'
Why: pinning makes runs reproducible; an unpinned collection can change installer behaviour under you across an SPS boundary. </details>
2. (Beginner) Fail fast with a preflight assertion. Before any install task, abort if the host has less than 4 GB RAM or is not subscribed to a SAP-solutions repo.
<details> <summary>Solution</summary>
- name: Read enabled repositories (read-only — must never report 'changed')
ansible.builtin.command: subscription-manager repos --list-enabled
register: repos
changed_when: false
- name: Preflight — refuse to install on an unfit host
ansible.builtin.assert:
that:
- ansible_facts.memtotal_mb >= 4096
- "'sap-solutions' in repos.stdout"
fail_msg: "Host is not SAP-ready (RAM below 4 GB or missing SAP-solutions repo)."
success_msg: "Preflight passed."
Why: assert evaluates even in --check, and changed_when: false keeps the read-only probe honest — you catch an unfit host before the one-way installer touches it.
</details>
3. (Intermediate) Make a HANA start task genuinely idempotent.
Replace a bare HDB start with a probe-then-act pattern so a second run reports no change.
<details> <summary>Solution</summary>
- name: Probe process state (read-only)
community.sap_libs.sap_control_exec:
sysnr: "{{ instance_number }}"
command: GetProcessList
register: procs
changed_when: false
failed_when: false
- name: Start the system only if it is not already GREEN
community.sap_libs.sap_control_exec:
sysnr: "{{ instance_number }}"
command: StartSystem
when: "'GREEN' not in (procs.out | default(''))"
Why: the installer/service tools are not idempotent — your wrapper is. Probe with changed_when: false, then guard the mutation with when:.
</details>
4. (Intermediate) Stage media with an integrity gate. Pull a HANA SAR from an internal mirror, fail on checksum mismatch, then extract it with SAPCAR.
<details> <summary>Solution</summary>
- name: Fetch media (idempotent + tamper-evident)
ansible.builtin.get_url:
url: "https://artifacts.internal.example/sap/HANA_2_SPS07/IMDB_SERVER.SAR"
dest: "/sapmedia/HANA_2_SPS07/IMDB_SERVER.SAR"
checksum: "sha256:{{ hana_server_sar_sha256 }}"
mode: "0640"
- name: Extract with SAPCAR
community.sap_libs.sapcar_extract:
path: "/sapmedia/HANA_2_SPS07/IMDB_SERVER.SAR"
dest: "/sapmedia/HANA_2_SPS07/extracted"
binary_path: "/sapmedia/tools/SAPCAR"
Why: truncated/tampered media is the most common HANA install failure; get_url’s checksum: makes the download both idempotent and verified before the installer ever sees it.
</details>
5. (Advanced) Roll a SAP-kernel patch in the correct order. Patch one instance at a time, ERS before ASCS, dialogs one by one — using ordering, not luck.
<details> <summary>Solution</summary>
- name: Rolling SAP kernel patch (ERS → ASCS → dialogs, one at a time)
hosts: sap_landscape # inventory ordered: ers, ascs, pas, aas
become: true
serial: 1
order: inventory # honour that inventory order, host by host
collections:
- community.sap_libs
tasks:
- name: Stop this instance gracefully
community.sap_libs.sap_control_exec:
sysnr: "{{ instance_number }}"
command: Stop
- name: Apply the kernel SAR files (backup + symlink + saproot.sh)
ansible.builtin.import_role:
name: sap_kernel_patch
- name: Start this instance again
community.sap_libs.sap_control_exec:
sysnr: "{{ instance_number }}"
command: Start
Why: serial: 1 + order: inventory turns a landscape-wide outage into a controlled wave — ERS drains locks before ASCS is touched, and each dialog leaves/rejoins the load balancer cleanly.
</details>
6. (Advanced) Gate the change on a live round-trip. After the operation, fail the play unless a synthetic RFC echoes back — proving VIP → dispatcher → work process is alive.
<details> <summary>Solution</summary>
- name: Post-op smoke test — RFC round-trip
community.sap_libs.sap_pyrfc:
function: "STFC_CONNECTION"
parameters:
REQUTEXT: "ansible-{{ ansible_date_time.epoch }}"
connection:
ashost: "{{ ascs_vip }}"
sysnr: "00"
client: "100"
user: "{{ vault_smoke_user }}"
passwd: "{{ vault_smoke_password }}"
lang: "EN"
register: rfc
no_log: true
- name: Fail the play if the echo does not round-trip
ansible.builtin.assert:
that:
- "(rfc.result.ECHOTEXT | default('')) == ('ansible-' ~ ansible_date_time.epoch)"
fail_msg: "SAP stack not reachable after the operation — investigate before declaring success."
(The exact return key — rfc.result.* vs rfc.return_value.* — depends on the module version; check --doc. Representative.)
Why: a service that is “started” is not proven “working.” A synthetic STFC_CONNECTION exercises the whole path end-to-end, so a broken dispatcher fails the change instead of shipping it.
</details>
Frequently asked questions
1. Can I install HANA without using redhat.sap_hana_install?
Technically yes, but you will reinvent the answer-file generation, license application, and post-install parameter setting. The collection encodes thousands of lines of basis knowledge; not using it is a guarantee of bugs.
2. What’s the right HANA replication mode for my landscape? Same DC: Sync (RPO=0, performance hit) or SyncMem (RPO≈0). Cross-region: Async (some loss possible on forced takeover). Hybrid (HSR as DR): Async with a 5-min lag alarm and a tested forced-takeover playbook.
3. How do I patch the Linux kernel under HANA?
Run redhat.sap_management.sap_hana_set_takeover to controlled-failover to secondary. Patch primary’s Linux kernel. Reboot. Re-establish HSR. Failback. This is one of the rarer-used routines and benefits the most from rehearsal.
4. Can Ansible handle SAP transport routes (TMS configuration)?
Yes, via tp CLI calls in playbooks. The TMS GUI is one-time configuration; routine transport imports are the recurring work, and they automate cleanly.
5. What about SAP S/4HANA Cloud (private edition)? Same patterns. The customer still owns the infrastructure layer; Ansible automates HANA install, NetWeaver install, kernel patches, transports. SAP only operates the “managed services” wrapper above your stack.
6. How do I integrate Ansible with Solution Manager (SolMan)?
SolMan can import job execution history via RFC; you pump Ansible job results back via sap_rfc_call. Most basis teams treat AAP as the orchestrator and SolMan as the change repository; SolMan owns the change/release record, AAP owns the execution.
7. What’s the right failure mode for a transport import that gets RC=8? Stop the workflow, page the basis lead. RC=8 means object-related issues that need human inspection. Do NOT auto-retry; you may mask a real syntax error.
8. How big should HANA backups be in production? Daily full + every-15min log backup is the SAP-recommended baseline. Use HANA’s native backup with a backint-compatible target (Veeam, Commvault, or HANA on AWS Backup with the AWS backint adapter). Ansible owns the backup-job creation and rotation policy; the actual data movement is the backint plug-in’s job.
9. Can I use Ansible to drive SAP MaxDB or ASE?
Yes, with community.sap_install having modules for both. They are less commonly needed than HANA but follow the same install/patch/configure pattern.
10. What’s the single most underrated SAP automation practice?
The per-SAP-Note role. When SAP issues a new Note that affects your platform (e.g., a kernel-tuning Note for memory leaks), encode it as a small Ansible role with a clear when guard, run it on the test landscape, and add it to the OS-prep workflow. Six months later, when an auditor asks “is Note 2382421 applied?”, the answer is “yes, and here is the ledger entry showing every host has run that role.”
Hands-on lab — first SAP-aware Ansible play
A full HANA install needs SAP licensed media. The following lab uses publicly available SAP-related tooling to get hands-on without a license: setting up the OS prerequisites a HANA install would expect.
Prerequisites: RHEL 8/9 VM with at least 4GB RAM, ansible-core ≥ 2.16.
mkdir -p sap-lab/{playbooks,roles}
cd sap-lab
ansible-galaxy collection install redhat.sap_install
# playbooks/os-prep.yml
- hosts: localhost
become: true
collections:
- redhat.sap_install
roles:
- role: sap_general_preconfigure
vars:
sap_general_preconfigure_modify_etc_hosts: false
- role: sap_hana_preconfigure
vars:
sap_hana_preconfigure_thp: never
ansible-playbook playbooks/os-prep.yml -K
sysctl kernel.shmmax # huge value
cat /sys/kernel/mm/transparent_hugepage/enabled # [never]
tuned-adm active # sap-hana
ulimit -n -H -S
Now read what the role did:
cat /etc/security/limits.d/99-sap.conf
cat /etc/sysctl.d/sap.conf
ansible-galaxy role list redhat.sap_install
You have just executed a non-trivial fraction of the OS work that goes into every HANA install, and seen the artefacts the SAP basis role leaves behind. Extend the lab by writing a roles/sap_storage_layout that creates the /hana/{data,log,shared} mountpoints (without real disks, use tmpfs); rerun and confirm idempotency.
Then take it one step further (ties the lesson together): run the same play again with --check --diff. Watch the OS-prep roles report no changes (they are idempotent) — that is the drift-probe from Going deeper in action. Now add the Challenge-2 preflight assert at the top and re-run in check mode; confirm the assertion still evaluates even though nothing is applied. That contrast — asserts run in check mode, installers do not — is the single most useful thing to internalise before you touch a real SID.
Glossary
- SID — System ID, three-letter code identifying an SAP system (e.g.,
S4P). - HANA — SAP’s in-memory column store database.
- HSR — HANA System Replication.
replicationMode/operationMode— the two HSR axes: how much the primary waits (sync/syncmem/async) and how the secondary stays current (logreplay/delta_datashipping).- NetWeaver — SAP application server stack (ABAP and Java).
- ASCS — ABAP SAP Central Services (message + enqueue).
- ERS — Enqueue Replication Server (mirror of enqueue table).
- PAS — Primary Application Server (dialog instance).
- AAS — Additional Application Server (dialog instance, scale-out).
- SAP Note — vendor-issued documentation/configuration update.
- SPS — Support Package Stack (HANA quarterly maintenance bundle).
- Pacemaker — Linux HA cluster manager.
- STONITH — Shoot The Other Node In The Head; fencing.
<sid>adm— OS user that owns SAP processes.tp— Transport tool used to import changes.- Solman — SAP Solution Manager, change/release management product.
hdblcm— HANA database lifecycle manager; the command-line installer the HANA roles wrap.sapinst/ SWPM — Software Provisioning Manager; the NetWeaver installer thesap_swpm/sap_installroles drive.- SAPCAR — SAP’s archive tool; unpacks
.SARmedia (community.sap_libs.sapcar_extractwraps it). sapcontrol— SAP’s start/stop/status CLI per instance (community.sap_libs.sap_control_execwraps it).- S-user — an SAP support-portal login (e.g.
S0001234567) needed to download media; keep it in Vault, never on managed hosts. - backint — the backup-tool interface HANA calls to stream backups to Veeam/Commvault/cloud targets.
- MDC — Multitenant Database Containers; one HANA system hosting multiple tenant DBs.
- RFC / PyRFC — Remote Function Call, SAP’s RPC protocol; PyRFC is the Python binding used by
sap_pyrfcfor synthetic smoke tests. - RPO / RTO — Recovery Point Objective (data you can lose) / Recovery Time Objective (time to recover) — the two DR targets HSR mode selection trades against.
- ANGI / SAPHanaSR — the certified Pacemaker resource agents for HANA HSR;
SAPHanaSR-angiis the newer “Active/Next-Generation Interface” generation. tunedprofile — a kernel/OS tuning bundle;sap-hanaandsap-netweaverare the SAP-certified profiles applied during OS-prep.- VIP — Virtual IP; floats to the active node so clients connect to the service, not to a specific host.
- RHEL for SAP Solutions — the specific RHEL subscription (not plain RHEL) that carries the SAP tuned profiles, HA agents, and support terms SAP requires.
Certification mapping
- EX374 — Workflow orchestration, RBAC, surveys (used heavily for transport imports).
- C_HANATEC, C_S4TM — SAP technology consultant certifications; this lesson maps to the basis tasks in those exams.
- AWS Certified: SAP on AWS Specialty — direct alignment.
Next steps
You now have an opinionated, Ansible-driven view of the SAP basis function. The remaining specialist lessons cover:
- Edge and IoT fleet management — small, intermittent, distributed targets that need a different connection and policy model than a datacentre fleet.
- ITSM and ChatOps — wiring AAP into ServiceNow/Jira/Slack so SAP transport imports and other regulated changes flow through controlled approval gates.
- Database migrations (online cutovers, blue-green) — the database-specific patterns that complement OS migrations.
- Observability — capturing RPO/RTO, patch coverage, HSR lag, and the rest of your SAP-relevant metrics into Prometheus/Grafana for a single pane of glass.
If you only take one habit from this lesson: always go through the SAP-supported collections. They are not perfect, but they encode hundreds of person-years of basis knowledge, and the alternative is a fork of hdblcm invocations that you will maintain forever.