# Leveraging Ansible to automate AWS instance management

[Ansible](https://www.ansible.com/) is an open-source software automation tool suited for instance configuration and provisioning, enabling an Infrastructure as Code approach to the Cloud.\
In this page we provide a set of [ansible-playbooks](https://docs.ansible.com/ansible/latest/user_guide/playbooks.html) templates to perform the most common task to tune EC2 instance types with Akamas, such as:

* EC2 instance creation
* EC2 instance termination
* EC2 instance resizing

Refer to the [Ansible documentation](https://docs.ansible.com/) and to the [Ansible ec2 module](https://docs.ansible.com/ansible/latest/modules/ec2_module.html) for more details, and make sure to check the concepts behind [inventory management](https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html) to build a robust automation.

The orchestrator requires access to an account or role linked to the correct policies; this requires managing [AWS Policies](/akamas-docs/3.6/knowledge-base/guidelines-for-optimizing-aws-ec2-instances.md#aws-policies) and having access to the required security groups.

### Instance Creation <a href="#instance-creation" id="instance-creation"></a>

The following example playbook provisions an EC2 instance using the latest *Ubuntu 18-04 LTS* image and then waits for it to be available.\
The playbook requires the following set of arguments:

* **key**: the name of the SSH key pair to use
* **Name**: the instance name
* **security\_group**: the name of the AWS security group
* **region**: the selected AWS region

You can update the `ec2_ami_info` task to query for a different [AMI](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) family or specify directly the id under `ec2.image`.

When executing the script we must assign the following arguments as [extra-vars](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#passing-variables-on-the-command-line):

* **intance\_type**: type of instance to provision
* **volume\_size**: the size of the attached volume

```yaml
# Launch an ubuntu instance and wait for ssh

- name: Create an instance request
  hosts: localhost
  gather_facts: False

  tasks:
    - name: query api
      ec2_ami_info:
        filters:
          name: "ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*"
          owner-id: "099720109477"  # Canonical Group Limited
      register: amis
    - name: sort by creation date
      set_fact:
        sorted_amis: "{{ amis.images | sort(attribute='creation_date') }}"
    - name: get latest
      set_fact:
        latest_ami: "{{ sorted_amis | last }}"

    - name: Launch instance
      ec2:
         key_name: "{{ key }}"
         instance_type: "{{ instance_type | default('m5.xlarge') }}"
         group:
          - <your-security-groups>
         image: "{{ latest_ami.image_id }}"
         count: "{{ count | default('1') }}"
         wait: yes
         wait_timeout: 500
         region: "{{ region }}"
         spot_wait_timeout: 600
         instance_initiated_shutdown_behavior: terminate
         ebs_optimized: yes
         volumes:
           - device_name: /dev/sda1
             volume_type: gp2
             volume_size: "{{ volume_size | default('20') }}"
             delete_on_termination: yes
         instance_tags:
           Name: "{{ Name }}"
           CNAME: "{{ Name }}.<your-domain>"
      register: ec2

    - name: Wait for SSH to come up
      wait_for:
        host: "{{ item.public_dns_name }}"
        port: 22
        delay: 60
        timeout: 320
        state: started
      with_items: "{{ ec2.instances }}"
```

To apply the EC2 parameters from the [AWS Optimization Pack](/akamas-docs/3.6/reference/optimization-packs/aws-pack.md) selected by the Akamas engine you can generate the playbook arguments through a template like the following one, where `ec2` is the name of the component:

```bash
ansible-playbook -i inventory --extra-vars "instance_type=${ec2.aws_ec2_instance_type}.${ec2.aws_ec2_instance_size}" provision.yaml
```

### Instance Termination <a href="#instance-termination" id="instance-termination"></a>

The following playbook terminates all instances with the specified name (or any other tag).\
It requires the following arguments:

* **instance\_name**: the name of the instance
* **region**: the selected AWS region

```yaml
# Terminate an aws instance

- name: Terminate instance
  hosts: localhost
  gather_facts: False
  tasks:
  - name: retrieve instance info
    ec2_instance_info:
      filters:
        "tag:Name": "{{ instance_name }}"
    register: ec2

  - name: terminate the instance
    ec2:
      state: absent
      instance_ids:
        - "{{ item.instance_id }}"
      region: "{{ region }}"
    with_items: "{{ ec2.instances }}"
```

### Instance Resizing <a href="#instance-resizing" id="instance-resizing"></a>

Instance resizing is a little trickier to deploy as it requires you to [install AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) and setup the [required credentials](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html).\
The following playbook provides a simple way to stop, update, and restart your instance: it is intended as a building block for more elaborate workflows.

It makes use of a list of arguments:

* **instance\_name**: your instance name
* **region**: the selected AWS region

For a successful workflow, it requires:

* The instance to exist
* The instance to be unique

```yaml
# Change instance type, requires AWS CLI

- name: Resize the instance
  hosts: localhost
  gather_facts: no
  connection: local
  tasks:
  - name: save instance info
    ec2_instance_info:
      filters:
        "tag:Name": "{{ instance_name }}"
    register: ec2
  - name: stop the instance
    ec2:
      region: "{{ region | default('us-east-2') }}"
      state: stopped
      instance_ids:
        - "{{ ec2.instances[0].instance_id }}"
      instance_type: "{{ ec2.instances[0].instance_type }}"
      wait: True
  - name: Change the instances ec2 type
    shell: >
       aws ec2 modify-instance-attribute --instance-id "{{ ec2.instances[0].instance_id }}"
       --instance-type "{{ new_instance_type }}"
    delegate_to: localhost
  - name: restart the instance
    ec2:
      region: "{{ region }}"
      state: running
      instance_ids:
        - "{{ ec2.instances[0].instance_id }}"
      wait: True
    register: ec2
  - name: wait for SSH to come up
    wait_for:
      host: "{{ item.public_dns_name }}"
      port: 22
      delay: 60
      timeout: 500
      state: started
    with_items: "{{ ec2.instances }}"
```

To apply the EC2 parameters from the [AWS Optimization Pack](/akamas-docs/3.6/reference/optimization-packs/aws-pack.md) selected by the Akamas engine you can generate the playbook arguments through a template like the following, where `ec2` is the name of the component:

```bash
ansible-playbook -i inventory --extra-vars "new_instance_type=${ec2.aws_ec2_instance_type}.${ec2.aws_ec2_instance_size}" resize.yaml
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.akamas.io/akamas-docs/3.6/knowledge-base/leveraging-ansible-to-automate-aws-instance-management.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
