Repository: ansible-collections/amazon.aws

Issue:
ec2_instance enable hibernate option for instance_initiated_shutdown_behavior
### Summary

I am trying to launch new EC2 instances with the 'stop hibernate' option enabled, as per options available in AWS Console.
https://aws.amazon.com/about-aws/whats-new/2019/10/amazon-ec2-hibernation-now-available-on-windows/


### Issue Type

Feature Idea

### Component Name

ec2_instance

### Additional Information

<!--- Paste example playbooks or commands between quotes below -->
```yaml (paste below)
- name: start an instance with a hibernate_options
  amazon.aws.ec2_instance:
    name: "public-cpuoption-instance"
    vpc_subnet_id: subnet-5ca1ab1e
    tags:
      Environment: Testing
    instance_type: c4.large
    volumes:
    - device_name: /dev/sda1
      ebs:
        delete_on_termination: true
    cpu_options:
        core_count: 1
        threads_per_core: 1
    instance_initiated_shutdown_behavior: "stop_hibernate"
```


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:
Files identified in the description:
* [`plugins/doc_fragments/tags.py`](https://github.com/['ansible-collections/amazon.aws', 'ansible-collections/community.aws', 'ansible-collections/community.vmware']/blob/main/plugins/doc_fragments/tags.py)
* [`plugins/modules/ec2_instance.py`](https://github.com/['ansible-collections/amazon.aws', 'ansible-collections/community.aws', 'ansible-collections/community.vmware']/blob/main/plugins/modules/ec2_instance.py)
* [`test/`](https://github.com/['ansible-collections/amazon.aws', 'ansible-collections/community.aws', 'ansible-collections/community.vmware']/blob/main/test/)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @jillr @ryansb @s-hertel @tremble
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@RonneGisun Thank you for this feature idea. Would you be willing to work on this functionality and open a pull request?
> @RonneGisun Thank you for this feature idea. Would you be willing to work on this functionality and open a pull request?

@alinabuzachis Sorry, but I couldn't justify spending time on this right now. I'm a team of one, and have a long to do list.

Resolving patch:
diff --git a/plugins/modules/ec2_instance.py b/plugins/modules/ec2_instance.py
--- a/plugins/modules/ec2_instance.py
+++ b/plugins/modules/ec2_instance.py
@@ -244,6 +244,14 @@
       - Whether to enable termination protection.
       - This module will not terminate an instance with termination protection active, it must be turned off first.
     type: bool
+  hibernation_options:
+    description:
+      - Indicates whether an instance is enabled for hibernation.
+        Refer U(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/hibernating-prerequisites.html)
+        for Hibernation prerequisits.
+    type: bool
+    default: False
+    version_added: 5.0.0
   cpu_credit_specification:
     description:
       - For T series instances, choose whether to allow increased charges to buy CPU credits if the default pool is depleted.
@@ -1289,6 +1297,15 @@ def build_top_level_options(params):
         spec['InstanceInitiatedShutdownBehavior'] = params.get('instance_initiated_shutdown_behavior')
     if params.get('termination_protection') is not None:
         spec['DisableApiTermination'] = params.get('termination_protection')
+    if params.get('hibernation_options') and params.get('volumes'):
+        for vol in params['volumes']:
+            if vol.get('ebs') and vol['ebs'].get('encrypted'):
+                spec['HibernationOptions'] = {'Configured': True}
+            else:
+                module.fail_json(
+                    msg="Hibernation prerequisites not satisfied. Refer {0}".format(
+                        "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/hibernating-prerequisites.html")
+                )
     if params.get('cpu_options') is not None:
         spec['CpuOptions'] = {}
         spec['CpuOptions']['ThreadsPerCore'] = params.get('cpu_options').get('threads_per_core')
@@ -2020,6 +2037,7 @@ def main():
         placement_group=dict(type='str'),
         instance_initiated_shutdown_behavior=dict(type='str', choices=['stop', 'terminate']),
         termination_protection=dict(type='bool'),
+        hibernation_options=dict(type='bool', default=False),
         detailed_monitoring=dict(type='bool'),
         instance_ids=dict(default=[], type='list', elements='str'),
         network=dict(default=None, type='dict'),


Test patch:
diff --git a/tests/integration/targets/ec2_instance_hibernation_options/aliases b/tests/integration/targets/ec2_instance_hibernation_options/aliases
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/ec2_instance_hibernation_options/aliases
@@ -0,0 +1,3 @@
+cloud/aws
+ec2_instance_info
+ec2_instance
\ No newline at end of file
diff --git a/tests/integration/targets/ec2_instance_hibernation_options/defaults/main.yml b/tests/integration/targets/ec2_instance_hibernation_options/defaults/main.yml
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/ec2_instance_hibernation_options/defaults/main.yml
@@ -0,0 +1,4 @@
+---
+# defaults file for ec2_instance
+ec2_instance_type: 't3.micro'
+ec2_instance_tag_TestId: '{{ resource_prefix }}-instance-hibernation-options'
diff --git a/tests/integration/targets/ec2_instance_hibernation_options/meta/main.yml b/tests/integration/targets/ec2_instance_hibernation_options/meta/main.yml
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/ec2_instance_hibernation_options/meta/main.yml
@@ -0,0 +1,9 @@
+# this just makes sure they're in the right place
+dependencies:
+- role: setup_ec2_facts
+- role: setup_ec2_instance_env
+  vars:
+    ec2_instance_test_name: hibernation_options
+- role: setup_botocore_pip
+  vars:
+    boto3_version: "1.20.30"
diff --git a/tests/integration/targets/ec2_instance_hibernation_options/tasks/main.yml b/tests/integration/targets/ec2_instance_hibernation_options/tasks/main.yml
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/ec2_instance_hibernation_options/tasks/main.yml
@@ -0,0 +1,145 @@
+- module_defaults:
+    group/aws:
+      aws_access_key: "{{ aws_access_key }}"
+      aws_secret_key: "{{ aws_secret_key }}"
+      security_token: "{{ security_token | default(omit) }}"
+      region: "{{ aws_region }}"
+  block:
+    - name: Create instance with hibernation option (check mode)
+      ec2_instance:
+        name: "{{ resource_prefix }}-hibernation-options"
+        image_id: "{{ ec2_ami_id }}"
+        tags:
+          TestId: "{{ resource_prefix }}"
+        security_groups: "{{ sg.group_id }}"
+        vpc_subnet_id: "{{ testing_subnet_b.subnet.id }}"
+        hibernation_options: true
+        instance_type: "{{ ec2_instance_type }}"
+        volumes:
+          - device_name: /dev/sda1
+            ebs:
+              delete_on_termination: true
+              encrypted: true
+        state: running
+        wait: yes
+      check_mode: yes
+      register: create_instance_check_mode_results
+
+    - name: Check the returned value for the earlier task
+      assert:
+        that:
+          - create_instance_check_mode_results is changed
+          - create_instance_check_mode_results.spec.HibernationOptions.Configured == True
+
+    - name: Create instance with hibernation config
+      ec2_instance:
+        name: "{{ resource_prefix }}-hibernation-options"
+        image_id: "{{ ec2_ami_id }}"
+        tags:
+          TestId: "{{ resource_prefix }}"
+        security_groups: "{{ sg.group_id }}"
+        vpc_subnet_id: "{{ testing_subnet_b.subnet.id }}"
+        hibernation_options: true
+        instance_type: "{{ ec2_instance_type }}"
+        volumes:
+          - device_name: /dev/sda1
+            ebs:
+              delete_on_termination: true
+              encrypted: true
+        state: running
+        wait: yes
+      register: create_instance_results
+
+    - set_fact:
+        instance_id: '{{ create_instance_results.instances[0].instance_id }}'
+
+    - name: Check return values of the create instance task
+      assert:
+        that:
+          - "{{ create_instance_results.instances | length }} > 0"
+          - "'{{ create_instance_results.instances.0.state.name }}' == 'running'"
+          - "'{{ create_instance_results.spec.HibernationOptions.Configured }}'"
+
+    - name: Gather information about the instance to get the hibernation status
+      ec2_instance_info:
+        filters:
+          "tag:Name": "{{ resource_prefix }}-hibernation-options"
+      register: instance_hibernation_status
+
+    - name: Assert hibernation options is true
+      assert:
+        that:
+          - instance_hibernation_status.instances[0].hibernation_options.configured == true
+
+    - name: Create instance with hibernation option (check mode) (idempotent)
+      ec2_instance:
+        name: "{{ resource_prefix }}-hibernation-options"
+        image_id: "{{ ec2_ami_id }}"
+        tags:
+          TestId: "{{ resource_prefix }}"
+        security_groups: "{{ sg.group_id }}"
+        vpc_subnet_id: "{{ testing_subnet_b.subnet.id }}"
+        hibernation_options: true
+        instance_type: "{{ ec2_instance_type }}"
+        volumes:
+          - device_name: /dev/sda1
+            ebs:
+              delete_on_termination: true
+              encrypted: true
+        state: running
+        wait: yes
+      check_mode: yes
+      register: create_instance_check_mode_results
+
+    - name: Check the returned value for the earlier task
+      assert:
+        that:
+          - create_instance_check_mode_results is not changed
+
+    - name: Create instance with hibernation options configured (idempotent)
+      ec2_instance:
+        name: "{{ resource_prefix }}-hibernation-options"
+        image_id: "{{ ec2_ami_id }}"
+        tags:
+          TestId: "{{ resource_prefix }}"
+        security_groups: "{{ sg.group_id }}"
+        vpc_subnet_id: "{{ testing_subnet_b.subnet.id }}"
+        hibernation_options: true
+        instance_type: "{{ ec2_instance_type }}"
+        volumes:
+          - device_name: /dev/sda1
+            ebs:
+              delete_on_termination: true
+              encrypted: true
+        state: running
+        wait: yes
+      register: create_instance_results
+
+    - name: Check return values of the create instance task
+      assert:
+        that:
+          - "{{ not create_instance_results.changed }}"
+          - "{{ create_instance_results.instances | length }} > 0"
+
+    - name: Create instance with hibernation options configured with unencrypted volume
+      ec2_instance:
+        name: "{{ resource_prefix }}-hibernation-options-error"
+        image_id: "{{ ec2_ami_id }}"
+        tags:
+          TestId: "{{ resource_prefix }}"
+        security_groups: "{{ sg.group_id }}"
+        vpc_subnet_id: "{{ testing_subnet_b.subnet.id }}"
+        hibernation_options: true
+        instance_type: "{{ ec2_instance_type }}"
+        volumes:
+          - device_name: /dev/sda1
+            ebs:
+              delete_on_termination: true
+      register: create_instance_results
+      failed_when: "'Hibernation prerequisites not satisfied' not in create_instance_results.msg"
+
+    - name: Terminate the instance
+      ec2_instance:
+        filters:
+          tag:TestId: "{{ resource_prefix }}"
+        state: absent
\ No newline at end of file