Automating PowerVC using Ansible

Red Hat Ansible: Automation for everyone

Automation is a fundamental mechanism in any digital transformation. Red Hat® Ansible is an extensive automation tool designed to be powerful and simple to use. Ansible’s popularity continues to rise for several reasons:

Ansible can be extended even further with Red Hat Ansible Automation Platform, which includes Ansible Tower, a visual dashboard for managing inventories, scheduling, notification, and so on.

Automating IBM PowerVC with Ansible

IBM PowerVC, built on top of OpenStack technology, is the strategic enterprise virtualization and cloud management solution for IBM® Power Systems™. It provides several benefits–simplified virtualization management and operations, rapid provisioning and upward integration with other technologies, such as Ansible. Because of its OpenStack heritage, the freely available OpenStack modules included with Ansible are all you need to get started (note that these Ansible modules are available through the community only–that is, no enterprise support provided at this time). Note that you can also use the Ansible uri module to directly call PowerVC APIs that may not be exposed through the OpenStack modules.

OpenStack modules applicable to PowerVC

As mentioned previously, because PowerVC is built on top of OpenStack technology, many of the OpenStack Ansible modules just work against a PowerVC target. However, not all modules are applicable because PowerVC does not provide all of the OpenStack services. To that end, below is a list of applicable Ansible modules as of this writing.

  • os_auth
  • os_client_config
  • os_flavor_info
  • os_image_info
  • os_keypair
  • os_networks_info
  • os_nova_flavor
  • os_nova_host_aggregate
  • os_quota
  • os_server
  • os_server_group
  • os_server
  • os_server_action
  • os_server_group
  • os_server_info
  • os_server_metadata
  • os_server_volume
  • os_volume

Example: Provision a virtual machine

As an example, we’ll walk through provisioning a new virtual machine (VM) using the os_server module.

Note: All playbooks and configuration files used in this example are available on GitHub at https://github.com/ppc64le/devops-automation/tree/master/ansible/powervc

Install Ansible

See Installing Ansible for detailed installation instructions. Everything in this example can be done with the command line interface, but you should also check out Red Hat Ansible Tower and the upstream AWX project, which provide a nice GUI interface to manage Ansible at enterprise scale.

The Ansible OpenStack modules require the Python ‘openstacksdk’ package. Ansible Tower comes with this installed. If you’re using the Ansible CLI, you can easily install it from your Ansible control node using pip: pip install openstacksdk --user.

Starting with Ansible v2.9 content, including the OpenStack modules, is distributed through “collections” hosted in Ansible Galaxy. Here’s a quick overview of the concept: https://www.ansible.com/blog/the-future-of-ansible-content-delivery. Ansible v2.10+ requires using the openstack.cloud collection. You can install the collection using the ‘ansible-galaxy’ CLI tool which comes with Ansible v2.9+: ansible-galaxy collection install openstack.cloud.

Once Ansible is installed into your control node, create an empty project directory.

$ mkdir ansible-demo
$ cd ansible-demo/
ansible-demo$

Configure your inventory

Ansible uses an inventory of managed hosts. The inventory can be as simple as a text file with a list of host names. In more dynamic environments, a script can be used to generate the host list and the associated meta data. Ansible comes with an OpenStack dynamic inventory script that we’ll make use of.

To use the dynamic inventory script, we’ll need to define connection and authentication parameters. PowerVC provides an OpenStack RC file with relevant environmental variables (also used for OpenStack CLI clients). Downloading this ‘powervcrc’ file is an easy way to get started. Run the following steps on your Ansible control node:

  1. Download the ‘powervcrc’ file from your PowerVC host. Add write permission and update values as directed in the header:

    ansible-demo$ export PVC_USER='prod_admin'
    ansible-demo$ export PVC_HOST='powervc-demo-server'
    ansible-demo$ scp ${PVC_USER}@${PVC_HOST}:/opt/ibm/powervc/powervcrc .
    prod_admin@powervc-demo-server's password:
    powervcrc                                     100% 1294    23.4KB/s   00:00
    ansible-demo$ chmod u+w powervcrc
    ansible-demo$ head -n 13 powervcrc
    # Copy this file to your user's home directory and edit as necessary.
    # In particular, you may wish to set these values:
    #    - OS_USERNAME     : Your PowerVC user name
    #    - OS_PASSWORD     : Your PowerVC password. If not set, openstack CLIs
    #                        will prompt for the password as needed.
    #    - OS_PROJECT_NAME : If you have multiple projects, specify which project
    #                        you want to access; else you can leave this as
    #                        ibm-default.
    #
    # NOTE: You should not add your password to this file until/unless its file
    # permissions prevent other users from reading it. This is one reason to copy
    # the file to your home directory and edit it there. Or you may wish to not
    # add your password at all and have the CLI prompt you, as noted above.
    
  2. To use SSL, download the CA certificates file and ensure that the OS_CACERT var in ‘powervcrc’ is set to the correct path:

    ansible-demo$ scp ${PVC_USER}@${PVC_HOST}:/etc/pki/tls/certs/powervc.crt .
    prod_admin@powervc-demo-server's password:
    powervc.crt                                   100% 1253    18.8KB/s   00:00
    ansible-demo$ grep OS_CACERT powervcrc
    export OS_CACERT=./powervc.crt
    
  3. Create an ‘ansible.cfg’ file, setting the default inventory path and enabling the OpenStack plugin. Check out Ansible Configuration Settings for information on these and many other parameters.

    ansible-demo$ cat ansible.cfg
    [defaults]
    inventory = ./openstack.yml
    
    [inventory]
    enable_plugins = host_list, openstack.cloud.openstack
    
  4. Create an OpenStack inventory source, ‘openstack.yml’.

    plugin: openstack.cloud.openstack
    expand_hostvars: yes
    fail_on_errors: yes
    
  5. Finally, source your ‘powervcrc’ file. An easy way to verify that your inventory is working is to use ansible-inventory to list all available hosts:

    ansible-demo$ source powervcrc
    ansible-demo$ ansible-inventory --list --yaml
    all:
      children:
        Default Group:
          hosts:
            ansible-demo-vm-name-test40:
              ansible_host: 10.0.0.185
              ansible_ssh_host: 10.0.0.185
              openstack:
    ~snip~
    

You can do the same thing in the Ansible Tower GUI. Enter the information contained in the ‘powervcrc’ file as an OpenStack credential:

fig1

Then you can create an inventory, and add a host source using the OpenStack credential.

Retrieve available images, flavors, and networks

You’ll need to specify image, flavour, and network values when creating a VM. You can get these from the PowerVC GUI, the openstack CLI tool, or by using Ansible modules. Below are a couple of quick playbooks that will retrieve information from your PowerVC server and print an easy-to-read list.

To run the playbook, write the YAML to file and pass the file name to ‘ansible-playbook’, for example, ansible-playbook list_images.yml

Make sure you’re working on your control node in your project directory with ‘ansible.cfg’, and have already run source powervcrc in your shell to define the connection!

The os_image_info module will retrieve the image information:

---
- name: List available PowerVC Images
  hosts: localhost
  tasks:
    - name: Retrieve list of all AIX images
      openstack.cloud.os_image_info:
        properties:
          os_distro: aix  # remove this line to list all images
      register: result

    - name: Print image list
      debug:
        msg: "{{ result | json_query('openstack_image[*].
              {name: name, id: id, os_distro: os_distro, status: status,
              project: location.project.name}') }}"

The os_flavor_info module will retrieve flavor information:

---
- name: List available PowerVC Flavors
  hosts: localhost
  tasks:
    - name: Retrieve list of all public flavors
      openstack.cloud.os_flavor_info:
        vcpus: ">=4"   # Optional filters
        ram: ">16000"  # See module docs for more options
      register: result

    - name: Print flavor list
      debug:
        msg: "{{ result | json_query('openstack_flavors[?is_public==`true`].
              {name: name, id: id, ram: ram, vcpus: vcpus}') }}"

The os_networks_info module will retrieve network information:

---
- name: List available PowerVC Networks
  hosts: localhost
  tasks:
    - name: Retrieve list of all networks
      openstack.cloud.os_networks_info:
      register: result

    - name: Print Network list
      debug:
        var: result.openstack_networks

Example flavor list output shown in Ansible Tower:

fig2

Create a virtual machine

Finally, use the os_server module to create a VM instance. Write the following playbook to the file, update the values with your own and run it!

Other modules used in this playbook:

  • os_keypair: Add an SSH public key to the VM.
  • debug: Display public IP address assigned to the VM. The debug module can be used as a “print” statement.
  • wait_for: Wait until the VM opens port 22 for SSH connections.
  • shell: Use ‘ssh-keyscan’ to add VM host key to ‘known_hosts’ file.
---
- name: Create a PowerVC Virtual Machine
  hosts: localhost
  tasks:
    - name: Create an SSH Key Pair
      openstack.cloud.os_keypair:
        state: present
        name: ansible-ssh-key
        public_key_file: "{{ ansible_env.HOME }}/.ssh/id_rsa.pub"

    - name: Create a new VM instance
      openstack.cloud.os_server:
        state: present
        name: my-new-vm
        image: 94333b61-b751-4143-a177-cacdc7fa492d
        flavor: 6c15cce7-0fe2-4c19-a575-bda0027acede
        key_name: ansible-ssh-key
        nics:
          - net-name: Static_Prod_Network
        meta:
          hostname: my-new-vm
          group: ansible-vms
      register: vm

    - name: Print VM's public IP address
      debug:
        var: vm.openstack.public_v4

    - name: Waits for SSH port 22 to open
      wait_for:
        host: "{{ vm.openstack.public_v4 }}"
        port: 22

    - name: Add VM host key to known hosts
      shell: "ssh-keyscan -H {{ vm.openstack.public_v4 }} >> ~/.ssh/known_hosts"

Example output of a VM creation job in Ansible Tower:

fig3

Keep going: Using Ansible to automate tasks on the new instance

You are now ready to leverage the full potential of Ansible configuration management! Run your existing playbooks, develop new content, or download from the community using Ansible Galaxy.

A few simple examples

Ansible ad-hoc commands allow you to run simple host tasks with CLI one-liners. Here is a quick example:

ansible-demo$ ansible ansible-vms -a "uname -p" --user root
SSH password:
my-new-vm | CHANGED | rc=0 >>
powerpc

An example playbook for IBM AIX® that downloads and configures yum package manager, and then installs MariaDB:

---
- name: Install MariaDB open source relational database
  hosts: ansible-vms
  tasks:
    - name: Download 'yum.sh' script
      get_url:
        url: https://public.dhe.ibm.com/aix/freeSoftware/aixtoolbox/ezinstall/ppc/yum.sh
        dest: /tmp/yum.sh
        mode: 0755
        validate_certs: False

    - name: Execute the 'yum.sh' script
      shell: /tmp/yum.sh

    - name: Install MariaDB package
      yum:
        name: mariadb-server
        state: latest