Add helper function so that IAM policies can be compared for equality and update s3_bucket to take advantage of helper function

This commit is contained in:
Rob White 2016-12-22 23:22:40 +11:00 committed by Ryan S. Brown
parent e66501b0b7
commit 62dfa2ad11
3 changed files with 79 additions and 6 deletions

47
lib/ansible/module_utils/ec2.py Normal file → Executable file
View file

@ -327,7 +327,6 @@ def camel_dict_to_snake_dict(camel_dict):
return all_cap_re.sub(r'\1_\2', s1).lower()
def value_is_list(camel_list):
checked_list = []
@ -341,7 +340,6 @@ def camel_dict_to_snake_dict(camel_dict):
return checked_list
snake_dict = {}
for k, v in camel_dict.items():
if isinstance(v, dict):
@ -464,7 +462,6 @@ def get_ec2_security_group_ids_from_names(sec_group_list, ec2_connection, vpc_id
else:
return sg.name
def get_sg_id(sg, boto3):
if boto3:
@ -472,7 +469,6 @@ def get_ec2_security_group_ids_from_names(sec_group_list, ec2_connection, vpc_id
else:
return sg.id
sec_group_id_list = []
if isinstance(sec_group_list, string_types):
@ -514,3 +510,46 @@ def get_ec2_security_group_ids_from_names(sec_group_list, ec2_connection, vpc_id
return sec_group_id_list
def sort_json_policy_dict(policy_dict):
""" Sort any lists in an IAM JSON policy so that comparison of two policies with identical values but
different orders will return true
Args:
policy_dict (dict): Dict representing IAM JSON policy.
Basic Usage:
>>> my_iam_policy = {'Principle': {'AWS':["31","7","14","101"]}
>>> sort_json_policy_dict(my_iam_policy)
Returns:
Dict: Will return a copy of the policy as a Dict but any List will be sorted
{
'Principle': {
'AWS': [ '7', '14', '31', '101' ]
}
}
"""
def value_is_list(my_list):
checked_list = []
for item in my_list:
if isinstance(item, dict):
checked_list.append(sort_json_policy_dict(item))
elif isinstance(item, list):
checked_list.append(value_is_list(item))
else:
checked_list.append(item)
checked_list.sort()
return checked_list
ordered_policy_dict = {}
for key, value in policy_dict.items():
if isinstance(value, dict):
ordered_policy_dict[key] = sort_json_policy_dict(value)
elif isinstance(value, list):
ordered_policy_dict[key] = value_is_list(value)
else:
ordered_policy_dict[key] = value
return ordered_policy_dict

36
lib/ansible/modules/cloud/amazon/GUIDELINES.md Normal file → Executable file
View file

@ -233,6 +233,34 @@ result = connection.aws_call()
module.exit_json(changed=True, **camel_dict_to_snake_dict(result))
```
### Dealing with IAM JSON policy
If your module accepts IAM JSON policies then set the type to 'json' in the module spec. For example"
```python
argument_spec.update(
dict(
policy=dict(required=False, default=None, type='json'),
)
)
```
Note that AWS is unlikely to return the policy in the same order that is was submitted. Therefore, a helper
function has been created to order policies before comparison.
```python
# Get the policy from AWS
current_policy = aws_object.get_policy()
# Compare the user submitted policy to the current policy but sort them first
if sort_json_policy_dict(user_policy) == sort_json_policy_dict(current_policy):
# Nothing to do
pass
else:
# Update the policy
aws_object.set_policy(user_policy)
```
### Helper functions
Along with the connection functions in Ansible ec2.py module_utils, there are some other useful functions detailed below.
@ -261,4 +289,10 @@ Opposite of above. Converts an Ansible dict to a boto3 tag list of dicts.
Pass this function a list of security group names or combination of security group names and IDs and this function will
return a list of IDs. You should also pass the VPC ID if known because security group names are not necessarily unique
across VPCs.
across VPCs.
### sort_json_policy_dict
Pass any JSON policy dict to this function in order to sort any list contained therein. This is useful
because AWS rarely return lists in the same order that they were submitted so without this function, comparison
of identical policies returns false.

2
lib/ansible/modules/cloud/amazon/s3_bucket.py Normal file → Executable file
View file

@ -213,7 +213,7 @@ def _create_or_update_bucket(connection, module, location):
# only show changed if there was already a policy
changed = bool(current_policy)
elif current_policy != policy:
elif sort_json_policy_dict(current_policy) != sort_json_policy_dict(policy):
try:
bucket.set_policy(json.dumps(policy))
changed = True