====== Ansible base OS customization ======
===== Conditional role =====
Assume 3 roles:
* aix_setup
* ppc64le_setup
* x86_64_setup
site.yml
roles/
├── aix_setup/
├── ppc64le_setup/
└── x86_64_setup/
# ansible-galaxy init roles/aix_setup
# ansible-galaxy init roles/ppc64le_setup
# ansible-galaxy init roles/x86_64_setup
roles/
├── aix_setup/
│ ├── defaults/
│ │ └── main.yml
│ ├── files/
│ ├── handlers/
│ │ └── main.yml
│ ├── meta/
│ │ └── main.yml
│ ├── tasks/
│ │ └── main.yml
│ ├── templates/
│ ├── tests/
│ │ ├── inventory
│ │ └── test.yml
│ └── vars/
│ └── main.yml
Example main.yml
# cat roles/ppc64le_setup/tasks/main.yml
---
- name: Print ppc64le architecture and OS
debug:
msg: "Running setup role on {{ inventory_hostname }}, OS: {{ ansible_system }}, Arch: {{ ansible_architecture }}"
# cat conditional_roles.yml
---
- name: Run role based on system architecture and OS
hosts: all
become: yes
gather_facts: yes
pre_tasks:
- name: Get AIX version if applicable
ansible.builtin.shell: oslevel
when: ansible_system == "AIX"
register: aix_version
changed_when: false
roles:
- role: aix_setup
when:
- ansible_system == "AIX"
- "'7.2' in aix_version.stdout or '7.3' in aix_version.stdout"
- role: ppc64le_setup
when:
- ansible_architecture == "ppc64le"
- ansible_system != "AIX"
- role: x86_64_setup
when:
- ansible_architecture == "x86_64"
- ansible_system != "AIX"
Also useful facts:
=== AIX ===
"ansible_os_family": "AIX",
"ansible_distribution": "AIX",
"ansible_distribution_major_version": "7",
"ansible_distribution_release": "2",
"ansible_distribution_version": "7.2",
"ansible_architecture": "chrp",
"ansible_system": "AIX"
=== Linux ===
"ansible_os_family": "RedHat",
"ansible_distribution": "openSUSE Leap",
"ansible_distribution_file_variety": "SUSE",
"ansible_distribution_major_version": "15",
"ansible_distribution_release": "1",
"ansible_distribution_version": "15.1",
"ansible_architecture": "x86_64",
"ansible_system": "Linux"
or "ansible_architecture": "ppc64le",
===== Pre task for AIX to set ansible_python_interpreter =====
# cat pretask.yml
---
- name: Set Python interpreter based on AIX version
hosts: aix_hosts
gather_facts: false # we'll do manual version check
become: yes
pre_tasks:
- name: Get AIX version
ansible.builtin.shell: oslevel
register: aix_version
changed_when: false
- name: Set Python interpreter for AIX 7.2
ansible.builtin.set_fact:
ansible_python_interpreter: "/opt/freeware/bin/python3"
when: "'7.2' in aix_version.stdout"
- name: Set Python interpreter for AIX 7.3
ansible.builtin.set_fact:
ansible_python_interpreter: "/opt/freeware/bin/python3_73"
when: "'7.3' in aix_version.stdout"
tasks:
- name: Debug current interpreter
ansible.builtin.debug:
msg: "Using interpreter: {{ ansible_python_interpreter }}"
# You can continue here with other tasks
===== Create filesystems =====
# cat inventory.ini
[aix_hosts]
aixserver1 ansible_user=root ansible_connection=ssh ansible_python_interpreter=/opt/freeware/bin/python3
# cat lv_config.json
[
{
"vgname": "datavg",
"lvname": "lv_data",
"mount_point": "/data",
"size": "2G"
"type": "jfs2"
},
{
"vgname": "appvg",
"lvname": "lv_app",
"mount_point": "/app",
"size": "5G"
"type": "jfs2"
}
]
Create filesystems
# cat create_aix_lvs.yml
---
- name: Create Logical Volumes and Filesystems on AIX
hosts: aix_hosts
become: yes
vars_files:
- lv_config.json
tasks:
- name: Create logical volume
ansible.builtin.shell: |
mklv -t {{ item.type }} -y {{ item.lvname }} {{ item.vgname }} {{ item.size }}
args:
creates: "/dev/{{ item.lvname }}"
loop: "{{ lv_config }}"
- name: Create file system
ansible.builtin.shell: |
crfs -v {{ item.type }} -d {{ item.lvname }} -m {{ item.mount_point }} -A yes
args:
creates: "{{ item.mount_point }}"
loop: "{{ lv_config }}"
- name: Create mount point directory
ansible.builtin.file:
path: "{{ item.mount_point }}"
state: directory
mode: '0755'
loop: "{{ lv_config }}"
- name: Mount filesystem
ansible.builtin.shell: |
mount {{ item.mount_point }}
loop: "{{ lv_config }}"
- name: Ensure filesystem is in /etc/filesystems (automount)
ansible.builtin.shell: |
chfs -A yes {{ item.mount_point }}
loop: "{{ lv_config }}"
Extend filesystems if smaller than desired
# cat extend_aix_lvs.yml
---
- name: Extend filesystems on AIX if current size is smaller
hosts: aix_hosts
become: yes
vars_files:
- lv_config.json
tasks:
- name: Get current size of filesystem
ansible.builtin.shell: |
lsfs {{ item.mount_point }} | awk 'NR>1 {print $3}'
register: current_fs_size
changed_when: false
loop: "{{ lv_config }}"
loop_control:
label: "{{ item.mount_point }}"
delegate_to: localhost
- name: Set fact with comparison results
ansible.builtin.set_fact:
fs_resize_list: >-
{{
fs_resize_list | default([]) +
[{
'mount_point': item.1.mount_point,
'lvname': item.1.lvname,
'vgname': item.1.vgname,
'current_size': (item.0.stdout | trim),
'desired_size': item.1.size
}] if (item.0.stdout | trim is version(item.1.size, '<')) else fs_resize_list | default([])
}}
loop: "{{ zip(current_fs_size.results, lv_config) }}"
loop_control:
label: "{{ item.1.mount_point }}"
- name: Extend filesystem only if current size is less than desired
ansible.builtin.shell: |
chfs -a size={{ item.desired_size }} {{ item.mount_point }}
loop: "{{ fs_resize_list }}"
when: fs_resize_list | length > 0
//Note//
AIX lsfs returns sizes in 512-byte blocks. So 4194304 blocks = 2G. You may need a helper function to normalize that if you want more accuracy.
You could replace size parsing with something like:
lsfs /data | awk 'NR>1 {printf "%.0fG\n", $3*512/1024/1024/1024}'
===== Playbook2 =====
[ansible@lnx001 playbooks]$ cat main.yml
---
- name: Master playbook
hosts: all
gather_facts: true
become: yes
roles:
- role: aix_system_config
when:
- ansible_system == "AIX"
- role: lnx_system_config
when:
- ansible_system == "Linux"
[ansible@lnx001 playbooks]$ cat roles/lnx_system_config/tasks/main.yml
---
- name: Include SSH configuration tasks
include_tasks: ssh_config.yml
[ansible@lnx001 playbooks]$ cat roles/lnx_system_config/vars/main.yml
---
_etc_ssh_sshd_config: /etc/ssh/sshd_config
[ansible@lnx001 playbooks]$ cat roles/lnx_system_config/files/sshd_config.json
[
{
"name": "Port",
"line": "Port 22",
"action": "replace"
},
{
"name": "ListenAddress",
"line": "ListenAddress 0.0.0.0",
"action": "replace"
},
{
"name": "ListenAddress",
"line": "ListenAddress ::",
"action": "remove"
},
{
"name": "UseDNS",
"line": "UseDNS no",
"action": "replace"
},
{
"name": "SyslogFacility",
"line": "SyslogFacility AUTH",
"action": "replace"
},
{
"name": "LogLevel",
"line": "LogLevel INFO",
"action": "replace"
},
{
"name": "PermitRootLogin",
"line": "PermitRootLogin yes",
"action": "replace"
},
{
"name": "PasswordAuthentication",
"line": "PasswordAuthentication yes",
"action": "replace"
},
{
"name": "UsePAM",
"line": "UsePAM yes",
"action": "replace"
},
{
"name": "PidFile",
"line": "PidFile /var/run/sshd.pid",
"action": "replace"
},
{
"name": "Subsystem",
"line": "Subsystem sftp /usr/libexec/openssh/sftp-server -f AUTH -l INFO",
"action": "replace"
},
{
"name": "KexAlgorithms",
"line": "KexAlgorithms -*sha1*",
"action": "insertafter",
"after": "GSSAPIEnablek5users"
},
{
"name": "MACs",
"line": "MACs -*umac-64*,*sha1*,umac-128-etm@openssh.com",
"action": "insertafter",
"after": "GSSAPIEnablek5users"
}
]