ansible

DellEMC PowerStore REST API Emulator

In the last few weeks I have spent some time creating a small emulator of the DellEMC PowerStore’s REST API. This was done for some educational requirement, but it might benefit other people out there, hence I am making it public

The emulator provides:

  • 2 API calls to gather information for the array
  • 11 API calls to perform block provisioning, including the host, volume and host_volume_resources

In terms of data, there is some seed data that is run from an external file when it’s started. This data is loaded into memory and will update as we perform provisioning calls. Any changes we make with those will show when we read back the relevant resource. Changes to the data are not persisted between runs

You can interact with the emulator programmatically in your favorite language, or using Postman and even Ansible. The GitHub repo includes a Postman collection and some sample Ansible playbooks.

The playbooks provided are idempotent like the real thing. Another cool thing you will notice while using Ansible is that, as the playbook runs you get to see all the API calls the module is doing under the covers. For one task in Ansible you can sometimes see 6 API calls run in the background to make Ansible’s declarative syntax work and ensure idempotency … pretty cool. I promise not to take again for granted all the extra effort Ansible does for me 🙂

The emulator mimics to a large extent the behavior of a real array for those calls, for example you can use the ‘select’ and ‘order’ parameters to customize the output of GET calls. You can also use the ‘field matching’ capabilities of the real API when querying a collection. However it will only take one field to match and it will only use the “eq” operator

There are some checks that are not implemented, ex: ensuring the new size of a volume is larger than the existing size during a volume extension, or not checking if a volume has mappings before deleting it … At the end of the day this is meant to be an educational tool to teach storage automation.

In order to run the emulator you will need Python3 (I have tried it with Python 3.9.2 and 3.6.8) and the packages specified in the ‘requirements.txt’ file

IMPORTANT: For Ansible I have tested everything with version 2.9.9 and version 1.1 of the PowerStore Ansible modules. Other users have tested successfully version 1.2.1 as well. However some changes were introduced in version 1.4.0 that will try to make use of certain API calls (ex: /logout, /login_session and /software_installed) that are not implemented in the emulator and will cause the Ansible modules to fail. So please avoid 1.4.0 and later

You can download the emulator and all the related content in GitHub.

https://github.com/cermegno/powerstore-api-emulator

Happy hacking!

3 replies »

  1. Deepak:
    FYI, I am going to deliver an Ansible class in early June to Dell EMC specialists in Austin TX. I would like to use your
    emulator to show how some of the Ansible Dell specific modules work. I pulled down all of the files, and when I run
    the Flask emulation program, it starts up just fine. I also changed the target IP in the creds.yml file to reflect the IP
    that the server pulled. However, when I try to play the prov.yml playbook, this is what I get:

    TASK [Create host] ******************************************************************
    fatal: [localhost]: FAILED! => {“changed”: false, “error_code”: 7, “msg”: “Unable to get details of host with ID: 19894d22-87e1-4fef-9a04-5f1200369542 — error: ValueError: ‘[Errno Expecting value] \n404 Not Found\nNot Found\nThe requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.\n: 0’ for Method: ‘GET’ URL: ‘https://192.168.184.176:443/api/rest/software_installed’ PayLoad: ‘None’ QueryString: ‘{‘select’: ‘release_version’}'”, “status_code”: null}

    here is what the Flask server shows:

    * Serving Flask app ‘powerstore-emulator’ (lazy loading)
    * Environment: production
    WARNING: This is a development server. Do not use it in a production deployment.
    Use a production WSGI server instead.
    * Debug mode: off
    * Running on all addresses.
    WARNING: This is a development server. Do not use it in a production deployment.
    * Running on https://192.168.184.176:443/ (Press CTRL+C to quit)
    192.168.184.176 – – [09/Apr/2022 15:01:40] “GET /api/rest/login_session HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:40] “GET /api/rest/host?select=id%2Cname%2Cdescription%2Cos_type%2Chost_group_id%2Chost_initiators%2Cos_type_l10n%2Cmapped_hosts%28id%2Clogical_unit_number%2Chost_group%28id%2Cname%29%2Cvolume%28id%2Cname%29%29&name=eq.demo01 HTTP/1.1” 200 –
    192.168.184.176 – – [09/Apr/2022 15:01:40] “POST /api/rest/logout HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:40] “GET /api/rest/login_session HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:40] “POST /api/rest/host HTTP/1.1” 201 –
    192.168.184.176 – – [09/Apr/2022 15:01:40] “POST /api/rest/logout HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:40] “GET /api/rest/login_session HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:40] “GET /api/rest/host?select=id%2Cname%2Cdescription%2Cos_type%2Chost_group_id%2Chost_initiators%2Cos_type_l10n%2Cmapped_hosts%28id%2Clogical_unit_number%2Chost_group%28id%2Cname%29%2Cvolume%28id%2Cname%29%29&name=eq.demo01 HTTP/1.1” 200 –
    192.168.184.176 – – [09/Apr/2022 15:01:40] “POST /api/rest/logout HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:40] “GET /api/rest/login_session HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:40] “GET /api/rest/software_installed?select=release_version HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:40] “POST /api/rest/logout HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “GET /api/rest/login_session HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “GET /api/rest/host?select=id%2Cname%2Cdescription%2Cos_type%2Chost_group_id%2Chost_initiators%2Cos_type_l10n%2Cmapped_hosts%28id%2Clogical_unit_number%2Chost_group%28id%2Cname%29%2Cvolume%28id%2Cname%29%29&name=eq.demo01 HTTP/1.1” 200 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “POST /api/rest/logout HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “GET /api/rest/login_session HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “GET /api/rest/volume?select=id%2Cname%2Cdescription%2Ctype%2Cwwn%2Cappliance_id%2Cstate%2Csize%2Ccreation_timestamp%2Cprotection_policy_id%2Cperformance_policy_id%2Cprotection_policy%28name%2Cid%29%2Cperformance_policy%28name%2Cid%29%2Cis_replication_destination%2Cmigration_session_id%2Cprotection_data%2Clocation_history%2Ctype_l10n%2Cstate_l10n%2Chost_group%28name%2Cid%29%2Chost%28name%2Cid%29%2Cvolume_groups%28name%2Cid%29%2Cmapped_volumes%28id%2Clogical_unit_number%29&name=eq.demo01_vol1 HTTP/1.1” 200 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “POST /api/rest/logout HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “GET /api/rest/login_session HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “POST /api/rest/volume HTTP/1.1” 201 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “POST /api/rest/logout HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “GET /api/rest/login_session HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “GET /api/rest/volume?select=id%2Cname%2Cdescription%2Ctype%2Cwwn%2Cappliance_id%2Cstate%2Csize%2Ccreation_timestamp%2Cprotection_policy_id%2Cperformance_policy_id%2Cprotection_policy%28name%2Cid%29%2Cperformance_policy%28name%2Cid%29%2Cis_replication_destination%2Cmigration_session_id%2Cprotection_data%2Clocation_history%2Ctype_l10n%2Cstate_l10n%2Chost_group%28name%2Cid%29%2Chost%28name%2Cid%29%2Cvolume_groups%28name%2Cid%29%2Cmapped_volumes%28id%2Clogical_unit_number%29&name=eq.demo01_vol1 HTTP/1.1” 200 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “POST /api/rest/logout HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “GET /api/rest/login_session HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “GET /api/rest/host_volume_mapping?select=id%2C+host_id%2C+host_group_id%2Clogical_unit_number&volume_id=eq.19894d22-87e1-4fef-9a04-5f1200941126 HTTP/1.1” 200 –

    It looks like to me that the Ansible module is trying to figure out if the host definition already exists, but it is getting host-id that
    you generated in the Flask code – does that sound right ?

    any ideas on how to fix it ? I would really like to be able to use your simulation during the class.

    If you wish, reply back to : laine@teteranet.net and/or laine.educational@gmail.com Phil LoVecchio

    192.168.184.176 – – [09/Apr/2022 15:01:41] “POST /api/rest/logout HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “GET /api/rest/login_session HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “GET /api/rest/software_installed?select=release_version HTTP/1.1” 404 –
    192.168.184.176 – – [09/Apr/2022 15:01:41] “POST /api/rest/logout HTTP/1.1” 404 –

    Like

    • Hi Phil, thanks for reaching out. The emulator was developed with version 1.1 of the Ansible modules. It appears that in version 1.4.0 a number of changes were introduced to handle the connection to the array using the REST API endpoints /logout and /login_session. Those two API calls were not implemented in version 1.1 hence the 404 status code you are seeing. The other API call that the modules are trying to use is /software_installed which appears to have been introduced also in 1.4.0. So using version 1.3.0 should work however I haven’t tested it myself. Another user tested recently 1.2.1 and his test worked well.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s