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:
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
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
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
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
[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
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
[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
[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
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