Using Ansible to automate IBM i workloads on Skytap

Ansible is a powerful IT automation engine that helps with cloud provisioning, configuration management, application deployment, and other IT needs through use of a simple declarative language in the form of Ansible Playbooks. In June this year, IBM announced the support for Ansible to manage IBM i instances through the Ansible Content for IBM Power Systems package that is available in GitHub:https://github.com/IBM/ansible-for-i

Support for IBM i comes in the form of Ansible modules built by IBM. Some of the capabilities of these modules include the ability to execute CL commands, save and restore libraries, reboot IBM i, and execute SQL scripts and queries. There are more than 35 different modules that are available in this repository: https://github.com/IBM/ansible-for-i/tree/devel/plugins/modules/.

Skytap IBM i templates already include the required software dependencies to support Ansible and enable Skytap’s IBM i customers to use this package.

Here’s a quick guide on how to set it up in Skytap.

Step 1: Deploy the CentOS Ansible Control Node template

Sign in to Skytap and deploy a template using an operating system of your choice to create your own Ansible Control Node. You can follow the instructions provided here: https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html

Step 2: Add IBM i LPARs 

Add new or existing IBM i LPARs to the environment. Ansible works best if it runs in the same environment as the VMs or LPARs that you want to manage. Technically, all that is required is a fast network connection between the control node and the machines that it would manage, such as through VPNs. But we recommend having all of the machines in the same environment to maximize network speeds.

A screenshot of a social media post

Description automatically generated

Step 3: Enable SSH on your IBM i LPARs

Ansible requires an SSH connection between the node and each LPAR that it manages. Because SSH is not enabled by default on the IBM i public templates, you might have to enable it manually. You can do this by signing in to your IBM i LPAR via 5250 emulator or through the Skytap SRA console as QSECOFR and running the STRTCPSVR SERVER(*SSHD) command.

Step 4: Verify Ansible dependencies on IBM i

Sign in to your IBM i LPAR using SSH. 

All of the required dependencies should be available in the IBM i public template. If you are using your own IBM i template, verify that python3, python3-toolkit and python3-ibm_db packages are installed, if not, you can run this command to install them:

/Qopensys/pkgs/bin/yum install python3 python3-itoolkit python3-ibm_db

Step 5: In the Ansible Control Node, install the IBM I Collection

(https://ibm.github.io/ansible-for-i/installation.html)

You can install the IBM i Collection by executing these commands:

  1. Set up a playbook to enable IBM i: 
cd ~/.ansible/collections/ansible_collections/ibm/power_ibmi/playbooks
  1. Configure Ansible with the relevant host information in the host_ibmi.ini file. You can use hostnames or IP addresses. Here’s an example:
[ibmi]
ibmi.example.com ansible_ssh_user=user01 ansible_ssh_pass=User123!@#[ibmi:vars]
ansible_python_interpreter="/QOpensys/pkgs/bin/python3"
ansible_ssh_common_args='-o StrictHostKeyChecking=no'
  1. Copy hosts_ibmi.ini to /etc/ansible/hosts.

Step 6: Test Ansible 

There are many example playbooks (https://github.com/IBM/ansible-for-i/tree/devel/playbooks) provided by IBM to get you started. For this guide, we’ll be using the CL command playbook.

  1. Download theibmi-cl-command-sample.yml into the Ansible control node.
  2. Execute the playbook by running this command: ansible-playbook ibmi-cl-command-sample.yml.

Step 7: Verify if everything is working correctly

Verify that the library was created, that an error was thrown when the playbook tried to create a second instance of an existing library, and that the library eventually gets deleted.

You should see the following output:

[root@centos7sx64 playbooks]# ansible-playbook ibmi-cl-command-sample.yml
[WARNING]: running playbook inside collection ibm.power_ibmi

PLAY [all] **************************************************************************************************


TASK [run the CL command to create a library] ***************************************************************
ok: [ibmi.example.com]


TASK [run the CL command to create the library again] *******************************************************
fatal: [ibmi.example.com]: FAILED! => {"changed": false, "cmd": "CRTLIB LIB(ANSIBLEI)", "delta": "0:00:01.235676", "end": "2020-08-14 16:47:53.260390", "job_log": [{"FROM_INSTRUCTION": "1005", "FROM_LIBRARY": "QSYS", "FROM_MODULE": null, "FROM_PROCEDURE": null, "FROM_PROGRAM": "QLICRLIB", "FROM_USER": "QSECOFR", "MESSAGE_FILE": "QCPFMSG", "MESSAGE_ID": "CPF2111", "MESSAGE_LIBRARY": "QSYS", "MESSAGE_SECOND_LEVEL_TEXT": "&N Recovery  . . . :   Before creating or renaming this library, change the new library name or delete the existing library (DLTLIB command). &P -- Use DSPLIB ASPDEV(*ALLAVL) to search for the library. If the library is not found and you are authorized to all auxiliary storage pool (ASP) devices, a library recovery object exists. To remove the library recovery object, either run Reclaim Storage, Initial Program Load (IPL) the machine, or, if the library exists in a primary or secondary ASP, vary off then vary on the ASP device.", "MESSAGE_SUBTYPE": "EXCEPTION HANDLED", "MESSAGE_TEXT": "Library ANSIBLEI already exists.", "MESSAGE_TIMESTAMP": "2020-08-14T16:47:53.073500", "MESSAGE_TYPE": "ESCAPE", "ORDINAL_POSITION": 10, "SEVERITY": 40, "TO_INSTRUCTION": "5833", "TO_LIBRARY": "QXMLSERV", "TO_MODULE": "PLUGILE", "TO_PROCEDURE": "ILECMDEXC", "TO_PROGRAM": "XMLSTOREDP"}, {"FROM_INSTRUCTION": "9558", "FROM_LIBRARY": "QSYS", "FROM_MODULE": "QSQSRVR", "FROM_PROCEDURE": "QSQSRVR", "FROM_PROGRAM": "QSQSRVR", "FROM_USER": "QSECOFR", "MESSAGE_FILE": "QCPFMSG", "MESSAGE_ID": "CPF9898", "MESSAGE_LIBRARY": "QSYS", "MESSAGE_SECOND_LEVEL_TEXT": "&N Cause . . . . . :   This message is used by application programs as a general escape message.", "MESSAGE_SUBTYPE": null, "MESSAGE_TEXT": "SERVER MODE CONNECTING JOB IS 004164/QSECOFR/QP0ZSPWP.", "MESSAGE_TIMESTAMP": "2020-08-14T16:47:52.332989", "MESSAGE_TYPE": "COMPLETION", "ORDINAL_POSITION": 9, "SEVERITY": 40, "TO_INSTRUCTION": "9558", "TO_LIBRARY": "QSYS", "TO_MODULE": "QSQSRVR", "TO_PROCEDURE": "QSQSRVR", "TO_PROGRAM": "QSQSRVR"}, {"FROM_INSTRUCTION": "9467", "FROM_LIBRARY": "QSYS", "FROM_MODULE": "QSQSRVR", "FROM_PROCEDURE": "QSQSRVR", "FROM_PROGRAM": "QSQSRVR", "FROM_USER": "QSECOFR", "MESSAGE_FILE": null, "MESSAGE_ID": null, "MESSAGE_LIBRARY": null, "MESSAGE_SECOND_LEVEL_TEXT": null, "MESSAGE_SUBTYPE": null, "MESSAGE_TEXT": "User Profile = QSECOFR   ", "MESSAGE_TIMESTAMP": "2020-08-14T16:47:52.332928", "MESSAGE_TYPE": "COMPLETION", "ORDINAL_POSITION": 8, "SEVERITY": 0, "TO_INSTRUCTION": "9467", "TO_LIBRARY": "QSYS", "TO_MODULE": "QSQSRVR", "TO_PROCEDURE": "QSQSRVR", "TO_PROGRAM": "QSQSRVR"}, {"FROM_INSTRUCTION": "11F3", "FROM_LIBRARY": "QSYS", "FROM_MODULE": null, "FROM_PROCEDURE": null, "FROM_PROGRAM": "QWTCHGJB", "FROM_USER": "QSECOFR", "MESSAGE_FILE": "QCPFMSG", "MESSAGE_ID": "CPF1301", "MESSAGE_LIBRARY": "QSYS", "MESSAGE_SECOND_LEVEL_TEXT": "&N Cause . . . . . :   Job resource accounting data for job 003492/QUSER/QSQSRVR was not journaled to the system accounting journal QSYS/QACGJRN. &P -- Reason codes and their meanings follow: &P -- 1-The accounting level system value (QACGLVL) indicated that this level of resource accounting was not to be done when the job entered the system. &P -- 2-The accounting journal QSYS/QACGJRN is unable to receive the data.  . The accounting data was sent to the history log (QHST) as the text of a CPF1303 message.  . See CPF1302 in the history log (QHST) for recovery action. &P -- 3-The accounting journal QSYS/QACGJRN  was allocated to another job.  . The accounting data was sent to the history log (QHST) as the text of a CPF1303 message.", "MESSAGE_SUBTYPE": null, "MESSAGE_TEXT": "ACGDTA for 003492/QUSER/QSQSRVR not journaled; reason 1.", "MESSAGE_TIMESTAMP": "2020-08-14T16:47:52.332876", "MESSAGE_TYPE": "INFORMATIONAL", "ORDINAL_POSITION": 7, "SEVERITY": 30, "TO_INSTRUCTION": "9376", "TO_LIBRARY": "QSYS", "TO_MODULE": "QSQSRVR", "TO_PROCEDURE": "QSQSRVR", "TO_PROGRAM": "QSQSRVR"}, {"FROM_INSTRUCTION": "318B", "FROM_LIBRARY": "QSYS", "FROM_MODULE": null, "FROM_PROCEDURE": null, "FROM_PROGRAM": "QWTCHGJB", "FROM_USER": "QSECOFR", "MESSAGE_FILE": "QCPFMSG", "MESSAGE_ID": "CPD1672", "MESSAGE_LIBRARY": "QSYS", "MESSAGE_SECOND_LEVEL_TEXT": "&N Cause . . . . . :   The request to change the job attributes completed successfully, however errors occurred during processing. &N Recovery  . . . :   See previously listed messages for details.", "MESSAGE_SUBTYPE": null, "MESSAGE_TEXT": "Job changed successfully; however errors occurred.", "MESSAGE_TIMESTAMP": "2020-08-14T16:47:52.332763", "MESSAGE_TYPE": "DIAGNOSTIC", "ORDINAL_POSITION": 6, "SEVERITY": 0, "TO_INSTRUCTION": "9369", "TO_LIBRARY": "QSYS", "TO_MODULE": "QSQSRVR", "TO_PROCEDURE": "QSQSRVR", "TO_PROGRAM": "QSQSRVR"}, {"FROM_INSTRUCTION": "318B", "FROM_LIBRARY": "QSYS", "FROM_MODULE": null, "FROM_PROCEDURE": null, "FROM_PROGRAM": "QWTCHGJB", "FROM_USER": "QSECOFR", "MESSAGE_FILE": "QCPFMSG", "MESSAGE_ID": "CPD0912", "MESSAGE_LIBRARY": "QSYS", "MESSAGE_SECOND_LEVEL_TEXT": "&N Cause . . . . . :   The printer device was not found. &N Recovery  . . . :   Either create the printer device (CRTDEVPRT command) or if the printer device name is not correct, change the printer device name and then try the command again.", "MESSAGE_SUBTYPE": null, "MESSAGE_TEXT": "Printer device PRT01 not found.", "MESSAGE_TIMESTAMP": "2020-08-14T16:47:52.332342", "MESSAGE_TYPE": "DIAGNOSTIC", "ORDINAL_POSITION": 5, "SEVERITY": 20, "TO_INSTRUCTION": "9369", "TO_LIBRARY": "QSYS", "TO_MODULE": "QSQSRVR", "TO_PROCEDURE": "QSQSRVR", "TO_PROGRAM": "QSQSRVR"}], "joblog": true, "msg": "non-zero return code:255", "rc": 255, "start": "2020-08-14 16:47:52.024714", "stderr": "{'error': '*** error CRTLIB LIB(ANSIBLEI)', 'error1': '202', 'version': 'XML Toolkit 2.0.1', 'xmlhint': 'CRTLIB LIB(ANSIBLEI)', 'xmlhint2': 'CRTLIB LIB(ANSIBLEI)', 'jobipc': '*na', 'jobipcskey': 'FFFFFFFF', 'jobname': 'QSQSRVR', 'jobuser': 'QUSER', 'jobnbr': '003492', 'curuser': 'QSECOFR', 'ccsid': '37', 'dftccsid': '37', 'paseccsid': '0', 'syslibl': 'QSYS QSYS2 QHLPSYS QUSRSYS', 'usrlibl': 'QGPL QTEMP'}", "stderr_lines": ["{'error': '*** error CRTLIB LIB(ANSIBLEI)', 'error1': '202', 'version': 'XML Toolkit 2.0.1', 'xmlhint': 'CRTLIB LIB(ANSIBLEI)', 'xmlhint2': 'CRTLIB LIB(ANSIBLEI)', 'jobipc': '*na', 'jobipcskey': 'FFFFFFFF', 'jobname': 'QSQSRVR', 'jobuser': 'QUSER', 'jobnbr': '003492', 'curuser': 'QSECOFR', 'ccsid': '37', 'dftccsid': '37', 'paseccsid': '0', 'syslibl': 'QSYS QSYS2 QHLPSYS QUSRSYS', 'usrlibl': 'QGPL QTEMP'}"], "stdout": "", "stdout_lines": []}
...ignoring


TASK [assert the repeating creation of the library failed] **************************************************
ok: [ibmi.example.com] => {
    "changed": false,
    "msg": "All assertions passed"
}


TASK [run the CL command to delete the library] *************************************************************
ok: [ibmi.example.com]


PLAY RECAP **************************************************************************************************
ibmi.example.com                   : 
ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1   

This sample goes through four actions:

  1. Create a library called ansiblei using the following command: crtlib lib(ansiblei).
    1. Create the library again to force an error.
    1. Assert that the repeated create library action failed.
    1. Delete the test library: dltlib ansiblei.

There you go, a few quick and easy steps to setting up Ansible to manage your IBM i LPARs on Skytap.

Join our email list for news, product updates, and more.