====== Ansible for AIX ======
https://galaxy.ansible.com/ui/repo/published/ibm/power_aix/
https://galaxy.ansible.com/ui/repo/published/ibm/power_vios/
https://galaxy.ansible.com/ui/repo/published/ibm/power_hmc/
https://galaxy.ansible.com/ui/repo/published/brocade/fos/
https://galaxy.ansible.com/ui/repo/published/ibm/storage_virtualize/
https://www.ansible.com/blog/aix-patch-management-with-ansible
https://github.com/aixoss/ansible-playbooks
https://github.com/IBM/ansible-power-aix-oracle
https://github.com/IBM/ansible-power-hmc
https://github.com/lg4U (PowerVC)
If server is installed on AIX, then install prerequisites AIX packages:
* bos.loc.com.utf
* bos.loc.utf.EN_US
And set LANG: export LANG=en_US.UTF-8
$ ansible-galaxy collection install ibm.power_aix
$ ansible-galaxy collection install community.general
$ ansible-galaxy collection install community.general.installp
When Ansible is installed, a default inventory file /etc/ansible/hosts is created. At this point, I’m going to include in the inventory the hosts used in this example:
nim01 is our AIX 7.2 NIM Master which is functional and has an lpp_source defined.
bruce is an AIX 7.2 NIM client registered to the nim01 NIM master.
freddie is an AIX 7.2 NIM client registered to the nim01 NIM master.
$ cat /etc/ansible/hosts
nim01 ansible_host=10.0.0.5 ansible_user=root ansible_python_interpreter=/usr/bin/python
bruce ansible_host=10.0.0.6 ansible_user=root ansible_python_interpreter=/usr/bin/python
freddie ansible_host=10.0.0.7 ansible_user=root ansible_python_interpreter=/usr/bin/python
I’m now going to connect to all the systems over SSH as “root”. The usual practice is to have a service account with “sudo” access, however for this example I will use “root” in our lab environment. Using the ssh-copy-id command, I can distribute my SSH public key to the AIX servers.
$ ssh-copy-id root@nim01
$ ssh-copy-id root@bruce
$ ssh-copy-id root@freddie
The next step is to use the Ansible ping module to check that I can connect to the three hosts in our inventory.
$ ansible -m ping all
PLAY [Ansible Ad-Hoc] **************************************************************************
TASK [ping] ************************************************************************************
ok: [nim01]
ok: [freddie]
ok: [bruce]
PLAY RECAP ************************************************************************************
nim01 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
bruce : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
freddie : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Ansible needs “python” to be installed on the AIX systems, and ideally the “yum” package manager should also be configured on AIX. If your AIX systems do not have these packages installed, or is a vanilla installation of AIX, IBM provides an Ansible Role to “bootstrap” an AIX system and manage it.
The playbook below uses the IBM provided role to prepare an AIX system for Ansible automation.
$ cat aix_bootstrap.yml
---
- name: Prep AIX for Ansible
hosts: all
vars:
pkgtype: yum
collections:
- ibm.power_aix
roles:
- power_aix_bootstrap
The following example demonstrates running the playbook; however, I can see that the hosts Ansible is running against already have “python” and “yum” installed, so there is no need for any changes to be made to these hosts.
$ ansible-playbook aix_bootstrap.yml
PLAY [Prep AIX for Ansible] ******************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************
ok: [bruce]
ok: [freddie]
ok: [nim01]
TASK [ibm.power_aix.power_aix_bootstrap : Fail if pkgtype not specified] *********************************************************************************************************************************************************************
skipping: [nim01]
skipping: [bruce]
skipping: [freddie]
TASK [ibm.power_aix.power_aix_bootstrap : Fail if download_dir not specified] ****************************************************************************************************************************************************************
skipping: [nim01]
skipping: [bruce]
skipping: [freddie]
TASK [ibm.power_aix.power_aix_bootstrap : Fail if target_dir not specified] ******************************************************************************************************************************************************************
skipping: [nim01]
skipping: [bruce]
skipping: [freddie]
TASK [ibm.power_aix.power_aix_bootstrap : Fail if rpm_src not specified] *********************************************************************************************************************************************************************
skipping: [nim01]
skipping: [bruce]
skipping: [freddie]
TASK [ibm.power_aix.power_aix_bootstrap : Fail if yum_src not specified] *********************************************************************************************************************************************************************
skipping: [nim01]
skipping: [bruce]
skipping: [freddie]
TASK [ibm.power_aix.power_aix_bootstrap : Bootstrap yum] *************************************************************************************************************************************************************************************
included: /home/tholloway/.ansible/collections/ansible_collections/ibm/power_aix/roles/power_aix_bootstrap/tasks/yum_install.yml for nim01, bruce, freddie
TASK [ibm.power_aix.power_aix_bootstrap : Check for existence of yum] ************************************************************************************************************************************************************************
changed: [bruce]
changed: [nim01]
changed: [freddie]
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
nim01 : ok=3 changed=1 unreachable=0 failed=0 skipped=5 rescued=0 ignored=0
bruce : ok=3 changed=1 unreachable=0 failed=0 skipped=5 rescued=0 ignored=0
freddie : ok=3 changed=1 unreachable=0 failed=0 skipped=5 rescued=0 ignored=0
===== Running an AIX Update using NIM and Ansible =====
First off, I’ll use a simple playbook to see what “oslevel” our NIM master and NIM clients are on, before I start.
$ cat check_os_version.yml
---
- name: talk to all hosts just so we can learn about them
hosts: all
tasks:
- name: Classify hosts depending on their OS distribution
group_by:
key: os_{{ ansible_facts['distribution'] }}
- hosts: os_CentOS
gather_facts: False
tasks:
- name: Check version of Linux system
shell: "cat /etc/centos-release | tail -1 | sed 's/(AltArch)//' | rev | awk '{print $1}' | rev"
register: output_oslevel
- name: Print the oslevel
debug:
msg: "{{ ansible_hostname }} has the {{ ansible_distribution }} oslevel of {{ output_oslevel.stdout }}"
- hosts: os_AIX
gather_facts: False
tasks:
- name: Check oslevel of AIX system
shell: "oslevel -s"
register: output_oslevel
- name: Print the oslevel
debug:
msg: "{{ ansible_hostname }} has the {{ ansible_distribution }} oslevel of {{ output_oslevel.stdout }}"
Running that playbook delivers the below result. I can see that bruce and freddie are a service pack behind.
$ ansible-playbook aix_oslevel_check.yml
PLAY [AIX oslevel checking playbook ] *****************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************
ok: [bruce]
ok: [freddie]
ok: [nim01]
TASK [Gather LPP Facts] **********************************************************************************************************************************************************************************************************************
changed: [freddie]
changed: [bruce]
changed: [nim01]
TASK [Print the oslevel] *********************************************************************************************************************************************************************************************************************
ok: [nim01] =>
msg: nim01 has the AIX oslevel of 7200-05-02-2114
ok: [bruce] =>
msg: bruce has the AIX oslevel of 7200-05-01-2038
ok: [freddie] =>
msg: freddie has the AIX oslevel of 7200-05-01-2038
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
nim01 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
bruce : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
freddie : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
To ensure all systems are operating on the same OS level, I need to download the latest service pack. It should define an “lpp_source” on our NIM master. Make sure that the name of the “lpp_source” matches the example below, or the Ansible module will not detect the “oslevel”.
$ cat aix_download.yml
---
- name: AIX Patching Playbook
hosts: nim01
vars:
oslevel: 7200-05-02
nim_lpp_source: 7200-05-02-2114-lpp_source
collections:
- ibm.power_aix
tasks:
- name: Download AIX Updates
nim_suma:
action: download
download_dir: "/export/nim/lpp_source"
lpp_source_name: "{{ nim_lpp_source }}"
oslevel: "{{ oslevel }}"
targets: 'bruce, freddie'
Next step is to run the download playbook. It will download the required updates from IBM Fix Central and define an “lpp_source” on the NIM master:
$ ansible-playbook aix_download.yml
PLAY [AIX Patching Playbook] *****************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************
ok: [nim01]
TASK [Download AIX Updates] ******************************************************************************************************************************************************************************************************************
changed: [nim01]
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
nim01 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Now I can run a patching playbook, which will make use of the “alt_disk” and “nim” Ansible modules. The playbook is going to perform the following tasks:
Remove any existing “altinst_rootvg” “alt_disk_copy” that is left on the AIX system.
Create a new “alt_disk_copy” clone of the root volume group to a spare disk as a backup.
Run an application stop script.
Run the AIX update via task delegation to the NIM master.
Reboot.
Run an application start script.
---
- name: AIX Patching Playbook
hosts: bruce,freddie
vars:
nim_lpp_source: 7200-05-02-2114-lpp_source
nim_master: nim01
collections:
- ibm.power_aix
tasks:
- name: Cleanup any existing alt_disk_copy
alt_disk:
action: clean
- name: Create an alt_disk_copy for backup
alt_disk:
targets: hdisk1
- name: Stop Application
shell: /usr/local/bin/stop.sh
- name: Run AIX Update
nim:
action: update
lpp_source: "{{ nim_lpp_source }}"
targets: "{{ ansible_hostname }}"
delegate_to: "{{ nim_master }}"
- name: Reboot
reboot:
post_reboot_delay: 180
- name: Start Application
shell: /usr/local/bin/start.sh
Now I will run the playbook and patch the NIM client systems “bruce” and “freddie”:
$ ansible-playbook aix_patching.yml
PLAY [AIX Patching Playbook] *****************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************
ok: [bruce]
ok: [freddie]
TASK [Cleanup any existing alt_disk_copy] ****************************************************************************************************************************************************************************************************
changed: [bruce]
changed: [freddie]
TASK [Create an alt_disk_copy for backup] ****************************************************************************************************************************************************************************************************
changed: [bruce]
changed: [freddie]
TASK [Stop Application] **********************************************************************************************************************************************************************************************************************
changed: [bruce]
changed: [freddie]
TASK [Run AIX Update] *************************************************************************************************************************************************************************************************************************
changed: [bruce -> 10.0.0.5]
changed: [freddie -> 10.0.0.5]
TASK [Reboot] ********************************************************************************************************************************************************************************************************************************
changed: [freddie]
changed: [bruce]
TASK [Start Application] *********************************************************************************************************************************************************************************************************************
changed: [bruce]
changed: [freddie]
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
bruce : ok=7 changed=6 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
freddie : ok=7 changed=6 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Next, I will run the aix_oslevel_check.yml playbook again and see that the systems are all on AIX 7.2 TL5 SP2.
$ ansible-playbook aix_oslevel_check.yml
PLAY [AIX oslevel checking playbook ] *****************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************
ok: [bruce]
ok: [freddie]
ok: [nim01]
TASK [Gather LPP Facts] **********************************************************************************************************************************************************************************************************************
changed: [freddie]
changed: [bruce]
changed: [nim01]
TASK [Print the oslevel] *********************************************************************************************************************************************************************************************************************
ok: [nim01] =>
msg: nim01 has the AIX oslevel of 7200-05-02-2114
ok: [bruce] =>
msg: bruce has the AIX oslevel of 7200-05-02-2114
ok: [freddie] =>
msg: freddie has the AIX oslevel of 7200-05-02-2114
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
nim01 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
bruce : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
freddie : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Another playbook
- name: Install package foo
community.general.installp:
name: foo
repository_path: /repository/AIX71/installp/base
accept_license: yes
state: present
- name: Install bos.sysmgt that includes bos.sysmgt.nim.master, bos.sysmgt.nim.spot
community.general.installp:
name: bos.sysmgt
repository_path: /repository/AIX71/installp/base
accept_license: yes
state: present
- name: Install bos.sysmgt.nim.master only
community.general.installp:
name: bos.sysmgt.nim.master
repository_path: /repository/AIX71/installp/base
accept_license: yes
state: present
- name: Install bos.sysmgt.nim.master and bos.sysmgt.nim.spot
community.general.installp:
name: bos.sysmgt.nim.master, bos.sysmgt.nim.spot
repository_path: /repository/AIX71/installp/base
accept_license: yes
state: present
- name: Remove packages bos.sysmgt.nim.master
community.general.installp:
name: bos.sysmgt.nim.master
state: absent
- name: List all software products and installable options contained on an installation cartridge tape
ibm.power_aix.installp:
action: list
device: /dev/rmt0.1
- name: List all customer-reported problems fixed by all software products on an installation tape
ibm.power_aix.installp:
action: list_fixes
device: /dev/rmt0.1
install_list: all
- name: Install all filesets within the bos.net software package and expand file systems if necessary
ibm.power_aix.installp:
extend_fs: yes
device: /usr/sys/inst.images
install_list: bos.net
- name: Reinstall and commit the NFS software product option that is already installed on the system at the same level
ibm.power_aix.installp:
commit: yes
force: yes
device: /dev/rmt0.1
install_list: bos.net.nfs.client:4.1.0.0
- name: Remove a fileset named bos.net.tcp.server
ibm.power_aix.installp:
action: deinstall
install_list: bos.net.tcp.server
===== NFS mount =====
==== First solution ====
Using **shell**, mount and umount
[root@aix200]/root> cat mksysb_nfs.yml
---
- name: "Run Mksysb"
hosts: aix200
become: yes
become_user: root
vars:
NIM_Server: "nimsrv01"
backup_repo: "/export/mksysb"
NFS_mount: "/mksysb"
tasks:
- name: Monut filesystem
shell: "mount -o vers=4,soft {{ NIM_Server }}:{{ backup_repo }} {{ NFS_mount }}"
- name: "Run mksysb backup"
mksysb:
name: "{{ansible_hostname}}_mksysb_{{ansible_date_time.date}}"
storage_path: "{{ NFS_mount }}"
exclude_files: yes
- name: "unmount NFS"
mount:
path: "{{ NFS_mount }}"
state: unmounted
==== Second solution ====
On AIX, to be sure that filesystem will be mounted add it into /etc/filesystems, else it 'll failed
[root@aix200]/root> cat /etc/filesystems
...
/mksysb:
dev = "/export/mksysb"
vfs = nfs
nodename = nimsrv01
mount = false
options = bg,soft,intr,vers=4,sec=sys
account = false
[root@lnx100 playbooks]# cat mount_nfs.yml
---
- name: "Mount NFS"
hosts: aix200
become: yes
become_user: root
vars:
NIM_Server: "nimsrv01"
backup_repo: "/export/mksysb"
NFS_mount: "/mksysb"
tasks:
- name: Mount NFS filesystem from nimsrv01.
community.general.aix_filesystem:
filesystem: "{{ NFS_mount }}"
fs_type: nfs
device: "{{ backup_repo }}"
nfs_server: "{{ NIM_Server }}"
auto_mount: no
state: mounted
===== Mksysb on NIM (NFS) =====
[root@lnxa100 playbooks]# cat mount_nfs.yml
---
- name: "Run Mksysb"
hosts: aixb200
become: yes
become_user: root
vars:
NIM_Server: "aixnb001"
backup_repo: "/export/mksysb"
NFS_mount: "/mksysb"
tasks:
- name: Monut filesystem
shell: "mount -o vers=4,soft {{ NIM_Server }}:{{ backup_repo }} {{ NFS_mount }}"
- name: "Run mksysb backup"
mksysb:
name: "{{ansible_hostname}}_mksysb_{{ansible_date_time.date}}"
storage_path: "{{ NFS_mount }}"
exclude_files: yes
- name: "unmount NFS"
shell: "umount {{ NFS_mount }}"
fstab: /etc/filesystems
===== Log and debug =====
The IBM Power Systems AIX collection uses the standard Ansible log system that is using the syslog subsystem on the managed nodes.
To activate AIX syslog you can update the configuration file /etc/syslog.conf with a selector user.info (or user.debug for more details) such as:
$ vi /etc/syslog.conf
user.info /var/log/syslog/user.info rotate size 1m files 4 compress
and restarting syslogd subsystem and look for Ansible logs:
$ > /var/log/syslog/user.info
$ refresh -s syslogd
$ grep ansible /var/log/syslog/user.info
May 6 03:28:27 nimmaster user:info ansible-nim: Invoked with resource=None force=False description=None script=damien_script lpp_source=None action=script asynchronous=True location=None device=None group=None operation=None targets=['nimclient01']
May 6 03:28:27 nimmaster user:info ansible-nim: *** START ***
...
To see the full debug log messages you should set the selector field to user.debug and run the playbook with the environment variable ANSIBLE_DEBUG=1
$ vi /etc/syslog.conf
user.debug /var/log/syslog.user.debug rotate size 1m files 4 compress
$ >/var/log/syslog.user.debug
$ refresh -s syslogd
$ ANSIBLE_DEBUG=1 ansible-playbook -M plugins/modules ./demo_nim.yml -vvv
===== Examples =====
==== Upgrade AIX NIM ====
[root@lnx01 production]# cat upgrade_aix_nim.yml
---
- name: "Run Mksysb"
hosts: aix07
become: yes
become_user: root
vars:
NIM_Server: "nimsrv"
nim_lpp_source: "/export/aix7200-05/aix7200-05-03_lpp"
NFS_mount: "/mnt"
tasks:
- name: Mount AIX Filesets
shell: "mount -o vers=4 {{ NIM_Server }}:{{ nim_lpp_source }} {{ NFS_mount }}"
register: nfsmount
- name: upgrade OS
shell: install_all_updates -d "{{ NFS_mount }}" -rc -Y
when: ansible_distribution == 'AIX'
register: output
- debug: var=output
- name: "unmount NFS"
mount:
path: "{{ NFS_mount }}"
state: unmounted
==== mksysb AIX NIM ====
[root@lnx01 production]# cat mksysb.yml
---
- name: "Run Mksysb"
hosts: aix07
become: yes
become_user: root
vars:
NIM_Server: "nimsrv"
backup_repo: "/export/mksysb"
NFS_mount: "/mksysb"
nfsmounts:
- { path: "/mksysb", src: "nimsrv:/export/mksysb" }
tasks:
- name: Mount AIX Filesets
shell: "mount -o vers=4 {{ NIM_Server }}:{{ backup_repo }} {{ NFS_mount }}"
register: nfsmount
- name: "Run mksysb backup"
mksysb:
name: "{{ansible_hostname}}_mksysb_{{ansible_date_time.date}}"
storage_path: "{{ NFS_mount }}"
exclude_files: yes
create_map_files: yes
- name: "unmount NFS"
mount:
path: "{{ NFS_mount }}"
state: unmounted
==== AIX NIMadm alternate disk migration ====
Below is an example of how to invoke the options. I'd added the "default('N/A')" to avoid errors if the variable was not defined, as the role is coded for "N/A", but should also work with "default(omit)"
- name: Include nim_alt_disk_migration role
include_role:
name: nim_alt_disk_migration
apply:
delegate_to: "{{ NIM_Master }}"
connection: "{{ NIM_Conn }}"
vars:
nim_client: "{{ NIM_Client }}"
target_disk:
disk_name: "{{ Target_DISK.disk_name }}"
force: "{{ NIMADM_Force }}"
lpp_source: "{{ Target_LPPS }}"
spot: "{{ Target_SPOT }}"
nim_mast_lpp: "{{ NIM_Mast_LPP }}"
nimadm_cache_vg: "{{ NIMADM_VG | default('N/A') }}"
nimadm_bundle: "{{ Target_eFix | default('N/A') }}"
nimadm_bidata: "{{ BOS_Inst_Data | default('N/A') }}"
control_phases:
validate_nim_resources: "{{ NIM_Res_Check }}"
perform_migration: "{{ NIM_Migration }}
debug_skip_nimadm: "{{ Skip_nimadm }}"
# ansible-galaxy collection list ibm.power_aix
# /.ansible/collections/ansible_collections
Collection Version
------------- -------
ibm.power_aix 1.8.1
This Ansible role, nim_alt_disk_migration, can be used for “migrating an alternate disk to a higher AIX level”.
Here’s the playbook I used, called **nimadm.yml**:
---
- name: NIMADM playbook
hosts: aixmig
gather_facts: no
collections:
ibm.power_aix
tasks:
- include_role:
name: nim_alt_disk_migration
apply:
delegate_to: lpar1
vars:
nimadm_cache_vg: nimadmvg
nim_client: aixmig
target_disk:
disk_name: hdisk0
lpp_source: AIX73TL1SP1
spot: spotAIX73TL1SP1
register: nimadm_results
- name: "Debug: nimadm_results"
ansible.builtin.debug: var=nimadm_results