Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ssm_inventory_info module #1745

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions meta/runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ action_groups:
- sns_topic
- sns_topic_info
- sqs_queue
- ssm_inventory_info
- ssm_parameter
- stepfunctions_state_machine
- stepfunctions_state_machine_execution
Expand Down
120 changes: 120 additions & 0 deletions plugins/modules/ssm_inventory_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright: Contributors to the Ansible project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

DOCUMENTATION = """
module: ssm_inventory_info
version_added: 6.0.0
short_description: Get SSM inventory information for EC2 instance

description:
- Gather SSM inventory for EC2 instance configured with SSM.

author: 'Aubin Bikouo (@abikouo)'

options:
instance_id:
description:
- EC2 instance id.
required: true
type: str

extends_documentation_fragment:
- amazon.aws.common.modules
- amazon.aws.region.modules
- amazon.aws.boto3
"""

EXAMPLES = """
- name: Retrieve SSM inventory info for instance id 'i-012345678902'
community.aws.ssm_inventory_info:
instance_id: 'i-012345678902'
"""


RETURN = """
ssm_inventory:
returned: on success
description: >
SSM inventory information.
type: dict
sample: {
'agent_type': 'amazon-ssm-agent',
'agent_version': '3.2.582.0',
'computer_name': 'ip-172-31-44-166.ec2.internal',
'instance_id': 'i-039eb9b1f55934ab6',
'instance_status': 'Active',
'ip_address': '172.31.44.166',
'platform_name': 'Fedora Linux',
'platform_type': 'Linux',
'platform_version': '37',
'resource_type': 'EC2Instance'
}
"""


try:
import botocore
except ImportError:
pass # Handled by AnsibleAWSModule

from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict

from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule


class SsmInventoryInfoFailure(Exception):
def __init__(self, exc, msg):
self.exc = exc
self.msg = msg
super().__init__(self)


def get_ssm_inventory(connection, filters):
try:
return connection.get_inventory(Filters=filters)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
raise SsmInventoryInfoFailure(exc=e, msg="get_ssm_inventory() failed.")


def execute_module(module, connection):

instance_id = module.params.get("instance_id")
try:
filters = [
{
"Key": "AWS:InstanceInformation.InstanceId",
"Values": [instance_id]
}
]

response = get_ssm_inventory(connection, filters)
entities = response.get("Entities", [])
ssm_inventory = {}
if entities:
content = entities[0].get("Data", {}).get("AWS:InstanceInformation", {}).get("Content", [])
if content:
ssm_inventory = camel_dict_to_snake_dict(content[0])
module.exit_json(changed=False, ssm_inventory=ssm_inventory)
except SsmInventoryInfoFailure as e:
module.fail_json_aws(exception=e.exc, msg=e.msg)


def main():
argument_spec = dict(
instance_id=dict(required=True, type="str"),
)

module = AnsibleAWSModule(
argument_spec=argument_spec,
supports_check_mode=True,
)

connection = module.client("ssm")
execute_module(module, connection)


if __name__ == "__main__":
main()
145 changes: 145 additions & 0 deletions tests/unit/plugins/modules/test_ssm_inventory_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# -*- coding: utf-8 -*-

# Copyright: Contributors to the Ansible project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

import pytest
from botocore.exceptions import BotoCoreError

from unittest.mock import MagicMock, patch
from ansible_collections.community.aws.plugins.modules.ssm_inventory_info import (
execute_module,
get_ssm_inventory,
SsmInventoryInfoFailure,
)


def test_get_ssm_inventory():
connection = MagicMock()
inventory_response = MagicMock()
connection.get_inventory.return_value = inventory_response
filters = MagicMock()

assert get_ssm_inventory(connection, filters) == inventory_response
connection.get_inventory.assert_called_once_with(
Filters=filters
)


def test_get_ssm_inventory_failure():
connection = MagicMock()
connection.get_inventory.side_effect = BotoCoreError(error="failed", operation="get_ssm_inventory")
filters = MagicMock()

with pytest.raises(SsmInventoryInfoFailure):
get_ssm_inventory(connection, filters)


@patch('ansible_collections.community.aws.plugins.modules.ssm_inventory_info.get_ssm_inventory')
def test_execute_module(m_get_ssm_inventory):

instance_id = "i-0202020202020202"
aws_inventory = {
'AgentType': 'amazon-ssm-agent',
'AgentVersion': '3.2.582.0',
'ComputerName': 'ip-172-31-44-166.ec2.internal',
'InstanceId': 'i-039eb9b1f55934ab6',
'InstanceStatus': 'Active',
'IpAddress': '172.31.44.166',
'PlatformName': 'Fedora Linux',
'PlatformType': 'Linux',
'PlatformVersion': '37',
'ResourceType': 'EC2Instance'
}

ansible_inventory = {
'agent_type': 'amazon-ssm-agent',
'agent_version': '3.2.582.0',
'computer_name': 'ip-172-31-44-166.ec2.internal',
'instance_id': 'i-039eb9b1f55934ab6',
'instance_status': 'Active',
'ip_address': '172.31.44.166',
'platform_name': 'Fedora Linux',
'platform_type': 'Linux',
'platform_version': '37',
'resource_type': 'EC2Instance'
}

m_get_ssm_inventory.return_value = {
"Entities": [
{
'Id': instance_id,
"Data": {
"AWS:InstanceInformation": {"Content": [aws_inventory]}
}
}
],
"Status": 200
}

connection = MagicMock()
module = MagicMock()
module.params = dict(
instance_id=instance_id
)
module.exit_json.side_effect = SystemExit(1)
module.fail_json_aws.side_effect = SystemError(2)

with pytest.raises(SystemExit):
execute_module(module, connection)

module.exit_json.assert_called_once_with(
changed=False, ssm_inventory=ansible_inventory
)


@patch('ansible_collections.community.aws.plugins.modules.ssm_inventory_info.get_ssm_inventory')
def test_execute_module_no_data(m_get_ssm_inventory):

instance_id = "i-0202020202020202"

m_get_ssm_inventory.return_value = {
"Entities": [
{
'Id': instance_id,
"Data": {}
}
],
}

connection = MagicMock()
module = MagicMock()
module.params = dict(
instance_id=instance_id
)
module.exit_json.side_effect = SystemExit(1)
module.fail_json_aws.side_effect = SystemError(2)

with pytest.raises(SystemExit):
execute_module(module, connection)

module.exit_json.assert_called_once_with(
changed=False, ssm_inventory={}
)


@patch('ansible_collections.community.aws.plugins.modules.ssm_inventory_info.get_ssm_inventory')
def test_execute_module_failure(m_get_ssm_inventory):

instance_id = "i-0202020202020202"

m_get_ssm_inventory.side_effect = SsmInventoryInfoFailure(
exc=BotoCoreError(error="failed", operation="get_ssm_inventory"),
msg="get_ssm_inventory() failed."
)

connection = MagicMock()
module = MagicMock()
module.params = dict(
instance_id=instance_id
)
module.exit_json.side_effect = SystemExit(1)
module.fail_json_aws.side_effect = SystemError(2)

with pytest.raises(SystemError):
execute_module(module, connection)