Forum Discussion

mdaniel's avatar
mdaniel
Day Hiker II
1 month ago

Flashblade & Ansible collection

Hello community,

We are facing some issues with our FlashBlade when provisioning policies with Ansible. We have updated all the components (py-pure-client and the collection), and we are failing on a simple policy deployment.

- name: Test
  purestorage.flashblade.purefb_policy:
    name: "filesystem_export_policy"
    enabled: True
    policy_type: "nfs"
    at: True
    client: "mynfsexport.flashblade.local"
    secure: True
    security: "sys"
    permission: "rw"
    access: "no-squash"
    fb_url: "{{ fb_host }}"
    api_token: "{{ fb_api_token }}"

The complete stack trace is :

The full traceback is:
Traceback (most recent call last):
  File "/home/user/.ansible/tmp/ansible-tmp-1778656887.1852276-3067455-48057529014464/AnsiballZ_purefb_policy.py", line 107, in <module>
    _ansiballz_main()
  File "/home/user/.ansible/tmp/ansible-tmp-1778656887.1852276-3067455-48057529014464/AnsiballZ_purefb_policy.py", line 99, in _ansiballz_main
    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
  File "/home/user/.ansible/tmp/ansible-tmp-1778656887.1852276-3067455-48057529014464/AnsiballZ_purefb_policy.py", line 47, in invoke_module
    runpy.run_module(mod_name='ansible_collections.purestorage.flashblade.plugins.modules.purefb_policy', init_globals=dict(_module_fqn='ansible_collections.purestorage.flashblade.plugins.modules.purefb_policy', _modlib_path=modlib_path),
  File "<frozen runpy>", line 226, in run_module
  File "<frozen runpy>", line 98, in _run_module_code
  File "<frozen runpy>", line 88, in _run_code
  File "/opt/tmp/tmp/ansible_purestorage.flashblade.purefb_policy_payload_xaietsz7/ansible_purestorage.flashblade.purefb_policy_payload.zip/ansible_collections/purestorage/flashblade/plugins/modules/purefb_policy.py", line 4233, in <module>
  File "/opt/tmp/tmp/ansible_purestorage.flashblade.purefb_policy_payload_xaietsz7/ansible_purestorage.flashblade.purefb_policy_payload.zip/ansible_collections/purestorage/flashblade/plugins/modules/purefb_policy.py", line 4008, in main
  File "/opt/tmp/tmp/ansible_purestorage.flashblade.purefb_policy_payload_xaietsz7/ansible_purestorage.flashblade.purefb_policy_payload.zip/ansible_collections/purestorage/flashblade/plugins/modules/purefb_policy.py", line 2392, in update_nfs_policy
AttributeError: 'ErrorResponse' object has no attribute 'items'
fatal: [localhost]: FAILED! => {
    "changed": false,
    "module_stderr": "Traceback (most recent call last):\n  File \"/home/user/.ansible/tmp/ansible-tmp-1778656887.1852276-3067455-48057529014464/AnsiballZ_purefb_policy.py\", line 107, in <module>\n    _ansiballz_main()\n  File \"/home/user/.ansible/tmp/ansible-tmp-1778656887.1852276-3067455-48057529014464/AnsiballZ_purefb_policy.py\", line 99, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/user/.ansible/tmp/ansible-tmp-1778656887.1852276-3067455-48057529014464/AnsiballZ_purefb_policy.py\", line 47, in invoke_module\n    runpy.run_module(mod_name='ansible_collections.purestorage.flashblade.plugins.modules.purefb_policy', init_globals=dict(_module_fqn='ansible_collections.purestorage.flashblade.plugins.modules.purefb_policy', _modlib_path=modlib_path),\n  File \"<frozen runpy>\", line 226, in run_module\n  File \"<frozen runpy>\", line 98, in _run_module_code\n  File \"<frozen runpy>\", line 88, in _run_code\n  File \"/opt/tmp/tmp/ansible_purestorage.flashblade.purefb_policy_payload_xaietsz7/ansible_purestorage.flashblade.purefb_policy_payload.zip/ansible_collections/purestorage/flashblade/plugins/modules/purefb_policy.py\", line 4233, in <module>\n  File \"/opt/tmp/tmp/ansible_purestorage.flashblade.purefb_policy_payload_xaietsz7/ansible_purestorage.flashblade.purefb_policy_payload.zip/ansible_collections/purestorage/flashblade/plugins/modules/purefb_policy.py\", line 4008, in main\n  File \"/opt/tmp/tmp/ansible_purestorage.flashblade.purefb_policy_payload_xaietsz7/ansible_purestorage.flashblade.purefb_policy_payload.zip/ansible_collections/purestorage/flashblade/plugins/modules/purefb_policy.py\", line 2392, in update_nfs_policy\nAttributeError: 'ErrorResponse' object has no attribute 'items'\n",
    "module_stdout": "",
    "msg": "MODULE FAILURE: No start of json char found\nSee stdout/stderr for the exact error",
    "rc": 1
}

If the policy is already set, the playbook runs perfectly fine. The problem occurs when a new policy is injected.

However, we have to install the collection from GitHub. It seems that the artifact built and installed by Ansible Galaxy is not correct. Some commits are not propagated.

For example, with the FlashBlade collection 1.24 (installed from Galaxy), we have:

>>> from pypureclient.flashblade import (
...     PolicyRuleObjectAccessCondition,
...     PolicyRuleObjectAccessPost,
...     PolicyRuleObjectAccess,
...     NfsExportPolicy,
...     NfsExportPolicyRule,
...     Policy,
...     PolicyPatch,
...     PolicyRule,
...     SmbSharePolicyRule,
...     SmbSharePolicy,
...     SmbClientPolicyRule,
...     SmbClientPolicy,
...     ObjectStoreAccessPolicyPost,
...     NetworkAccessPolicy,
...     NetworkAccessPolicyRule,
...     WormDataPolicy,
... )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/user/conda/envs/ansible/lib/python3.12/site-packages/pypureclient/flashblade/__init__.py", line 40, in __getattr__
    raise ImportError(f'module {__package__} has no attribute {name}')
ImportError: module pypureclient.flashblade has no attribute PolicyPatch

We have compared the archive from GitHub and there are many differences with the upstream collection code.

To help, find my my env package : 

 Package           Version
----------------- -----------
annotated-types   0.7.0
ansible-core      2.18.5
bcrypt            5.0.0
certifi           2026.4.22
cffi              2.0.0
cryptography      44.0.0
dnspython         2.8.0
invoke            3.0.3
Jinja2            3.1.4
MarkupSafe        2.1.1
packaging         24.1
paramiko          5.0.0
pip               24.2
py-pure-client    1.88.0
pycparser         2.22
pydantic          2.13.4
pydantic_core     2.46.4
PyJWT             2.12.1
PyNaCl            1.6.2
python-dateutil   2.9.0.post0
PyYAML            6.0.2
resolvelib        1.0.1
setuptools        75.8.2
six               1.17.0
typing_extensions 4.15.0
typing-inspection 0.4.2
urllib3           2.7.0
wheel             0.45.0

And our flashblades are running the Purity//FB 4.6.9.

If anyone has a lead to help us get our Ansible back up and running, I thank them in advance.

We appreciate your help.

Matth

10 Replies

  • mdaniel​ 

    Thanks for confirming the patch works.

    We will get it merged and into a new Collection as soon as we can.

    Simon

  • mdaniel's avatar
    mdaniel
    Day Hiker II

    Hello simon​ 

    I can confirm that the operation is correct.

    I am able to delete/create/update a nfs policy as expected.

    I think you will port the code to the master branch of the collection and I will update all my ansible env.

    Thank you 👍

  • mdaniel​ 

    I've updated the patch, so that should perform correctly now. 

    Please try it out and let me know.

    Simon

  • mdaniel's avatar
    mdaniel
    Day Hiker II

    Hello simon​ , the behavior is somewhat better in my case with your branch.

    But some of my export policies are seen by Ansible as needing to be updated. (but they are correct and not modified for a while)

    When I applied the playbook without check mode, I received the following error:

    Error: An NFS export rule with this client already exists in the current policy.

    If I delete the problematic export and create it for the first time, it works as expected, but on the second run, it fails.

    Matth

  • mdaniel's avatar
    mdaniel
    Day Hiker II

    Hello simon​

    Thank you for the answer.

    From the ansible point of view, I had the context value. The issue is still present.

    fatal: [localhost]: FAILED! => {
        "changed": false,
        "invocation": {
            "module_args": {
                "access": "root-squash",
                "account": null,
                "actions": null,
                "anongid": null,
                "anonuid": null,
                "api_token": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                "at": null,
                "atime": true,
                "before_rule": null,
                "change": null,
                "client": "10.0.1.0/24",
                "context": "myfbname",
                "default_retention": null,
                "desc": "",
                "destroy_snapshots": false,
                "disable_warnings": false,
                "effect": "allow",
                "enabled": true,
                "every": null,
                "fb_url": "fb_ipv4",
                "fileid_32bit": false,
                "filesystem": null,
                "force_delete": false,
                "full_control": null,
                "ignore_enforcement": true,
                "interfaces": null,
                "keep_for": null,
                "max_retention": null,
                "min_retention": null,
                "name": "test_nfs_export",
                "object_resources": null,
                "permission": "rw",
                "policy_type": "nfs",
                "principal": null,
                "read": null,
                "rename": null,
                "replica_link": null,
                "retention_lock": null,
                "rule": null,
                "s3_delimiters": null,
                "s3_prefixes": null,
                "secure": true,
                "security": [
                    "sys",
                    "krb5"
                ],
                "smb_encryption": "optional",
                "source_ips": null,
                "state": "present",
                "target": null,
                "target_rule": null,
                "timezone": null,
                "user": null
            }
        },
        "msg": "Failed to get NFS export policy rules for test_nfs_export. Error: Unexpected error."
    }

    The context seems to be correctly set.

    The usage of the function : 

    blade.get_nfs_export_policies_rules(
        policy_names=["test_nfs_export"],
        filter="client='" + '10.0.1.0/24' + "'",
        context_names=["myfbname"])
    {'errors': [{'context': None, 'message': 'Unexpected error.'}],
     'headers': None,
     'status_code': 500}

    I've implemented a very ugly patch as a temporary solution to my issue. I am not sure this is a good approach. 

    diff --git a/plugins/modules/purefb_policy.py b/plugins/modules/purefb_policy.py
    index edfcba8..67a4368 100644
    --- a/plugins/modules/purefb_policy.py
    +++ b/plugins/modules/purefb_policy.py
    @@ -2341,13 +2341,14 @@ def update_nfs_policy(module, blade):
                     policy_names=[module.params["name"]],
                     filter="client='" + module.params["client"] + "'",
                     context_names=[module.params["context"]],
    +                names=[module.params["name"]]
                 )
             else:
                 current_policy_rule = blade.get_nfs_export_policies_rules(
                     policy_names=[module.params["name"]],
                     filter="client='" + module.params["client"] + "'",
                 )
    -        if current_policy_rule.status_code != 200:
    +        if current_policy_rule.status_code != 200 and current_policy_rule.status_code != 400:
                 module.fail_json(
                     msg="Failed to get NFS export policy rules for {0}. Error: {1}".format(
                         module.params["name"],
    @@ -2355,8 +2356,9 @@ def update_nfs_policy(module, blade):
                     )
                 )
             elif (
    -            current_policy_rule.status_code == 200
    -            and current_policy_rule.total_item_count == 0
    +            (current_policy_rule.status_code == 200
    +            and current_policy_rule.total_item_count == 0)
    +            or (current_policy_rule.status_code == 400 and current_policy_rule.errors[0].message == "NFS export policy rule does not exist.")
             ):
                 rule = NfsExportPolicyRule(
                     client=module.params["client"],

    Thank you for your time.

    Best.

    Matth

  • Hi Matt

    I think I understand where the issue is coming from in the latest versions of Purity//FB.

    Can you try adding an additional parameter in the playbook when calling the purefb_policy module, to diagnose the issue.

    Add:

    context: <flashblade name>

    This should hopefully stop the error occuring.

    Please let me know the outcome, so I can do a more permamnent fix in the Collection

    Simon

    • mdaniel's avatar
      mdaniel
      Day Hiker II

      Hello Ludes​ 

      Thank you for taking the time to ask the Pure Storage team to investigate this issue.

      I see that simon​ released a new version of the ansible flashblade collection and I move forward with my problem.

      I have a more understandable error 😁

      "msg": "Failed to get NFS export policy rules for test_nfs_export. Error: Unexpected error."

      In the collection the function : get_nfs_export_policies_rules is used and it located in the python pypure-client

      I have isolate the code and reproduce the behavior

      import pypureclient
      from pypureclient import flashblade
      import platform
      
      VERSION = "1.5"
      USER_AGENT_BASE = "Ansible"
      API_AGENT_VERSION = "1.5"
      
      user_agent = "%(base)s %(class)s/%(version)s (%(platform)s)" % {
          "base": USER_AGENT_BASE,
          "class": __name__,
          "version": VERSION,
          "platform": platform.platform(),
      }
      
      try:
          blade = flashblade.Client('myFB.domain.com', api_token="TOKEN", user_agent=user_agent)
      except pypureclient.exceptions.PureError as e:
          print("Exception when logging in to the array: %s\n" % e)
      
      versions = list(blade.get_versions().items)
      print(versions)
      
      res = blade.get_nfs_export_policies_rules(
          policy_names=["test_nfs_export"],
          filter="client='" + '10.0.1.0/24' + "'")
      
      print(res)
      if type(res) == pypureclient.responses.ValidResponse:
          print(list(res.items))

      This return :

      {'errors': [{'context': None, 'message': 'Unexpected error.'}],
       'headers': None,
       'status_code': 500}

      The good news is that we have consistent behavior, and the problem is isolated to the filter when adding a new NFS policy member.

      Finally, I tried to use the FlashBlade API directly: 

      ➜ curl -X GET "https://myFB.domain.com/api/2.24/nfs-export-policies/rules?policy_names=test_nfs_export&filter=client%3D%2710.0.1.0%2F24%2 7" -H "x-auth-token: TOKEN"
      {"errors":[{"code":0,"message":"Unexpected error.","location_context":null}]}

      However, it works correctly with an already-defined subnet (also with an FQDN).

      Something has probably changed in the API in Purity//FB 4.6.9, and it needs to be fixed to ensure the API returns a status code different from 200.

      Could you please confirm whether this works in older versions of Purity//FB? I don't have access to an older FlashBlade to test.

      I appreciate your help and insights.

      Best regards.

  • Ludes's avatar
    Ludes
    Community Manager

    Thanks Matt - we'll have some folks look at it and respond here for you and the community.