---
title: 'Ansible for SAN Automation: Part 3 Pure Storage Flash Array'
url: 'https://tech.luc3nt.com/blog/ansible-for-san-automation-part-3'
markdown: 'https://tech.luc3nt.com/blog/ansible-for-san-automation-part-3.md'
date: '2022-05-12'
description: "In part 3 of our Ansible for SAN Automation series I'm going to document how I build automations targeting deployment and configuration management and routine tasks on a Pure Storage FlashArray//X. Take my word for it, Pure Storage's FlashArray//X has to be the nicest all-flash storage array on th…"
taxonomy:
  category:
    - blog
  tag:
    - automation
    - ansible
    - pure
  archives_month:
    - may_2022
  archives_year:
    - '2022'
---

[ Home ](https://tech.luc3nt.com/)     [ Blog ](https://tech.luc3nt.com/blog)      Ansible for SAN Automation: Part 3 Pure Storage Flash Array    

In part 3 of our Ansible for SAN Automation series I'm going to document how I build automations targeting deployment and configuration management and routine tasks on a Pure Storage FlashArray//X. Take my word for it, Pure Storage's FlashArray//X has to be the nicest all-flash storage array on the market. I cant overstate the value that Pure has packed into this product, but one of its most useful features I find is that Pure offers a very feature complete Ansible module collection for both [FlashArray](https://docs.ansible.com/ansible/latest/collections/purestorage/flasharray/index.html) and [FlashBlade](https://docs.ansible.com/ansible/latest/collections/purestorage/flashblade/index.html). Lets jump right in to using it.

An important prerequisite to use the ansible Pure Storage module is that you will need to log into your array and generate an API key for your user account. Or even better create a new ansible service account and generate for that user. In current versions of Purity OS this usually found in **Settings > Access > Users > Create API Token**. The API key will be used below assigned as the var `fa_api`.

### Inventory

First things first, your inventory of your control node should have entires that appear as follows for your Pure Storage FlashArrays. Where you keep your vars is a bit of a personal preference, in the example below I have placed them in my inventory file which is a sin to some. Place them where you prefer just bear in mind [Ansible's variable precedence](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#understanding-variable-precedence).

```yaml
[purefa]
PSFAX01.example.net fa_api=asfq1394_jfas923nas 
PSFAX02.example.net fa_api=asfq1394_jfas923nas 

[purefa:vars]
fa_url="{{ inventory_hostname }}"
ansible_user=admin
ansible_password=!vault...
ansible_become=yes

[all:vars]
domain_name=example.net
```

Now lets make our first playbook. How about something simple, updating the Array name in Purity OS.

```yaml

#!/bin/ansible-playbook
---
- name: "##### Sets the Array name on FlashArray #####"
  hosts: '{{target|default("purefa")}}'
  gather_facts: False

  tasks:
# Set the hostname on FlashArrays
    - name: Set the FlashArray name
      delegate_to: localhost
      purestorage.flasharray.purefa_arrayname:
        name: "{{ inventory_hostname_short }}"
        state: present
        fa_url: "{{ fa_url }}"
        api_token: "{{ fa_api }}"

```

[Above "create-hosts.yml" Playbook available on my Github.](https://github.com/amlucent/automation-playbooks/blob/master/pure/purefa/create-hosts.yml)

So let me explain a few things about our above playbook.

- First, I like to always do a she-bang and put `#! /path/to/ansible-playbook` as the first line of my playbooks, this allows the playbook to be ran like a normal script assuming it has the posix execute mode bit.
- Second, we used a group in our inventory file called `purefa` and we put our flasharray hostnames in this group. In the example I have **PSFAX01.example.net** and **PSFAX02.example.net**, instead you would want to list your flasharray's DNS resolvable hostname. Short names like `PSFAX01` are just fine in your inventory as long as its resolvable and your DNS supports it. Whatever you make this value we will name the array however I have specified to always name the array the short DNS name using the [special variable](https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html). Alter this value as you see fit.
- Finally, the `delegate_to: localhost`. I recommend you go read up about ansible delegation. What I'm saying is all the "work" for this play is going to be done on the localhost. We don't run the whole playbook against the localhost because that solution doesn't scale if you have more than one flasharray. This way we can run the playbook against our entire inventory, all of our flash arrays, or we can `--limit PSFAX01.example.net` and only run against a single host. When we build a playbook with this method we will almost always `delegate_to: localhost` on nearly every task. Just one of the idiosyncrasies of working with a fleet of storage devices like this.

After your have your playbook file created you can run it on your ansible control node. When you run this it should update the array name to whatever you have listed as the name in the inventory file. This is great for forcing configurations against a fleet and preventing unauthorized of unintended changes. You could schedule a playbook like this to run nightly, it could set and reset any configuration variable like defining [DNS servers](https://github.com/amlucent/automation-playbooks/blob/master/pure/purefa/set-dns.yml) and [NTP sources](https://github.com/amlucent/automation-playbooks/blob/master/pure/purefa/set-ntp.yml) just for example. Or maybe setting a [MOTD message banner](https://github.com/amlucent/automation-playbooks/blob/master/pure/purefa/set-banner.yml). Sky is the limit.

Ok, lets do something a bit more advanced. Lets create a playbook that helps us do a pretty common task; define new hosts and associate the WWPNs (or IQNs or NQNs). I have found a very user friendly way to do this is to pull the host's values from a comma separated value spreadsheet so each row represents a host. This method also scales very well, need to add 100 vmware hosts to 4 different storage arrays? Using this .csv method it's no problem.

So open Excel and create a spreadsheet called "hosts.csv". Fill it as the example below:

```csv
Hostname,Platform,WWPNA,WWPNB,IQN,NQN
esx-server01,esxi,56:2:22:11:22:88:11:67,56:2:22:11:22:88:11:68,,
esx-server02,esxi,56:2:22:11:22:88:11:71,56:2:22:11:22:88:11:72,iqn.1994-05.com.vmware:7d366003914,
aix-server01,aix,,,,nqn.2014-08.com.vendor:nvme:nvm-subsystem-sn-d78432
```

Put your hostnames for the new servers in the `Hostname` column. If using Fibre Channel put your WWPNs in the two columns `WWPNA` and `WWPNB`. If using iscsi put it in the `IQN` column. NVMe-oF put it in the `NQN` column. It is possible to fill out more than one column type for a single host (ie both fibre channel + iscsi) and pure says it will use the preferred method and fall back to the slower but I dont do this in production because I dont trust it but to be fair I havent tested it. If you have positive experience with this I would love to hear about it.

After our [hosts.csv](https://github.com/amlucent/automation-playbooks/blob/master/pure/purefa/hosts.csv) file is created and looking as you intend lets make our playbook:

```yaml
#!/bin/ansible-playbook
########################

# DESCRIPTION
# Creates and Removes Hosts on Pure Storage FlashArrays

# DIRECTIONS
# Usage to create a single host
# Run ./create-hosts.yml --tags create-adhoc -e "Hostname=esx-server01,Platform=ESXi,WWPNA=56:2:22:11:22:88:11:67,WWPNB=56:2:22:11:22:88:11:68" -v

# Usage to remove a single host (note, Platform and WWPN/IQN values not required to remove)
# Run ./create-hosts.yml --tags remove-adhoc -e "Hostname=esx-server01" -v

# Usage to create multiple hosts using hosts.csv file: 
#     1. create a file called hosts.csv in the same directory as this playbook.
#     2. Make columns titled "Hostname", "Platform", "WWPNA", and "WWPNB" if using FC. A column named IQN for iscsi, or NQN column for NVMe.  Read about "Platform" values here under personaility - https://docs.ansible.com/ansible/latest/collections/purestorage/flasharray/purefa_host_module.html
#     3. fill in the values in all columns for all the hosts you want to create. 
#
# Run ./create-hosts.yml --tags create-csv -v

# Usage to remove multiple hosts using hosts.csv file:
# Run ./create-hosts.yml --tags remove-csv -v

---
- name: "##### Create and Removes hosts on FlashArrays #####"
  hosts: '{{target|default("purefa")}}'
  gather_facts: False
  strategy: free

  tasks:

    - name: Reading the csv file
      read_csv:
        path: hosts.csv
      register: hosts_list
      delegate_to: localhost
      tags:
      - create-csv
      - remove-csv        

    - name: Creates all hosts from CSV file on FlashArrays
      delegate_to: localhost
      purestorage.flasharray.purefa_host:
        name: "{{ item.Hostname }}"
        personality: "{{ item.Platform }}"
        nqn:
        - "{{ item.NQN }}"
        iqn:
        - "{{ item.IQN }}"
        wwns:
        - "{{ item.WWPNA }}"
        - "{{ item.WWPNB }}"
        fa_url: "{{ fa_url }}"
        api_token: "{{ fa_api }}"
      loop: "{{ hosts_list.list }}" 
      tags:
      - create-csv

    - name: Removes all hosts from CSV file on FlashArrays
      delegate_to: localhost
      purestorage.flasharray.purefa_host:
        name: "{{ item.Hostname }}"
        state: absent
        fa_url: "{{ fa_url }}"
        api_token: "{{ fa_api }}"
      loop: "{{ hosts_list.list }}" 
      tags:
      - remove-csv

    - pause:
      delegate_to: localhost
        prompt: "Enter the hostname to create:"
        echo: true
      register: hostname
    - set_fact:
        ask_user: "{{ hostname.user_input }}"
      when: hostname == ""
      tags:
      - create-adhoc
      - remove-adhoc

    - name: Creates a single FC host on FlashArrays
      delegate_to: localhost
      purestorage.flasharray.purefa_host:
        name: "{{ hostname }}"
        personality: "{{ platform }}"
      #  nqn:
      #  - "{{ NQN }}"
      #  iqn:
      #  - "{{ IQN }}"     
        wwns:
        - "{{ wwpna }}"
        - "{{ wwpnb }}"
        fa_url: "{{ fa_url }}"
        api_token: "{{ fa_api }}"        
      tags:
      - create-adhoc

    - name: Removes a single FC host on FlashArrays
      delegate_to: localhost
      purestorage.flasharray.purefa_host:
        name: "{{ hostname }}"
        state: absent
        fa_url: "{{ fa_url }}"
        api_token: "{{ fa_api }}"
      tags:
      - remove-adhoc

```

[Playbook "create-hosts.yml" also available on my Github.](https://github.com/amlucent/automation-playbooks/blob/master/pure/purefa/create-hosts.yml)

Notice in the `Creates a single FC host on FlashArrays` play task that all of the transport types other than FC `WWPNA` and `WWPNB` are commented out. This is done because when using the `--tag create-adhoc` any options you are not using will fail if they are not commented out as ansible will complain there are "undefined variables". Basically, if you are using iscsi as your preferred connection method youll want to uncomment IQN and comment the other transport types. I prefer Fibre Channel so thats what I leave uncommented.

Directions for use are in the header comments of the playbook. So, give it a go and if you have any questions about its use feel free to leave a comment below.

 [ Previous Post](https://tech.luc3nt.com/blog/netboot-like-a-pro) [Next Post ](https://tech.luc3nt.com/blog/useful-pure-storage-flash-array-cli-commands)

#### Related Posts

- 100 

     [Useful Pure Storage Flash Array CLI commands](https://tech.luc3nt.com/blog/useful-pure-storage-flash-array-cli-commands "Useful Pure Storage Flash Array CLI commands")
- 100 

     [Ansible for SAN Automation: Part 2 Cisco MDS](https://tech.luc3nt.com/blog/ansible-for-san-automation-part-2 "Ansible for SAN Automation: Part 2 Cisco MDS")
- 100 

     [Enabling Cisco MDS Scheduled Backups via CLI](https://tech.luc3nt.com/blog/enabling-cisco-sched-backups-cli "Enabling Cisco MDS Scheduled Backups via CLI")
- 100 

     [Ansible for SAN Automation: Part 1 Introduction](https://tech.luc3nt.com/blog/ansible-for-san-automation-part-1 "Ansible for SAN Automation: Part 1 Introduction")

#### Random Article

 [ I'm Feeling Lucky!](https://tech.luc3nt.com/random)

#### About Me

![imgur](https://i.imgur.com/l86CB8L.png)##### **Tony Lucent**

**Blog Owner - System Engineer - Technology Enthusiast** 
I excel in data storage, storage area networking, disaster recovery, and virtualization.

![](https://raw.githubusercontent.com/bradvin/social-share-urls/master/images/logo-icons/linkedin.jpg) [LinkedIn](https://www.linkedin.com/in/amlucent/)

#### Popular Tags

#### Archives

- [ 2 May 2022  ](https://tech.luc3nt.com/blog/archives_month:may_2022)
- [ 1 April 2022  ](https://tech.luc3nt.com/blog/archives_month:apr_2022)
- [ 2 March 2022  ](https://tech.luc3nt.com/blog/archives_month:mar_2022)
- [ 1 February 2022  ](https://tech.luc3nt.com/blog/archives_month:feb_2022)
- [ 1 November 2020  ](https://tech.luc3nt.com/blog/archives_month:nov_2020)
- [ 2 October 2020  ](https://tech.luc3nt.com/blog/archives_month:oct_2020)
- [ 2 August 2020  ](https://tech.luc3nt.com/blog/archives_month:aug_2020)
- [ 1 July 2020  ](https://tech.luc3nt.com/blog/archives_month:jul_2020)

#### Syndicate

 [ Atom 1.0](https://tech.luc3nt.com/blog.atom) [ RSS](https://tech.luc3nt.com/blog.rss)

---

## Navigation

- Parent: [Blog](https://tech.luc3nt.com/blog.md)
- Previous: [Useful Pure Storage Flash Array CLI commands](https://tech.luc3nt.com/blog/useful-pure-storage-flash-array-cli-commands.md)
- Next: [Ditch the USB drive and Netboot like a PRO](https://tech.luc3nt.com/blog/netboot-like-a-pro.md)
