About a month ago, I developed an Ansible role to manage OPSS application policies. By original design, my role uses two lists: application role names and principals and then assigned each role to each principal.

Something similar to:

- name: Grant application roles
  include_roles:
    role: opss-grant
  vars:
    app_name: soa-infra
    app_role:
      - SOAAdmin
      - SOADesigner
    principal:
      - weblogic
      - operator
Working code with lists

For a while, it worked just fine to the moment when I used my role this way:.

- name: Grant application roles
  include_roles:
    role: opss-grant
  vars:
    app_name: OAMAdmin
    app_role:
      - USMAdmin
      - USMViewer 
    principal: weblogic
Quite unexpected outcome. 

This code looks like as legit as the previous one, except the fact that Ansible/Python treats string "weblogic" as a list of characters so this time it produces operations: grant('OAMAdmin','USMAdmin','w'), grant('OAMAdmin','USMViewer','w') ... and so forth.

Well, not a big deal, just another bug in the code, there are two possible solutions:

  • The obvious one: Name it as a feature and document it as "Don't hold it this way™."
  • The desired one: Follow the Ansible way, which means that role should handle strings and lists equally.

Fortunately, Python is all about strings and lists so solution is very simple.The current version doesn't work with the parameters directly, instead it uses two internal arrays, initialized with the code similar to

# Role variables 
# opss-grant/vars/main.yml

role_list: "{{ [app_role] |flatten }}"
prcpl_list: "{{ [principal] |flatten }}"
internal list declaration

Now role always works with the list. In case if you pass the list, filter flatten converts it to the one level array.