HPE Nimble Storage Tech Blog
cancel
Showing results for 
Search instead for 
Did you mean: 

NimbleOS loves Ansible

mmattsson

If I end setting up the same thing twice or need to step through a tedious workflow I tend to find myself looking to Ansible for pain relief. I've picked Ansible as my configuration management tool of choice as I can bend it to do whatever I like to anything I like with a language I can read and understand.

Ansible is written in Python and as with all things Python, Ansible is available in the Python Package Index (PyPi), on a node where pip is installed, simply run:

$ pip install ansible


Comprehensive documentation about Ansible is available on docs.ansible.com.

Today I was delighted to discover that the built-in URI module is capable of manipulating NimbleOS arrays via the comprehensive REST API (check it out on InfoSight!). Needless to say, we now have a fully fledged orchestration tool at our disposal!

I'm currently doing a lot testing of an upcoming and exciting Nimble Storage offering and find myself with an array completely cluttered with volumes in all shapes and sizes. I wanted to revert my array to a clean state without disrupting the rest of my configuration and volumes not affected by these tests. The volumes I want to get rid of have two distinct features: they are offline and the volume name contains a specific string. Challenge accepted.

The following Ansible playbook (it's a YAML file, attached below) contains some commentary of what some of the interesting parameters are doing (for clarity, I've put the entire workflow in one playbook):

# volume-reaper.yml

---

# We will use this node to interface with my Nimble Storage Group

- hosts: localhost

  # Since our array is remote, we don't care about collecting local facts

  gather_facts: no

  # Variables local for this play

  vars:

    base_url: https://nimble-array.local:5392/v1

    username: admin

    password: admin

  tasks:

  # First we need a token to be able to use the APIs

  - name: Get API token

    uri:

      url: "{{ vars.base_url }}/tokens"

      validate_certs: no

      method: POST

      # This is the HTTP status code that designates success

      status_code: 201

 

      # This ensures the correct Content-Type header is set

      body_format: json

      # The following structure will be converted to JSON on the fly

      body:

       data:

         username: "{{ vars.username }}"

         password: "{{ vars.password }}"

      # We want to access the content we retrieve

      return_content: yes

    # The returned data JSON object will be accessible in the token dictionary

    register: token

  # List all the volumes

  - name: Fetch all volumes and metadata

    uri:

      url: "{{ vars.base_url }}/volumes/detail?fields=name,online,id"

      method: GET

      validate_certs: no

      status_code: 200

      return_content: yes

      # Here's the token we got from a successful login above

      HEADER_X-Auth-Token: "{{ token.json.data.session_token }}"

    # All volume data is accessible through the volume dictionary

    register: volumes

  - name: Destroy Volumes if offline and contains the name MyTestVol

    uri:

      url: "{{ vars.base_url }}/volumes/{{ item.id }}"

      method: DELETE

      validate_certs: no

      status_code: 200

      return_content: yes

      HEADER_X-Auth-Token: "{{ token.json.data.session_token }}"

    # This task will iterate over all volumes

    with_items: "{{ volumes.json.data }}"

    # ... but only execute the task if the volume name contains MyTestVol and is offline

    when: "('MyTestVol' in item.name and not item.online)"

    # Note: The condition in the when: statement is a Jinja2 expression

So, to simply wipe my array from offline volumes that contains the keyword 'MyTestVol' in the volume name, one would simply run:

$ ansible-playbook volume-reaper.yml

[WARNING]: provided hosts list is empty, only localhost is available

PLAY [localhost] ***************************************************************

TASK [Get API token] ***********************************************************

ok: [localhost]

TASK [Fetch all volumes and metadata] ******************************************

ok: [localhost]

TASK [Destroy Volumes if offline and contains the name MyTestVol] *****************

skipping: [localhost] => (item={u'id': u'0633cfd76905aa2a50000000000000000000000016', u'name': u'MyProdVol3', u'online': True})

ok: [localhost] => (item={u'id': u'0633cfd76905aa2a5000000000000000000000001d', u'name': u'MyTestVol40', u'online': False})

skipping: [localhost] => (item={u'id': u'0633cfd76905aa2a5000000000000000000000001b', u'name': u'MyProdVol2', u'online': True})

PLAY RECAP *********************************************************************

localhost                  : ok=3    changed=0    unreachable=0    failed=0


$ _


Until there is a bleeding need for a native NimbleOS Ansible module, this will more than suffice for most use cases. Please note, for this particular Ansible playbook I was using NimbleOS 3.3, earlier versions have not been tested.

Please tell me what you automated today.

Michael

About the Author

mmattsson

Comments
steves43

Great post!  Thanks for the details on how to get this going.