CREATE A CMDB FOR IBM POWER ENVIROMENT USING ANSIBLE – PART 2
In the first part of this article (https://community.ibm.com/community/user/power/blogs/nicolae-chirea/2023/08/25/cmdb-ansible-1), we explored the creation of a configuration database containing IBM Power details. Now, the challenge lies in matching LPAR names with their corresponding host names in IBM Storwize® family storage systems. This information proves invaluable when implementing and automating various storage-based solutions for our LPARs, such as cloning, snapshots, and remote replication.
The underlying idea of the solution is quite straightforward: each LPAR is configured with a number of NPIV (N-Port ID Virtualization) connections, and each NPIV connection is associated with a unique WWNN (World Wide Node Name). These WWNNs are subsequently used to define hosts in the storage system. Therefore, our task is to retrieve these identifiers from both the LPARs and the storage system and establish a connection between them.
To begin, we create two tables in our SQLite3 database to store the retrieved information:
- name: Create table for storage information: hostwwnn
ibm.power_ibmi.ibmi_sqlite3:
database: "/home/ansible/db1/config.db"
sql: "CREATE TABLE IF NOT EXISTS hostwwn (
NOMBREHOST CHAR(60) NOT NULL,
HOSTWWNN CHAR(25) NOT NULL,
ESTADO CHAR(20),
IPCABINA CHAR(15),
NOMBRECABINA CHAR(40),
UNIQUE(NOMBREHOST,HOSTWWNN) ON CONFLICT IGNORE)"
- name: Create table for lpar information: lparwwn
ibm.power_ibmi.ibmi_sqlite3:
database: "/home/ansible/db1/config.db"
sql: "CREATE TABLE IF NOT EXISTS lparwwn (
NOMBRELPAR CHAR(60) NOT NULL,
LPARWWNN CHAR(25) NOT NULL,
UNIQUE(NOMBRELPAR,LPARWWNN) ON CONFLICT IGNORE)"
Retrieve WWNN for LPAR’s:
- name: Retrive lpar and wwnn
ibm.power_hmc.hmc_command:
hmc_host: "{{ hmc_ip }}"
hmc_auth:
username: '{{ usuario }}'
password: '{{ pass_hmc }}'
cmd: lshwres -m "{{sys_name.split(',')[0]}}" --level lpar -r virtualio --rsubtype fc -F lpar_name, wwpns
register: info_sys_fc
The content of info_sys_fc is something like this:
{
"changed": true,
"command_output": [
"V7R4B_DR,\"c0507608a98800a5,c0507608a98800a6\"",
"V7R4B_DR,\"c0507608a98800a9,c0507608a98800aa\"",
"ocpbalancer-81ab1567-00000007,\"c05076080639002a,c05076080639002b\"",
"ocpbalancer-81ab1567-00000007,\"c050760806390028,c050760806390029\"",
"ocpbalancer-81ab1567-00000007,\"c050760806390026,c050760806390027\"",
"ocpbalancer-81ab1567-00000007,\"c050760806390024,c050760806390025\"",
],
As I mentioned in the first part, inserting data into an SQLite table using Ansible is relatively slow. Therefore, here, I opted for a different approach. I stored JSON data in a JSON file, extracted it using the jq tool (jq - jqlang.github.io), which can be installed even on IBM i, and subsequently imported it into the SQLite table:
- name: Save wwnn en lparwwn.json
copy:
content: "{{ info_sys_fc | to_nice_json }}"
dest: "/home/ansible/db1/lparwwn.json"
- name: Transform lparwwn.json to lparwwn.csv
shell: jq -r '.command_output[]| sub("\"";"")|split(",")| {a:.[0], b:.[1]}| [ .a, .b] | @csv '
/home/ansible/db1/lparwwn.json >/home/ansible/db1/lparwwn.csv
- name: import lparwwn.csv to lparwwn
shell: sqlite3 /home/ansible/db1/config.db ".import /home/ansible/db1/lparwwn.csv lparwwn --csv"
This is very fast and the result and here is what we can see through sqlite-web:
We do the dame process for storage information – retrieve information:
# Host information from storage
- name: Get host info
ibm.spectrum_virtualize.ibm_svc_info:
clustername: "{{item.1}}"
username: "{{usuario}}"
password: "{{pass}}"
objectname: "{{item.0}}"
gather_subset: host
register: info_host_fc
loop: "{{hostcabinas.rows}}"
The content of info_host_fc is something like this:
"Host": {
"id": "23",
"name": " V7R4B_DR ",
"port_count": "2",
"type": "generic",
"iogrp_count": "2",
"status": "offline",
"site_id": "",
"site_name": "",
"host_cluster_id": "",
"host_cluster_name": "",
"protocol": "scsi",
"status_policy": "redundant",
"status_site": "all",
"nodes": [
{
"WWPN": " C0507608A98800A5",
"node_logged_in_count": "0",
"state": "offline"
},
{
"WWPN": " C0507608A98800A9",
"node_logged_in_count": "0",
"state": "offline"
}
],
And now I use same technique as before:
- name: Save host info to hostwwn.json
copy:
content: "{{ info_host_fc | to_nice_json }}"
dest: "/home/ansible/db1/hostwwn.json"
- name: Transform hostwwn.json to hostwwn.csv
shell: jq -r '.results[]| .item[1] as $ipcabina|.Host |.name as $nombrehost|.nodes| .[]| {a:$nombrehost, b:.WWPN, c:.state, d:$ipcabina}| [ .a, .b, .c, .d] |@csv '
/home/ansible/db1/hostwwn.json >/home/ansible/db1/hostwwn.csv
- name: import hostwwn.csv to hostwwn
shell: sqlite3 /home/ansible/db1/config.db ".import /home/ansible/db1/hostwwn.csv hostwwn --csv"
Finally, I only have to join both table:
- name: fill hostlparwwn from lparwwn and hostwwn and lpar
ibm.power_ibmi.ibmi_sqlite3:
database: "/home/ansible/db1/config.db"
sql: INSERT INTO hostlparwwn
SELECT a.NOMBREHOST, b.NOMBRELPAR, a.HOSTWWNN, b.LPARWWNN, a.ESTADO, a.IPCABINA, c.NOMBRESYS, c.IPHMC, c.TIPOLPAR
FROM hostwwn a, lparwwn b, lpar c
where (upper(a.HOSTWWNN) = upper(b.LPARWWNN)) and (a.HOSTWWNN > '0') and (b.NOMBRELPAR = c.NOMBRELPAR) and ( a.ESTADO = c.STATE)
order by b.NOMBRELPAR
In conclusion, this method provides a easy way to acquire and maintain highly valuable data about our IBM infrastructure.