Skip to content

Commit

Permalink
Bugfix aws_ec2 inventory use_ssm_inventory (#1957) (#1958)
Browse files Browse the repository at this point in the history
[PR #1957/05c262a4 backport][stable-6] Bugfix aws_ec2 inventory use_ssm_inventory

This is a backport of PR #1957 as merged into main (05c262a).
SUMMARY
Fix bug where aws_ec2 inventory plugin was failing with use_ssm_inventory: true if there are more than 40 inventories.
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME
aws_ec2
ADDITIONAL INFORMATION
Fixes #1713

Reviewed-by: Alina Buzachis
  • Loading branch information
patchback[bot] authored Feb 5, 2024
1 parent 839d813 commit a89460f
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 2 deletions.
3 changes: 3 additions & 0 deletions changelogs/fragments/20240129-aws_ec2-inventory-bugfix.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
bugfixes:
- plugins/inventory/aws_ec2 - Fix failure when retrieving information for more than 40 instances with use_ssm_inventory (https://github.com/ansible-collections/amazon.aws/issues/1713).
17 changes: 15 additions & 2 deletions plugins/inventory/aws_ec2.py
Original file line number Diff line number Diff line change
Expand Up @@ -649,8 +649,8 @@ def _query(self, regions, include_filters, exclude_filters, strict_permissions,
return {"aws_ec2": instances}

def _add_ssm_information(self, connection, instances):
filters = [{"Key": "AWS:InstanceInformation.InstanceId", "Values": [x["InstanceId"] for x in instances]}]
result = _get_ssm_information(connection, filters)
instance_ids = [x["InstanceId"] for x in instances]
result = self._get_multiple_ssm_inventories(connection, instance_ids)
for entity in result.get("Entities", []):
for x in instances:
if x["InstanceId"] == entity["Id"]:
Expand All @@ -659,6 +659,19 @@ def _add_ssm_information(self, connection, instances):
x["SsmInventory"] = content[0]
break

def _get_multiple_ssm_inventories(self, connection, instance_ids):
result = {}
# SSM inventory filters Values list can contain a maximum of 40 items so we need to retrieve 40 at a time
# https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_InventoryFilter.html
while len(instance_ids) > 40:
filters = [{"Key": "AWS:InstanceInformation.InstanceId", "Values": instance_ids[:40]}]
result.update(_get_ssm_information(connection, filters))
instance_ids = instance_ids[40:]
if instance_ids:
filters = [{"Key": "AWS:InstanceInformation.InstanceId", "Values": instance_ids}]
result.update(_get_ssm_information(connection, filters))
return result

def _populate(
self,
groups,
Expand Down
36 changes: 36 additions & 0 deletions tests/unit/plugins/inventory/test_aws_ec2.py
Original file line number Diff line number Diff line change
Expand Up @@ -649,3 +649,39 @@ def test_inventory__add_ssm_information(m_get_ssm_information, inventory):

filters = [{"Key": "AWS:InstanceInformation.InstanceId", "Values": [x["InstanceId"] for x in instances]}]
m_get_ssm_information.assert_called_once_with(connection, filters)


@patch("ansible_collections.amazon.aws.plugins.inventory.aws_ec2._get_ssm_information")
def test_inventory__get_multiple_ssm_inventories(m_get_ssm_information, inventory):
instances = [{"InstanceId": f"i-00{i}", "Name": f"instance {i}"} for i in range(41)]
result = {
"StatusCode": 200,
"Entities": [
{
"Id": f"i-00{i}",
"Data": {
"AWS:InstanceInformation": {
"Content": [{"os_type": "Linux", "os_name": "Fedora", "os_version": 37}]
}
},
}
for i in range(41)
],
}
m_get_ssm_information.return_value = result

connection = MagicMock()

expected = [
{
"InstanceId": f"i-00{i}",
"Name": f"instance {i}",
"SsmInventory": {"os_type": "Linux", "os_name": "Fedora", "os_version": 37},
}
for i in range(41)
]

inventory._add_ssm_information(connection, instances)
assert expected == instances

assert 2 == m_get_ssm_information.call_count

0 comments on commit a89460f

Please sign in to comment.