Ansible’s cloud modules for OpenStack offer various modules to manage most of OpenStack’s components. In this post, we will show how to perform basic operations with Cinder volumes — create a volume, attach it to and detach it from a VM.

Prerequisites

In order to be able to follow the steps and perform the commands presented in this post, you need to do the following:

  • Install Ansible ($ sudo pip install ansible),
  • Install Shade ($ pip install shade).
  • Deploy two Ubuntu 16.04 VMs. They will be referred to as vm1 and vm2. You can deploy a VM in Dashboard (Compute -> Instances -> Launch Instance) .
  • Set the OS_ variables (OS_AUTH_URL, OS_PROJECT_ID, OS_PROJECT_NAME, OS_USER_DOMAIN_NAME, OS_USERNAME, OS_PASSWORD, and OS_REGION_NAME) to enable Absible the access to your project. The easiest way to do so is to source the openrc file. You can download one in Dashboard -> Access & Security -> API Access -> Download OpenStack RC File v3 and execute it (run $ source ./your-project-openrc.sh ).
  • Finally, have one of the SSH keys available in the project to be added to your SSH agent so that you as well as Ansible can SSH to the VMs.

We assume that you have at least a basic knowledge of Ansible. Otherwise, we recommend reading this tutorial first.

Cinder volumes

Cinder provides block storage for OpenStack compute instances. It is designated for providing persistent storage that is independent on the life-cycle of compute instances. That means that we are able to reuse a Cinder volume on several instances (only one at a time). Therefore, the tasks concerning block storage include mainly the creation and deletion of volumes and attachment of volumes to and detachment from an instance.

Create a Cinder volume

Creation of volumes is usually not performed as frequently as its attachment because volumes are often being reused for multiple instances as a form of data persistence over multiple instances’ life-cycles. Nevertheless, it is also important to be able to automate this step as a part of creation of an environment ‘from the scratch’.

The module for creation and deletion of a volume is called os_volume. There, we can specify the name, size, and other parameters of the volume we want to create. In our case we specify a 1GB volume called ansible_volume in the availability zone nova . Let’s attach the volume to the VM in playbook called create_volume.yaml.

- name: Create persistent data storage
  hosts: localhost
  tasks:
  - name: Create 1GB volume
    os_volume:
      state: present
      display_name: ansible_volume
      size: 1
      availability_zone: nova
      display_description: Test volume created by Ansible.

And execute the playbook — Ansible will use the environment variables to perform the operation in the specified project and by the specified user.

$ ansible-playbook create_volume.yaml

Once the command is finished, you can check the Dashboard to see that the volume is present (Compute -> Volumes).

Attach the volume to a VM

Having an existing volume and a running VM in place, we can attach the volume to the VM so that it can be used by the running instance. Since the volume has just been created, it contains no data yet. Let’s attach the volume to the VM in playbook called attach_volume_vm1.yaml.

- name: Attach a volume
  hosts: localhost
  tasks:
  - name: Atach the volume to vm1
    os_server_volume:
      state: present
      server: vm1
      volume: ansible_volume
      device: /dev/vdb

For the volume attachment, we use the module os_server_volume. The module requires, as expected, the name of the interacting VM (parameter server) as well as the volume. Besides, a useful option is specifying the device to attach the volume to. In our case, we chose /dev/vdb. Before choosing the device, make sure that it is free. Should you omit this parameter, the device name is determined automatically.

Execute the playbook the usual way:

$ ansible-playbook attach_volume_vm1.yaml

You can make sure again in the Dashboard that the volume is attached to the VM (Dashboard -> Volumes).

Mount the attached volume

Now let’s mount the volume on the VM. Since we specified the path to attach the volume to, we can use that for the volume mounting. To do so, let’s SSH to the VM and switch to superuser.

localhost$ ssh ubuntu@<IP_of_vm1>
      vm1$ sudo -i

Having the volume attached to the VM, we will build a file system on the volume so that it can be browsed in the same way as the file system on the VM. For that, we will use mkfs.ext4 to create file system ext4.

# mkfs.ext4 /dev/vdb

The file system, after being created, can be mounted. To mount a file system, we need to specify the device path, the path to mount the file system to, and the file system type. We will mount the file system to /tmp/volume. Since the folder does not exist yet, we will create it before mounting the volume.

# mkdir -p /tmp/volume
# mount /dev/vdb /tmp/volume/ -t ext4

The filesystem is now mounted to the specified path so we can create a file there. The file is being created on the volume so that even if the VM gets terminated, we will not lose the content.

# echo "Test file on the mounted volume." >> /tmp/volume/test_file.txt

You can exit the SSH connection now.

Detach a volume

The current state is us having the volume attached to vm1. Moreover, the volume has a file system and there is a text file that we created there. To use the volume (with its content) on another VM, let’s detach the volume with ansible first. To do so, we specify the playbook detach_volume_vm1.yaml. The playbook uses the same module as the one for volume attachment — os_server_volume — however this time with state parameter set to absent. That indicates that we do not want to have the specified state. The rest of the module parameters specify the volume that we manipulate in the same way as in attach_volume_vm1.yaml.

- name: Detach a volume
  hosts: localhost
  tasks:
  - name: Detach the volume from vm1
    os_server_volume:
      state: absent
      server: vm1
      volume: ansible_volume

The playbook can be executed now.

$ ansible-playbook detach_volume_vm1.yaml

See the result

The volume is no longer attached to the first VM. Therefore, we can attach it to the second one. To do so, we need to slightly modify the playbook attach_volume_vm1.yaml. The parameter server needs to be changed from vm1 to vm2 so that the volume will be attached to vm2 instead. Save the modified playbook as attach_volume_vm2.yaml and execute it.

$ ansible-playbook attach_volume_vm2.yaml

The volume is now attached to the second VM. You can again check it in the Dashboard. Now, we use the same approach as before to mount the volume. First, establish the SSH connection to vm2, then switch to supersuer, create a folder for mounting the volume, and perform the mount (we do not need to execute mkfs since the file system has already been created the first time we used the volume and is still present).

$ ssh ubuntu@<IP_of_vm2>
$ sudo -i
# mkdir -p /tmp/volume
# mount /dev/vdb /tmp/volume/ -t ext4

The volume is now mounted to /tmp/volume — as before. Since the volume provides persistent storage, the content we created on the first VM should be now available on vm2. Let’s try to read the file /tmp/volume/test_file.txt

# cat /tmp/volume/test_file.txt
Test file on the mounted volume.

Summary

Ansible is a useful tool for operating with OpenStack infrastructure. In this article, we used Ansible to operate an instance of OpenStack Block Storage. It provided persistent storage for VMs. We created the volume and attached it to and later detached it from a VM with use of Ansible modules and playbooks.

Ansible is an easy way of how to transfer your basic operations with OpenStack infrastructure into code. That helps when redeploying a certain setting. It shortens the necessary time and can assure the same state every time it is used. Considering Cinder, we showed how it eases volume creations and its presence on preferred VM.