Skip to content

Commit

Permalink
fix transform
Browse files Browse the repository at this point in the history
  • Loading branch information
tremble committed Sep 17, 2024
1 parent 5d5e151 commit 43d99b1
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 22 deletions.
Empty file.
32 changes: 26 additions & 6 deletions plugins/module_utils/_autoscaling/transformations.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,15 @@
from ..transformation import AnsibleAWSResourceList
from ..transformation import BotoResource
from ..transformation import BotoResourceList
from ..transformation import boto3_resource_list_to_ansible_dict
from ..transformation import boto3_resource_to_ansible_dict

# from ..transformation import boto3_resource_to_ansible_dict
# from ..transformation import boto3_resource_list_to_ansible_dict


def _inject_asg_name(
instance: BotoResource,
group_name: Optional[str] = None,
) -> BotoResource:
if not instance:
return instance
if not group_name:
return instance
if "AutoScalingGroupName" in instance:
Expand All @@ -28,13 +26,35 @@ def _inject_asg_name(
return instance


def normalize_autoscaling_instance(
instance: BotoResource,
group_name: Optional[str] = None,
):
"""Converts an AutoScaling Instance from the CamelCase boto3 format to the snake_case Ansible format.
Also handles inconsistencies in the output between describe_autoscaling_group() and describe_autoscaling_instances().
"""
if not instance:
return instance

# describe_autoscaling_group doesn't add AutoScalingGroupName
instance = _inject_asg_name(instance, group_name)

try:
# describe_autoscaling_group and describe_autoscaling_instances aren't consistent
instance["HealthStatus"] = instance["HealthStatus"].upper()
except KeyError:
pass

return boto3_resource_to_ansible_dict(instance, force_tags=False)


def normalize_autoscaling_instances(
autoscaling_instances: BotoResourceList,
group_name: Optional[str] = None,
) -> AnsibleAWSResourceList:
"""Converts a list of AutoScaling Instances from the CamelCase boto3 format to the snake_case Ansible format"""
if not autoscaling_instances:
return autoscaling_instances
autoscaling_instances = [_inject_asg_name(i) for i in autoscaling_instances]
autoscaling_instances = boto3_resource_list_to_ansible_dict(autoscaling_instances, force_tags=False)
autoscaling_instances = [normalize_autoscaling_instance(i, group_name) for i in autoscaling_instances]
return sorted(autoscaling_instances, key=lambda d: d.get("instance_id", None))
1 change: 1 addition & 0 deletions plugins/module_utils/autoscaling.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from ._autoscaling import instances as _instances
from ._autoscaling import transformations as _transformations
from ._autoscaling.common import AnsibleAutoScalingError # pylint: disable=unused-import
from ._autoscaling.common import AutoScalingErrorHandler # pylint: disable=unused-import


def get_autoscaling_groups(client, group_names=None):
Expand Down
6 changes: 5 additions & 1 deletion plugins/modules/autoscaling_instance_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,11 @@ def main():

client = module.client("autoscaling", retry_decorator=AWSRetry.jittered_backoff())

instances = get_autoscaling_instances(client, group_name=module.params["group_name"])
instances = get_autoscaling_instances(
client,
instance_ids=module.params["instance_ids"],
group_name=module.params["group_name"],
)

module.exit_json(changed=False, auto_scaling_instances=instances)

Expand Down
30 changes: 15 additions & 15 deletions tests/integration/targets/autoscaling_instance/tasks/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@
- "'launch_configuration_name' in instance_info.auto_scaling_instances[0]"
- "'lifecycle_state' in instance_info.auto_scaling_instances[0]"
- "'protected_from_scale_in' in instance_info.auto_scaling_instances[0]"
# - "'auto_scaling_group_name' in instance_info.auto_scaling_instances[1]"
- "'auto_scaling_group_name' in instance_info.auto_scaling_instances[1]"
- "'availability_zone' in instance_info.auto_scaling_instances[1]"
- "'health_status' in instance_info.auto_scaling_instances[1]"
- "'instance_id' in instance_info.auto_scaling_instances[1]"
- "'instance_type' in instance_info.auto_scaling_instances[1]"
- "'launch_configuration_name' in instance_info.auto_scaling_instances[1]"
- "'lifecycle_state' in instance_info.auto_scaling_instances[1]"
- "'protected_from_scale_in' in instance_info.auto_scaling_instances[1]"
# - specific_instance_info.auto_scaling_group_name == default_resource_name
- specific_instance_info.auto_scaling_group_name == default_resource_name
- specific_instance_info.health_status == "HEALTHY"
- specific_instance_info.instance_id == initial_instances[0]
- specific_instance_info.instance_type == "t3.micro"
Expand Down Expand Up @@ -142,7 +142,7 @@
# - no change should happen
- name: instance_ids - idempotency/all - no purge - check_mode
amazon.aws.autoscaling_instance:
instance_ids: "{{ listed_instance_ids }}"
instance_ids: "{{ initial_instances }}"
group_name: "{{ default_resource_name }}"
state: present
purge_instances: False
Expand All @@ -152,7 +152,7 @@

- name: instance_ids - idempotency/all - no purge
amazon.aws.autoscaling_instance:
instance_ids: "{{ listed_instance_ids }}"
instance_ids: "{{ initial_instances }}"
group_name: "{{ default_resource_name }}"
state: present
purge_instances: False
Expand All @@ -163,7 +163,7 @@
# - no change should happen
- name: instance_ids - idempotency/partial - no purge - check_mode
amazon.aws.autoscaling_instance:
instance_ids: "{{ listed_instance_ids[0] }}"
instance_ids: "{{ initial_instances[0] }}"
group_name: "{{ default_resource_name }}"
state: present
purge_instances: False
Expand All @@ -173,7 +173,7 @@

- name: instance_ids - idempotency/partial - no purge
amazon.aws.autoscaling_instance:
instance_ids: "{{ listed_instance_ids[0] }}"
instance_ids: "{{ initial_instances[0] }}"
group_name: "{{ default_resource_name }}"
state: present
purge_instances: False
Expand All @@ -184,7 +184,7 @@
# - no change should happen as there are no instances that are attached but not requested
- name: instance_ids - idempotency/all - purge - check_mode
amazon.aws.autoscaling_instance:
instance_ids: "{{ listed_instance_ids }}"
instance_ids: "{{ initial_instances }}"
group_name: "{{ default_resource_name }}"
purge_instances: True
state: present
Expand All @@ -194,7 +194,7 @@

- name: instance_ids - idempotency/all - purge
amazon.aws.autoscaling_instance:
instance_ids: "{{ listed_instance_ids }}"
instance_ids: "{{ initial_instances }}"
group_name: "{{ default_resource_name }}"
purge_instances: True
state: present
Expand All @@ -205,7 +205,7 @@
# Detach a specific instance
- name: instance_ids - single instance - detach - check_mode
amazon.aws.autoscaling_instance:
instance_ids: "{{ listed_instance_ids[0] }}"
instance_ids: "{{ initial_instances[0] }}"
group_name: "{{ default_resource_name }}"
state: detached
diff: True
Expand All @@ -214,7 +214,7 @@

- name: instance_ids - single instance - detach
amazon.aws.autoscaling_instance:
instance_ids: "{{ listed_instance_ids[0] }}"
instance_ids: "{{ initial_instances[0] }}"
group_name: "{{ default_resource_name }}"
state: detached
diff: True
Expand All @@ -223,7 +223,7 @@
# Ensure present state (not using standby - should be the same as attached)
- name: instance_ids - single instance - attach/present - check_mode
amazon.aws.autoscaling_instance:
instance_ids: "{{ listed_instance_ids[0] }}"
instance_ids: "{{ initial_instances[0] }}"
group_name: "{{ default_resource_name }}"
state: present
diff: True
Expand All @@ -232,7 +232,7 @@

- name: instance_ids - single instance - attach/present
amazon.aws.autoscaling_instance:
instance_ids: "{{ listed_instance_ids[0] }}"
instance_ids: "{{ initial_instances[0] }}"
group_name: "{{ default_resource_name }}"
state: present
diff: True
Expand All @@ -241,7 +241,7 @@
# Detach it again so we can reattach
- name: instance_ids - single instance - detach (again - prepare to attach)
amazon.aws.autoscaling_instance:
instance_ids: "{{ listed_instance_ids[0] }}"
instance_ids: "{{ initial_instances[0] }}"
group_name: "{{ default_resource_name }}"
state: detached
diff: True
Expand All @@ -250,7 +250,7 @@
# Ensure attached state (not using standby - should be the same as attached)
- name: instance_ids - single instance - attach/attach - check_mode
amazon.aws.autoscaling_instance:
instance_ids: "{{ listed_instance_ids[0] }}"
instance_ids: "{{ initial_instances[0] }}"
group_name: "{{ default_resource_name }}"
state: attached
diff: True
Expand All @@ -259,7 +259,7 @@

- name: instance_ids - single instance - attach/attach
amazon.aws.autoscaling_instance:
instance_ids: "{{ listed_instance_ids[0] }}"
instance_ids: "{{ initial_instances[0] }}"
group_name: "{{ default_resource_name }}"
state: attached
diff: True
Expand Down
131 changes: 131 additions & 0 deletions tests/unit/module_utils/autoscaling/test_autoscaling_error_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# -*- 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)

try:
import botocore
except ImportError:
pass

import pytest

from ansible_collections.amazon.aws.plugins.module_utils.autoscaling import AnsibleAutoScalingError
from ansible_collections.amazon.aws.plugins.module_utils.autoscaling import AutoScalingErrorHandler
from ansible_collections.amazon.aws.plugins.module_utils.botocore import HAS_BOTO3

if not HAS_BOTO3:
pytestmark = pytest.mark.skip("test_iam_error_handler.py requires the python modules 'boto3' and 'botocore'")


class TestAutoScalingDeletionHandler:
def test_no_failures(self):
self.counter = 0

@AutoScalingErrorHandler.deletion_error_handler("no error")
def no_failures():
self.counter += 1

no_failures()
assert self.counter == 1

def test_client_error(self):
self.counter = 0
err_response = {"Error": {"Code": "MalformedPolicyDocument"}}

@AutoScalingErrorHandler.deletion_error_handler("do something")
def raise_client_error():
self.counter += 1
raise botocore.exceptions.ClientError(err_response, "Something bad")

with pytest.raises(AnsibleAutoScalingError) as e_info:
raise_client_error()
assert self.counter == 1
raised = e_info.value
assert isinstance(raised.exception, botocore.exceptions.ClientError)
assert "do something" in raised.message
assert "Something bad" in str(raised.exception)

def test_ignore_error(self):
self.counter = 0
err_response = {"Error": {"Code": "NoSuchEntity"}}

@AutoScalingErrorHandler.deletion_error_handler("do something")
def raise_client_error():
self.counter += 1
raise botocore.exceptions.ClientError(err_response, "I couldn't find it")

ret_val = raise_client_error()
assert self.counter == 1
assert ret_val is False


class TestIamListHandler:
def test_no_failures(self):
self.counter = 0

@AutoScalingErrorHandler.list_error_handler("no error")
def no_failures():
self.counter += 1

no_failures()
assert self.counter == 1

def test_client_error(self):
self.counter = 0
err_response = {"Error": {"Code": "MalformedPolicyDocument"}}

@AutoScalingErrorHandler.list_error_handler("do something")
def raise_client_error():
self.counter += 1
raise botocore.exceptions.ClientError(err_response, "Something bad")

with pytest.raises(AnsibleAutoScalingError) as e_info:
raise_client_error()
assert self.counter == 1
raised = e_info.value
assert isinstance(raised.exception, botocore.exceptions.ClientError)
assert "do something" in raised.message
assert "Something bad" in str(raised.exception)

def test_list_error(self):
self.counter = 0
err_response = {"Error": {"Code": "NoSuchEntity"}}

@AutoScalingErrorHandler.list_error_handler("do something")
def raise_client_error():
self.counter += 1
raise botocore.exceptions.ClientError(err_response, "I couldn't find it")

ret_val = raise_client_error()
assert self.counter == 1
assert ret_val is None


class TestIamCommonHandler:
def test_no_failures(self):
self.counter = 0

@AutoScalingErrorHandler.common_error_handler("no error")
def no_failures():
self.counter += 1

no_failures()
assert self.counter == 1

def test_client_error(self):
self.counter = 0
err_response = {"Error": {"Code": "MalformedPolicyDocument"}}

@AutoScalingErrorHandler.common_error_handler("do something")
def raise_client_error():
self.counter += 1
raise botocore.exceptions.ClientError(err_response, "Something bad")

with pytest.raises(AnsibleAutoScalingError) as e_info:
raise_client_error()
assert self.counter == 1
raised = e_info.value
assert isinstance(raised.exception, botocore.exceptions.ClientError)
assert "do something" in raised.message
assert "Something bad" in str(raised.exception)
Loading

0 comments on commit 43d99b1

Please sign in to comment.