Why and how I use Amazon Step Functions

# Why I use Amazon Step Functions Service
We have weekly releasing by using Jenkins, but we don't want to schedule RDS instance restoring and take snapshots by building server. So I decided to use Amazon Lambda do those tasks. 

And the reason post is because I am looking forward more better way to do this task, if you have any idea please kindly share with me.

### Prepare Jobs
- You already tired to operate RDS console manually each week?
- You never wrote any Python Code just like me?
- Not familiar with Amazon Cloud Watch like me?
- Not familiar with Amazon Step Function like me?
- Not familiar with Amazon Lambda like me?
- Only have 16 hours to finish this task like me?
- Two different security group already been created.
- Two RDS instance of any database; In this example I am using mySQL.
- You already know how to create IAM role.
- You know how RDS instance status and snapshot works.

### Serval Amazon Services will be used
- Amazon RDS
- Amazon Lambda
- Amazon Step Functions
- Amazon Cloud Watch

### Roadmap
At the beginning of story always be simple and easy...like this
![simple_lambda_architecture-2.png](https://qiita-image-store.s3.amazonaws.com/0/174850/bcaa6828-6d19-7ead-456d-8283f596b1dc.png)


### Environment of RDS instance
- Dev RDS instance named **DEV** with **SGA(security group A)**
- Staging RDS instance named **STAGING** **SGB(security group B)**

### Work Flow that I want to do
1. Take Dev's snapshot.
2. Delete Staging's instance with final snapshot.
3. Restore Dev's snapshot that we just took and rename it to Staging's instance name and setting preferences for it.
4. Replace SGA by modifying Staging's instance.

# Let's Start!
First let's write a super easy Python on Amazon Lambda!!

### Create IAM Role
Let's create a new IAM role only for your Lambda function use. If you need more help with creating IAM role, please see this in [Japanese version](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/intro-permission-model.html#lambda-intro-execution-role) or [English version](http://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html)

The role I created here is just for demonstration, you do not necessary to attach full access like me. You should try those access rules and find out more accurately accessing rules.
<img width="1058" alt="スクリーンショット 2017-04-08 18.29.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/174850/d1e5e77d-b3b9-2286-da7c-8e2d69794389.png">

And this is my Trust Relationship settings.

```json:TrustRelationship.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

### Create Lambda
After created a lambda function by using services panel. There're few steps introductions will lead you finish your function.

#### Select Blueprint
Select Python 2.7 and type "hello" in the text filter, we are going to use **hello-world-python** to write it.
<img width="916" alt="スクリーンショット 2017-04-08 18.51.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/174850/fa244f79-8dbe-c01a-47ba-32eae1e47eec.png">

#### Configure Triggers
We want to organize those lambda functions by using Amazon Step Function, therefore we just pass this trigger for now.
Click **Next**!
<img width="937" alt="スクリーンショット 2017-04-08 18.56.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/174850/0424fecd-ba9c-9b52-b58f-e66c4b22cdb6.png">

#### Configure Function
Let name your function in this step, make sure the **Runtime** should be **Python 2.7**
<img width="962" alt="スクリーンショット 2017-04-08 18.59.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/174850/e2199bd7-11d9-55c0-d193-d32259cf3b05.png">

#### Lambda Function Code
It's really a very tiny code to use [Python 2.7](https://docs.python.org/2/#) and [Boto3 ver.1.4.4](http://boto3.readthedocs.io/en/latest/reference/services/rds.html), so let's use **Edit code inline** here.
<img width="924" alt="スクリーンショット 2017-04-08 19.07.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/174850/e347eb08-9f60-225a-8999-72746f62024d.png">

```py:dev-snapshot.py
import boto3
from botocore.client import ClientError
from datetime import datetime, timedelta, tzinfo

rds = boto3.client('rds')

# db_source_instance is a varible that your insance name
db_source_instance='dev'

# dev_snapshot_prefix is the snapshot name after execute this function
dev_snapshot_prefix = "dev-to-staging-snapshot"

# You can skip this class if you don't need convert to your timezone
class TWST(tzinfo):
    def utcoffset(self, dt):
        return timedelta(hours=8)
    def dst(self, dt):
        return timedelta(0)
    def tzname(self, dt):
        return 'JST'

# Lambda function entry
def lambda_handler(event, context):
    # Before we take snapshot for DEV, I prefer to delete the snapshots that I took in the same day.
    delete_snapshots(dev_snapshot_prefix)
    create_dev_snapshot(dev_snapshot_prefix, db_source_instance)

# Delete snapshots
def delete_snapshots(prefix):
    print '[delete_snapshots] Start'
    snapshots = rds.describe_db_snapshots()

    for snapshot in snapshots['DBSnapshots']:
        if snapshot['DBSnapshotIdentifier'].startswith(prefix):
            rds.delete_db_snapshot(DBSnapshotIdentifier=snapshot['DBSnapshotIdentifier'])

    print '[delete_snapshots] End'

# Create snapshot for DEV
def create_dev_snapshot(prefix, instanceid):
    print '[create_dev_snapshot] Start'
    snapshotid = "-".join([prefix, datetime.now(tz=TWST()).strftime("%Y-%m-%d")])

    for i in range(0, 5):
        try:
            snapshot = rds.create_db_snapshot(
                DBSnapshotIdentifier=snapshotid,
                DBInstanceIdentifier=instanceid
            )
            return
        except ClientError as e:
                print(str(e))
        time.sleep(1)

    print '[create_dev_snapshot] End'
```

#### Lambda Function Handler and Role
Keep the Handler and Role, select the IAM role you just created by your own, it will appear the name you gave it.
<img width="946" alt="スクリーンショット 2017-04-08 19.28.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/174850/ad98dfb7-ca2f-2aca-ccb8-d12cec1c10ba.png">

#### Advanced Settings
There are serval things that I hit this time.

At begin I wanted all those tasks in single one lambda function, then I realized waiting time like **snapshot creating** or **restoring instance** cause me timeout problem.

I tried to increase **Timeout limit** in Advanced Settings, but I can only increase it until 5 mins only. That's also make sense to me, because AWS Lambda charge service fee by request times, execution time and memory size.

>時間
時間はコードの実行が開始された瞬間からコードが返されるか中止されるまでで計算され、>100 ミリ秒単位で切り上げられます。料金は関数に割り当てたメモリ量により異なります。1 >GB-秒の使用につき 0.00001667 USD の料金が発生します。

You can see more [detail](https://aws.amazon.com/jp/lambda/pricing/) if you like.

Therefore I separated my function to several functions and using default advanced settings only. Again **Timeout** and **Memory** is depends on how much resources that your function need.
<img width="953" alt="スクリーンショット 2017-04-08 19.31.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/174850/c88ebe57-cd12-eba5-80b4-9417f7171c0f.png">


#### Test Your Lambda Function
After you click **Next** and **Create Function**, you will see this testing page.
<img width="1071" alt="スクリーンショット 2017-04-08 19.45.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/174850/e286cecb-a794-4f37-277f-9133c113870b.png">

Go test it and see does it works fine.
After you click the Test button, it will show a **Input test event** and wait your response for **Sample event template**.
Type "event" in that text filter like this.
<img width="978" alt="スクリーンショット 2017-04-08 19.47.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/174850/eeb61997-1462-8108-d444-4397a6106bcd.png">

When you select this template, you can see that content
<img width="884" alt="スクリーンショット 2017-04-08 19.48.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/174850/44e6bf56-ac4c-75c6-08ed-96e4e09511da.png">

Click **Save and test**
You should use those **Execution result**, **Summary** and **Log output** to fix your function until it's perfect to you!

#### Congratulations!!
Until here you already completed your first Python Lambda Function on Amazon Lambda.