Search code examples
amazon-web-servicesansibleansible-2.xrdsansible-facts

Ansible - Create RDS Instance from most recent existing snapshot


ansible 2.7.8

My goal is this:

Create a new RDS database, from the most recent existing snapshot of another database.

I found a similar question at (Ansible: Create new RDS DB from last snapshot of another DB) however that solution required creating a new snapshot. I would like to restore from the most recent already created snapshot.

So here is what I've done so far... The play used to gather the current snapshot info. I'm using the rds_snapshot_facts module (https://docs.ansible.com/ansible/latest/modules/rds_snapshot_facts_module.html)

  - name : get snap facts
    rds_snapshot_facts  :
      db_instance_identifier: "{{ source_db_name }}"
      region        : "{{ region }}"
      aws_access_key: "{{ access_key }}"
      aws_secret_key: "{{ secret_key }}"

It runs successfully, here is example data structure returned from the above play:

"snapshots": [
    {
        "allocated_storage": 500,
        "availability_zone": "us-east-1a",
        "db_instance_identifier": "pg-test-01",
        "db_snapshot_arn": "arn:aws:rds:us-east-1:111111111111111:snapshot:rds:pg-test-01-2019-03-01-06-22",
        "db_snapshot_identifier": "rds:pg-test-01-2019-03-01-06-22",
        "dbi_resource_id": "db-hidden",
        "encrypted": false,
        "engine": "postgres",
        "engine_version": "10.6",
        "iam_database_authentication_enabled": false,
        "instance_create_time": "2019-02-27T05:08:47.480000+00:00",
        "license_model": "postgresql-license",
        "master_username": "postgres",
        "option_group_name": "default:postgres-10",
        "percent_progress": 100,
        "port": 5432,
        "processor_features": [],
        "snapshot_create_time": "2019-03-01T06:22:58.771000+00:00",
        "snapshot_type": "automated",
        "status": "available",
        "storage_type": "gp2",
        "tags": {},
        "vpc_id": "vpc-hidden"
    },
    {
        "allocated_storage": 500,
        "availability_zone": "us-east-1a",
        "db_instance_identifier": "pg-test-01",
        "db_snapshot_arn": "arn:aws:rds:us-east-1:111111111111111:snapshot:rds:pg-test-01-2019-03-02-06-32",
        "db_snapshot_identifier": "rds:pg-test-01-2019-03-02-06-32",
        "dbi_resource_id": "db-hidden",
        "encrypted": false,
        "engine": "postgres",
        "engine_version": "10.6",
        "iam_database_authentication_enabled": false,
        "instance_create_time": "2019-02-27T05:08:47.480000+00:00",
        "license_model": "postgresql-license",
        "master_username": "postgres",
        "option_group_name": "default:postgres-10",
        "percent_progress": 100,
        "port": 5432,
        "processor_features": [],
        "snapshot_create_time": "2019-03-02T06:32:42.325000+00:00",
        "snapshot_type": "automated",
        "status": "available",
        "storage_type": "gp2",
        "tags": {},
        "vpc_id": "vpc-hidden"
    },
    {
        "allocated_storage": 500,
        "availability_zone": "us-east-1a",
        "db_instance_identifier": "pg-test-01",
        "db_snapshot_arn": "arn:aws:rds:us-east-1:111111111111111:snapshot:rds:pg-test-01-2019-03-03-06-33",
        "db_snapshot_identifier": "rds:pg-test-01-2019-03-03-06-33",
        "dbi_resource_id": "db-hidden",
        "encrypted": false,
        "engine": "postgres",
        "engine_version": "10.6",
        "iam_database_authentication_enabled": false,
        "instance_create_time": "2019-02-27T05:08:47.480000+00:00",
        "license_model": "postgresql-license",
        "master_username": "postgres",
        "option_group_name": "default:postgres-10",
        "percent_progress": 100,
        "port": 5432,
        "processor_features": [],
        "snapshot_create_time": "2019-03-03T06:33:06.463000+00:00",
        "snapshot_type": "automated",
        "status": "available",
        "storage_type": "gp2",
        "tags": {},
        "vpc_id": "vpc-hidden"
    },
    {
        "allocated_storage": 500,
        "availability_zone": "us-east-1a",
        "db_instance_identifier": "pg-test-01",
        "db_snapshot_arn": "arn:aws:rds:us-east-1:111111111111111:snapshot:rds:pg-test-01-2019-03-04-06-32",
        "db_snapshot_identifier": "rds:pg-test-01-2019-03-04-06-32",
        "dbi_resource_id": "db-hidden",
        "encrypted": false,
        "engine": "postgres",
        "engine_version": "10.6",
        "iam_database_authentication_enabled": false,
        "instance_create_time": "2019-02-27T05:08:47.480000+00:00",
        "license_model": "postgresql-license",
        "master_username": "postgres",
        "option_group_name": "default:postgres-10",
        "percent_progress": 100,
        "port": 5432,
        "processor_features": [],
        "snapshot_create_time": "2019-03-04T06:32:30.227000+00:00",
        "snapshot_type": "automated",
        "status": "available",
        "storage_type": "gp2",
        "tags": {},
        "vpc_id": "vpc-hidden"
    },
    {
        "allocated_storage": 500,
        "availability_zone": "us-east-1a",
        "db_instance_identifier": "pg-test-01",
        "db_snapshot_arn": "arn:aws:rds:us-east-1:111111111111111:snapshot:rds:pg-test-01-2019-03-05-06-32",
        "db_snapshot_identifier": "rds:pg-test-01-2019-03-05-06-32",
        "dbi_resource_id": "db-hidden",
        "encrypted": false,
        "engine": "postgres",
        "engine_version": "10.6",
        "iam_database_authentication_enabled": false,
        "instance_create_time": "2019-02-27T05:08:47.480000+00:00",
        "license_model": "postgresql-license",
        "master_username": "postgres",
        "option_group_name": "default:postgres-10",
        "percent_progress": 100,
        "port": 5432,
        "processor_features": [],
        "snapshot_create_time": "2019-03-05T06:32:57.880000+00:00",
        "snapshot_type": "automated",
        "status": "available",
        "storage_type": "gp2",
        "tags": {},
        "vpc_id": "vpc-hidden"
    },
    {
        "allocated_storage": 500,
        "availability_zone": "us-east-1a",
        "db_instance_identifier": "pg-test-01",
        "db_snapshot_arn": "arn:aws:rds:us-east-1:111111111111111:snapshot:snapshot-pg-test-01-2019-03-06-02-22",
        "db_snapshot_identifier": "snapshot-pg-test-01-2019-03-06-02-22",
        "dbi_resource_id": "db-hidden",
        "encrypted": false,
        "engine": "postgres",
        "engine_version": "10.6",
        "iam_database_authentication_enabled": false,
        "instance_create_time": "2019-02-27T05:08:47.480000+00:00",
        "license_model": "postgresql-license",
        "master_username": "postgres",
        "option_group_name": "default:postgres-10",
        "percent_progress": 100,
        "port": 5432,
        "processor_features": [],
        "snapshot_create_time": "2019-03-06T02:23:35.039000+00:00",
        "snapshot_type": "manual",
        "status": "available",
        "storage_type": "gp2",
        "tags": {},
        "vpc_id": "vpc-hidden"
    }
]

So with the above info, I would like to do some logic against it and create a new db.

I know how to create a db from a snapshot already:

  - name : Restore RDS from snapshot
    rds  :
      command           : restore
      instance_name     : "{{ new_db_name }}"
      snapshot          : "{{ snapshot_name }}"
      instance_type     : "db.t2.medium"
      subnet            : my_subnet_grp 
      wait              : yes
      wait_timeout      : 1600
      region             : "{{ region }}"
      aws_access_key: "{{ access_key }}"
      aws_secret_key: "{{ secret_key }}"

However, in my case I would like the variable "{{ snapshot_name }}" to be filled in dynamically from the facts collected.

Essentially the pseudo code logic would be something like:

db_snapshot_identifier where status=available and max(snapshot_create_time)

I'm really not sure where to even start constructing that logic for an Ansible operation, so any help or point in the right direction is welcomed - thanks!


Solution

  • Jinja2 is what you need.

    Use a selectattr filter to only select available snapshots.

    Then sort filter to order the results by snapshot_create_time

    Finally the last filter to pick the last result and use that in the rds module.

    There's lots of good information in the Jinja2 documentation

    - name : get snap facts
      rds_snapshot_facts  :
        db_instance_identifier: "{{ source_db_name }}"
        region        : "{{ region }}"
        aws_access_key: "{{ access_key }}"
        aws_secret_key: "{{ secret_key }}"
      register: snapshot_facts
    
    - name: get latest snapshot facts
      set_fact:
        latest_snapshot: '{{ snapshot_facts.snapshots | 
                            selectattr("status", "equalto", "available") |
                            sort(attribute="snapshot_create_time") |
                            last }}'
    
    - name : Restore RDS from snapshot
      rds  :
        command           : restore
        instance_name     : "{{ new_db_name }}"
        snapshot          : "{{ latest_snapshot.db_snapshot_identifier }}"
        instance_type     : "db.t2.medium"
        subnet            : my_subnet_grp 
        wait              : yes
        wait_timeout      : 1600
        region            : "{{ region }}"
        aws_access_key: "{{ access_key }}"
        aws_secret_key: "{{ secret_key }}"