[[{“value”:”
Introduction
This is a follow-up to my earlier post on deploying SAP HANA 2.0 on AWS with Terraform and Ansible. That covered a single-node installation.
SAP HANA System Replication (HSR) paid my mortgage for about 12 / 13 years, but I don’t get to play with it much anymore, which is a shame. This post automates the whole setup — two EC2 instances in separate availability zones, HANA installed on both, HSR configured end to end with no manual steps.
I might follow it up with a blog about HA, but I don’t believe that Pacemaker / STONITH is fit for purpose. On nearly every project that I’ve worked on that had Pacemaker, we ended up tearing it out in favour of manual HSR with manual failover. We’ll see.
Everything here was built and tested live. The gotchas section reflects what actually broke, not theoretical edge cases.
Note: Same sandbox sizing as the previous post — r5.xlarge, 100GB root volume. Not for production. Run proper sizing before you go anywhere near a productive landscape.
Architecture
Local machine
├── Terraform → VPC, two subnets (AZ-a, AZ-b), IGW, Route 53 private zone
│ two EC2 instances, IAM role for S3 access
│
└── Ansible → hana-install.yml (runs on both nodes in parallel)
hsr-setup.yml (primary first, then secondary, then verify)
AWS VPC (10.0.0.0/16)
├── Subnet 10.0.1.0/24 (us-east-2a) → hana-primary (r5.xlarge)
└── Subnet 10.0.2.0/24 (us-east-2b) → hana-secondary (r5.xlarge)
Replication: SYNCMEM, logreplay mode
The security group allows all inbound traffic within the VPC (10.0.0.0/16) so HSR can communicate freely between nodes. HANA System Replication uses ports in the 4000x and 5432x ranges depending on instance number — rather than enumerate them, open the VPC CIDR internally and restrict SSH at the perimeter.
Project Layout
ansible_hsr/
├── terraform/
│ ├── providers.tf
│ ├── variables.tf
│ ├── main.tf
│ └── outputs.tf
├── ansible/
│ ├── inventory.ini
│ ├── hana-install.yml
│ ├── hsr-setup.yml
│ └── templates/
│ └── hana_install.cfg.j2
└── generate_inventory.sh
Step 1 — Terraform
What it provisions
- VPC with DNS support and hostnames enabled (required for HANA internal resolution)
- Two subnets in separate AZs for HA placement
- Internet gateway and route table
- Route 53 private hosted zone (hana.internal) with A records for both nodes
- IAM role + policy granting S3 read access to the HANA media bucket — no credentials on the instances
- Security group: SSH from anywhere, all internal VPC traffic, all egress
- Two EC2 instances: r5.xlarge, SUSE SLES for SAP 15 SP5 PAYG AMI, 100GB gp3
variables.tf
variable "aws_region" {
default = "us-east-2"
}
variable "key_pair_name" {
default = "<your-key-pair-name>"
}
variable "hana_media_bucket" {
default = "<your-s3-bucket-name>"
}
variable "private_zone_name" {
default = "hana.internal"
}
main.tf (abbreviated — key sections)
locals {
sles_sap_ami = "ami-099afc29551c4b139" # SUSE SLES for SAP 15 SP5 PAYG, us-east-2
}
resource "aws_vpc" "hana" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
}
resource "aws_subnet" "primary" {
vpc_id = aws_vpc.hana.id
cidr_block = "10.0.1.0/24"
availability_zone = "${var.aws_region}a"
}
resource "aws_subnet" "secondary" {
vpc_id = aws_vpc.hana.id
cidr_block = "10.0.2.0/24"
availability_zone = "${var.aws_region}b"
}
resource "aws_security_group" "hana" {
vpc_id = aws_vpc.hana.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "All internal VPC traffic (HSR)"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["10.0.0.0/16"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "hana_primary" {
ami = local.sles_sap_ami
instance_type = "r5.xlarge"
key_name = var.key_pair_name
subnet_id = aws_subnet.primary.id
vpc_security_group_ids = [aws_security_group.hana.id]
iam_instance_profile = aws_iam_instance_profile.hana_s3.name
associate_public_ip_address = true
root_block_device {
volume_type = "gp3"
volume_size = 100
}
tags = { Name = "hana-primary" }
}
outputs.tf
output "primary_public_ip" { value = aws_instance.hana_primary.public_ip }
output "secondary_public_ip" { value = aws_instance.hana_secondary.public_ip }
output "primary_private_ip" { value = aws_instance.hana_primary.private_ip }
output "secondary_private_ip" { value = aws_instance.hana_secondary.private_ip }
Run
cd terraform
terraform init
terraform apply -auto-approve
Step 2 — Generate the Ansible Inventory
After terraform apply, run generate_inventory.sh from the repo root. It reads the Terraform outputs, validates the IPs, constructs the primary’s private hostname, and writes ansible/inventory.ini.
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$SCRIPT_DIR/terraform"
PRIMARY_PUBLIC=$(terraform output -raw primary_public_ip 2>&1)
SECONDARY_PUBLIC=$(terraform output -raw secondary_public_ip 2>&1)
PRIMARY_PRIVATE=$(terraform output -raw primary_private_ip 2>&1)
if [[ ! "$PRIMARY_PUBLIC" =~ ^[0-9]+.[0-9]+.[0-9]+.[0-9]+$ ||
! "$SECONDARY_PUBLIC" =~ ^[0-9]+.[0-9]+.[0-9]+.[0-9]+$ ]]; then
echo "ERROR: No valid IPs from Terraform — run terraform apply first"
exit 1
fi
PRIMARY_HOSTNAME="ip-$(echo "$PRIMARY_PRIVATE" | tr '.' '-')"
cat > "$SCRIPT_DIR/ansible/inventory.ini" <<EOF
[primary]
hana-primary ansible_host=${PRIMARY_PUBLIC} ansible_user=ec2-user ansible_ssh_private_key_file=~/.ssh/HANA_DEP.pem
[secondary]
hana-secondary ansible_host=${SECONDARY_PUBLIC} ansible_user=ec2-user ansible_ssh_private_key_file=~/.ssh/HANA_DEP.pem
[hana:children]
primary
secondary
[hana:vars]
ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ServerAliveInterval=30 -o ServerAliveCountMax=20'
primary_private_hostname=${PRIMARY_HOSTNAME}
EOF
The primary_private_hostname variable is critical — see the gotchas section.
./generate_inventory.sh
Step 3 — Install HANA on Both Nodes
hana-install.yml (Appendix A) runs against [hana] (both nodes in parallel). It handles all prerequisites — packages, kernel parameters, swap, ulimits, THP, saptune — downloads the HANA media from S3, and runs hdblcm in silent/batch mode.
Key points:
- The IAM instance profile gives each node S3 read access — AWS CLI uses it automatically, no credentials needed on the instance
hdblcmis run withasync: 3600, poll: 30— installation takes 20–40 minutes and will time out a normal SSH connection- A
statcheck preventshdblcmre-running if HANA is already installed - The backup directory
/hana/backupis chowned tohdbadm:sapsysafterhdblcmruns —hdbadmdoesn’t exist until HANA installs
cd ansible
ansible-playbook -i inventory.ini hana-install.yml
Step 4 — Configure HSR
hsr-setup.yml (Appendix B) is three plays:
- Primary — take backups, enable HSR, copy PKI files to control node
- Secondary — stop HANA, push PKI files, register with primary, start HANA
- Primary — verify replication is ACTIVE
ansible-playbook -i inventory.ini hsr-setup.yml
The full playbook is in the appendix. The gotchas below explain every decision in it.
Gotchas
1. HANA MDC requires backups of BOTH databases before sr_enable
HANA 2.0 runs as Multi-Database Container (MDC) by default. There is a SYSTEMDB and one or more tenant databases (in this case HDB). hdbnsutil -sr_enable will refuse to run unless both have a complete data backup:
Backup has not yet been executed for database 'HDB'
Primary needs initial data backup for system replication!
A SYSTEMDB backup alone is not enough. The playbook runs both explicitly:
- name: Run SYSTEMDB backup
shell: |
su - hdbadm -c "
hdbsql -i 00 -d SYSTEMDB -u SYSTEM -p 'Hana1234!'
"BACKUP DATA USING FILE ('systemdb_backup')"
"
changed_when: true
- name: Run tenant database backup
shell: |
su - hdbadm -c "
hdbsql -i 00 -d HDB -u SYSTEM -p 'Hana1234!'
"BACKUP DATA USING FILE ('tenant_backup')"
"
changed_when: true
Then waits for each to appear in the backup catalog before proceeding:
- name: Wait for SYSTEMDB backup in catalog
shell: |
su - hdbadm -c "
hdbsql -i 00 -d SYSTEMDB -u SYSTEM -p 'Hana1234!'
"SELECT COUNT(*) FROM SYS.M_BACKUP_CATALOG
WHERE ENTRY_TYPE_NAME='complete data backup'
AND STATE_NAME='successful'"
"
register: systemdb_backup_catalog
until: (systemdb_backup_catalog.stdout | regex_search('[1-9][0-9]*')) is not none
retries: 20
delay: 15
changed_when: false
Gotcha:
regex_search()in Ansible returns a string (the match) or None — not a boolean. Using it bare inuntil:raises a “Conditional result was derived from value of type str” error. Theis not nonecast makes it a proper boolean.
2. PKI files
HANA HSR uses PKI/SSFS files to authenticate replication between nodes. These must be copied from the primary to the secondary so both nodes trust each other. The files are:
/usr/sap/HDB/SYS/global/security/rsecssfs/data/SSFS_HDB.DAT
/usr/sap/HDB/SYS/global/security/rsecssfs/key/SSFS_HDB.KEY
The playbook copies them to /tmp on the primary, fetches them to the control node with Ansible’s fetch module, then pushes them to the secondary with copy:
- name: Copy PKI files to tmp
shell: |
cp /usr/sap/HDB/SYS/global/security/rsecssfs/data/SSFS_HDB.DAT /tmp/SSFS_HDB.DAT
cp /usr/sap/HDB/SYS/global/security/rsecssfs/key/SSFS_HDB.KEY /tmp/SSFS_HDB.KEY
chmod 644 /tmp/SSFS_HDB.DAT /tmp/SSFS_HDB.KEY
changed_when: true
- name: Fetch PKI DAT to control node
fetch:
src: "/tmp/SSFS_HDB.DAT"
dest: "/tmp/SSFS_HDB.DAT"
flat: true
On the secondary:
- name: Push PKI DAT file to secondary
copy:
src: "/tmp/SSFS_HDB.DAT"
dest: "/usr/sap/HDB/SYS/global/security/rsecssfs/data/SSFS_HDB.DAT"
owner: hdbadm
group: sapsys
mode: "0600"
3. Use the EC2 private hostname, not Route 53
When registering the secondary with the primary, hdbnsutil -sr_register --remoteHost= must match the hostname that HANA itself registered under. HANA on AWS registers using the EC2 internal hostname, which is always derived from the private IP:
10.0.1.154 → ip-10-0-1-154
Route 53 names like hana-primary.hana.internal will not match and the registration will fail with an SSL/PKI error that looks like a certificate problem but is actually a hostname mismatch.
generate_inventory.sh constructs the correct hostname from the Terraform private IP output and writes it to [hana:vars] in inventory.ini:
PRIMARY_HOSTNAME="ip-$(echo "$PRIMARY_PRIVATE" | tr '.' '-')"
The secondary play reads it as {{ primary_private_hostname }} — no hardcoding.
4. hdbadm doesn’t exist until HANA installs
The first time hana-install.yml runs, hdbadm and the sapsys group don’t exist yet — they’re created by hdblcm. Any task that references them (like setting ownership on /hana/backup) must run after the hdblcm task, not before.
5. Variables don’t cross plays
Ansible plays are isolated. A variable set in the primary play is not available in the secondary play. This is why primary_private_hostname is in inventory.ini under [hana:vars] rather than set in the primary play and referenced later. Inventory group vars are available to all hosts in all plays.
Verifying Replication
Once the playbook completes, SSH to the primary and run:
ssh -i ~/.ssh/<your-key-pair-name>.pem ec2-user@<primary-public-ip>
sudo su - hdbadm
python3 /usr/sap/HDB/HDB00/exe/python_support/systemReplicationStatus.py
A healthy output looks like:
|Database |Host |Port |Service Name |Site ID |Site Name |Secondary |Replication |Status |Fully Synced |
|SYSTEMDB |ip-10-0-1-154 |30001 |nameserver | 1 |SITE1 |ip-10-0-2-150 |SYNCMEM |ACTIVE | True |
|HDB |ip-10-0-1-154 |30007 |xsengine | 1 |SITE1 |ip-10-0-2-150 |SYNCMEM |ACTIVE | True |
|HDB |ip-10-0-1-154 |30003 |indexserver | 1 |SITE1 |ip-10-0-2-150 |SYNCMEM |ACTIVE | True |
overall system replication status: ACTIVE
All three services — nameserver, xsengine, indexserver — must show ACTIVE and Fully Synced: True.
Tear Down
cd terraform
terraform destroy -auto-approve
The S3 bucket and HANA media are unmanaged by Terraform and persist between runs — you only pay S3 storage rates between deployments.
Key Lessons
Problem Root Cause Fix
| sr_enable: backup not executed | MDC has SYSTEMDB + tenant — both need backups | Explicit backup task for each DB with catalog wait |
| sr_register: SSL/PKI error | Hostname mismatch — Route 53 name vs EC2 hostname | Use ip-<private-ip> format, derived from Terraform output |
| PKI copy failing | Wrong file path | Files are at /usr/sap/HDB/SYS/global/security/rsecssfs/ |
| hdbadm not found | Running chown before hdblcm creates the user | Move ownership task to after hdblcm |
| Backup catalog check error | regex_search() returns str not bool | Use is not none to cast to boolean |
| HANA re-installs on re-run | No idempotency check | stat check on hdbnsutil before running hdblcm |
Appendix
A) hana-install.yml
---
- name: SAP HANA prerequisites and installation
hosts: all
become: true
gather_facts: true
vars:
hana_sid: "HDB"
hana_instance: "00"
hana_master_pw: "<your-password>"
sapadm_password: "<your-password>"
lss_password: "<your-password>"
hana_s3_bucket: "<your-s3-bucket-name>"
hana_s3_prefix: "SAP_HANA_DATABASE/DATA_UNITS/HDB_SERVER_LINUX_X86_64"
hana_media_dir: "/hana/media"
hana_install_dir: "/hana/shared"
hana_data_dir: "/hana/data"
hana_log_dir: "/hana/log"
swap_size_mb: 20480
tasks:
- name: Confirm target is SUSE
fail:
msg: "This playbook requires SUSE Linux Enterprise Server. Got: {{ ansible_os_family }}"
when: ansible_os_family != 'Suse'
- name: Refresh zypper repositories
zypper_repository:
repo: '*'
runrefresh: true
ignore_errors: true
- name: Install required OS packages
zypper:
name:
- libaio1
- libaio-devel
- libltdl7
- libatomic1
- libnuma1
- numactl
- uuidd
- rsync
- lsof
- unzip
- xfsprogs
- glibc-i18ndata
- graphviz
- expect
- python3
state: present
- name: Enable and start uuidd
systemd:
name: uuidd
state: started
enabled: true
- name: Check existing swap
command: swapon --show=SIZE --noheadings --bytes
register: swap_check
changed_when: false
failed_when: false
- name: Create swapfile
command: dd if=/dev/zero of=/swapfile bs=1M count={{ swap_size_mb }}
when: swap_check.stdout == ""
- name: Set swapfile permissions
file:
path: /swapfile
mode: "0600"
when: swap_check.stdout == ""
- name: Format swapfile
command: mkswap /swapfile
when: swap_check.stdout == ""
- name: Activate swapfile
command: swapon /swapfile
when: swap_check.stdout == ""
- name: Persist swapfile in fstab
lineinfile:
path: /etc/fstab
line: "/swapfile swap swap defaults 0 0"
state: present
- name: Set kernel parameters for HANA
sysctl:
name: "{{ item.key }}"
value: "{{ item.value }}"
sysctl_set: true
state: present
reload: true
loop:
- { key: "vm.max_map_count", value: "2147483647" }
- { key: "kernel.sem", value: "1250 256000 100 8192" }
- { key: "net.core.somaxconn", value: "4096" }
- { key: "net.ipv4.tcp_max_syn_backlog", value: "8192" }
- { key: "kernel.numa_balancing", value: "0" }
- name: Set ulimits for SAP
copy:
dest: /etc/security/limits.d/99-sap.conf
mode: "0644"
content: |
@sapsys soft nofile 1048576
@sapsys hard nofile 1048576
@sapsys soft nproc unlimited
@sapsys hard nproc unlimited
@sdba soft nofile 1048576
@sdba hard nofile 1048576
- name: Disable THP at runtime
shell: |
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
changed_when: true
- name: Create systemd unit to disable THP on boot
copy:
dest: /etc/systemd/system/disable-thp.service
mode: "0644"
content: |
[Unit]
Description=Disable Transparent Huge Pages
After=network.target
[Service]
Type=oneshot
ExecStart=/bin/sh -c "echo never > /sys/kernel/mm/transparent_hugepage/enabled && echo never > /sys/kernel/mm/transparent_hugepage/defrag"
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
- name: Enable disable-thp service
systemd:
name: disable-thp
enabled: true
daemon_reload: true
- name: Create HANA filesystem directories
file:
path: "{{ item }}"
state: directory
mode: "0755"
loop:
- "{{ hana_install_dir }}"
- "{{ hana_data_dir }}"
- "{{ hana_log_dir }}"
- "/hana/backup"
- name: Install saptune
zypper:
name: saptune
state: present
ignore_errors: true
- name: Apply SAP HANA tuning profile via saptune
command: saptune solution apply HANA
changed_when: true
ignore_errors: true
- name: Enable saptune daemon
systemd:
name: saptune
enabled: true
state: started
ignore_errors: true
- name: Check if aws cli is present
command: which aws
register: aws_cli_check
changed_when: false
failed_when: false
- name: Download and install AWS CLI v2
shell: |
curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip
unzip -q /tmp/awscliv2.zip -d /tmp/awscli-install
/tmp/awscli-install/aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update
rm -rf /tmp/awscliv2.zip /tmp/awscli-install
when: aws_cli_check.rc != 0
- name: Sync HANA media from S3
command: >
aws s3 sync s3://{{ hana_s3_bucket }}/{{ hana_s3_prefix }}/ {{ hana_media_dir }}/
--no-progress
register: s3_sync
changed_when: "'download' in s3_sync.stdout"
- name: Find hdblcm installer
find:
paths: "{{ hana_media_dir }}"
patterns: "hdblcm"
recurse: true
register: hdblcm_find
- name: Fail if hdblcm not found
fail:
msg: "hdblcm not found under {{ hana_media_dir }} — check hana_s3_bucket and hana_s3_prefix"
when: hdblcm_find.files | length == 0
- name: Set hdblcm path fact
set_fact:
hdblcm_path: "{{ hdblcm_find.files[0].path }}"
- name: Make hdblcm executable
file:
path: "{{ hdblcm_path }}"
mode: "0755"
- name: Write hdblcm silent response file
template:
src: hana_install.cfg.j2
dest: /tmp/hana_install.cfg
mode: "0600"
force: true
- name: Move LSS media aside
command: mv {{ hana_media_dir }}/lss {{ hana_media_dir }}/lss_aside
args:
removes: "{{ hana_media_dir }}/lss"
- name: Make media directory fully executable
shell: chmod -R 755 {{ hana_media_dir }}
changed_when: true
- name: Check if HANA already installed
stat:
path: "/usr/sap/{{ hana_sid }}/HDB{{ hana_instance }}/exe/hdbnsutil"
register: hana_installed
- name: Run SAP HANA installation (hdblcm)
command: >
{{ hdblcm_path }} --batch --configfile=/tmp/hana_install.cfg
register: hdblcm_result
changed_when: true
async: 3600
poll: 30
when: not hana_installed.stat.exists
- name: Show hdblcm output
debug:
msg: "{{ hdblcm_result.stdout_lines | default(['HANA already installed, skipped']) }}"
- name: Set backup directory ownership for hdbadm
file:
path: /hana/backup
owner: hdbadm
group: sapsys
recurse: true
- name: Check HDB daemon is running
shell: |
su - {{ hana_sid | lower }}adm -c "HDB info" 2>&1 | grep -E "hdbdaemon|hdbnameserver"
register: hdb_info
changed_when: false
failed_when: hdb_info.rc != 0
- name: Confirm HANA installation complete
debug:
msg: >
SAP HANA {{ hana_sid }} instance {{ hana_instance }} installed successfully.
Connect: hdbsql -i {{ hana_instance }} -u SYSTEM -p <password>
B) hsr-setup.yml
---
- name: Enable HSR on primary
hosts: primary
become: true
gather_facts: true
vars:
hana_sid: "HDB"
hana_instance: "00"
hana_master_pw: "<your-password>"
hsr_replication_mode: "syncmem"
hsr_operation_mode: "logreplay"
hsr_site_name_primary: "SITE1"
tasks:
- name: Run SYSTEMDB backup
shell: |
su - {{ hana_sid | lower }}adm -c "
hdbsql -i {{ hana_instance }} -d SYSTEMDB -u SYSTEM -p '{{ hana_master_pw }}'
"BACKUP DATA USING FILE ('systemdb_backup')"
"
changed_when: true
- name: Run tenant database backup
shell: |
su - {{ hana_sid | lower }}adm -c "
hdbsql -i {{ hana_instance }} -d {{ hana_sid }} -u SYSTEM -p '{{ hana_master_pw }}'
"BACKUP DATA USING FILE ('tenant_backup')"
"
changed_when: true
- name: Wait for SYSTEMDB backup in catalog
shell: |
su - {{ hana_sid | lower }}adm -c "
hdbsql -i {{ hana_instance }} -d SYSTEMDB -u SYSTEM -p '{{ hana_master_pw }}'
"SELECT COUNT(*) FROM SYS.M_BACKUP_CATALOG WHERE ENTRY_TYPE_NAME='complete data backup' AND STATE_NAME='successful'"
"
register: systemdb_backup_catalog
until: (systemdb_backup_catalog.stdout | regex_search('[1-9][0-9]*')) is not none
retries: 20
delay: 15
changed_when: false
- name: Wait for tenant backup in catalog
shell: |
su - {{ hana_sid | lower }}adm -c "
hdbsql -i {{ hana_instance }} -d {{ hana_sid }} -u SYSTEM -p '{{ hana_master_pw }}'
"SELECT COUNT(*) FROM SYS.M_BACKUP_CATALOG WHERE ENTRY_TYPE_NAME='complete data backup' AND STATE_NAME='successful'"
"
register: tenant_backup_catalog
until: (tenant_backup_catalog.stdout | regex_search('[1-9][0-9]*')) is not none
retries: 20
delay: 15
changed_when: false
- name: Check if HSR already enabled on primary
shell: |
su - {{ hana_sid | lower }}adm -c "hdbnsutil -sr_state"
register: sr_state_check
changed_when: false
- name: Enable system replication on primary
shell: |
su - {{ hana_sid | lower }}adm -c "
hdbnsutil -sr_enable --name={{ hsr_site_name_primary }}
"
changed_when: true
when: "'mode: primary' not in sr_state_check.stdout"
ignore_errors: true
- name: Confirm primary HSR state
shell: |
su - {{ hana_sid | lower }}adm -c "hdbnsutil -sr_state"
register: sr_state_primary
changed_when: false
- name: Show primary HSR state
debug:
msg: "{{ sr_state_primary.stdout_lines }}"
- name: Fail if primary not in HSR primary mode
fail:
msg: "Primary HSR enable failed"
when: "'mode: primary' not in sr_state_primary.stdout"
- name: Copy PKI files to tmp
shell: |
cp /usr/sap/{{ hana_sid }}/SYS/global/security/rsecssfs/data/SSFS_{{ hana_sid }}.DAT /tmp/SSFS_{{ hana_sid }}.DAT
cp /usr/sap/{{ hana_sid }}/SYS/global/security/rsecssfs/key/SSFS_{{ hana_sid }}.KEY /tmp/SSFS_{{ hana_sid }}.KEY
chmod 644 /tmp/SSFS_{{ hana_sid }}.DAT /tmp/SSFS_{{ hana_sid }}.KEY
changed_when: true
- name: Fetch PKI DAT to control node
fetch:
src: "/tmp/SSFS_{{ hana_sid }}.DAT"
dest: "/tmp/SSFS_{{ hana_sid }}.DAT"
flat: true
- name: Fetch PKI KEY to control node
fetch:
src: "/tmp/SSFS_{{ hana_sid }}.KEY"
dest: "/tmp/SSFS_{{ hana_sid }}.KEY"
flat: true
- name: Stop HANA on secondary and push PKI files
hosts: secondary
become: true
gather_facts: true
vars:
hana_sid: "HDB"
hana_instance: "00"
hana_master_pw: "<your-password>"
hsr_replication_mode: "syncmem"
hsr_operation_mode: "logreplay"
hsr_site_name_secondary: "SITE2"
tasks:
- name: Stop HANA on secondary
shell: |
su - {{ hana_sid | lower }}adm -c "HDB stop"
changed_when: true
- name: Wait for HANA to fully stop
shell: |
su - {{ hana_sid | lower }}adm -c "HDB info" 2>&1 | grep -c hdbdaemon || true
register: stop_check
until: stop_check.stdout | int == 0
retries: 20
delay: 15
changed_when: false
- name: Push PKI DAT file to secondary
copy:
src: "/tmp/SSFS_{{ hana_sid }}.DAT"
dest: "/usr/sap/{{ hana_sid }}/SYS/global/security/rsecssfs/data/SSFS_{{ hana_sid }}.DAT"
owner: hdbadm
group: sapsys
mode: "0600"
- name: Push PKI KEY file to secondary
copy:
src: "/tmp/SSFS_{{ hana_sid }}.KEY"
dest: "/usr/sap/{{ hana_sid }}/SYS/global/security/rsecssfs/key/SSFS_{{ hana_sid }}.KEY"
owner: hdbadm
group: sapsys
mode: "0600"
- name: Register secondary with primary
shell: |
su - {{ hana_sid | lower }}adm -c "
hdbnsutil -sr_register
--name={{ hsr_site_name_secondary }}
--remoteHost={{ primary_private_hostname }}
--remoteInstance={{ hana_instance }}
--replicationMode={{ hsr_replication_mode }}
--operationMode={{ hsr_operation_mode }}
"
register: sr_register
changed_when: true
- name: Show registration output
debug:
msg: "{{ sr_register.stdout_lines }}"
- name: Start HANA on secondary
shell: |
su - {{ hana_sid | lower }}adm -c "HDB start"
changed_when: true
async: 600
poll: 30
- name: Verify replication state from primary
hosts: primary
become: true
gather_facts: false
vars:
hana_sid: "HDB"
hana_instance: "00"
tasks:
- name: Wait for secondary to connect
shell: |
su - {{ hana_sid | lower }}adm -c "
python3 /usr/sap/{{ hana_sid }}/{{ hana_sid }}{{ hana_instance }}/exe/python_support/systemReplicationStatus.py
" 2>&1 || true
register: hsr_status
until: "'ACTIVE' in hsr_status.stdout or 'SYNCING' in hsr_status.stdout"
retries: 20
delay: 15
changed_when: false
- name: Show replication status
debug:
msg: "{{ hsr_status.stdout_lines }}"
- name: Confirm replication is active
fail:
msg: "HSR did not reach ACTIVE or SYNCING state"
when: "'ACTIVE' not in hsr_status.stdout and 'SYNCING' not in hsr_status.stdout"
- name: Final replication status
shell: |
su - {{ hana_sid | lower }}adm -c "
python3 /usr/sap/{{ hana_sid }}/{{ hana_sid }}{{ hana_instance }}/exe/python_support/systemReplicationStatus.py
"
register: final_status
changed_when: false
ignore_errors: true
- name: Show final replication status
debug:
msg: "{{ final_status.stdout_lines }}"
“}]]
Read More Technology Blog Posts by Members articles
#abap