AliEaters Code支部#2: [ハンズオン資料]サルでもわかるアリババのサーバーレス

# はじめ
このQiita記事は[AliEaters Code支部#2](https://alibabacloud.connpass.com/event/142937/)の説明資料になります。
※ AliEaters Code支部はAlibaba Cloudの開発者に特化したユーザー会であり、aliyuncli、sdk、Alibaba Cloud関連の開発ツールを利用して、ハンズオンでAlibaba Cloudを使い倒すコミュニティです。

また、下記AliEaters Code支部の活動履歴になります。
【 1 】[AliEaters Code支部#1: 【初心者向け】Alibaba Cloud CLIハンズオン](https://alibabacloud.connpass.com/event/130315/)
　　　※ ハンズオン資料 [[Alibaba Cloud] VPC + ECS作成ハンズオン](https://qiita.com/nago3/items/3a2908bebb4794810fc7)

# AliEaters Code支部#2で取り扱うトピック or 課題: リソース管理

運用ルールが定まっておらず、クラウド環境(特に検証環境とか)に大量な作成者不明のリソースがあり、「リソースの上限にひかかってしまった」「この仮想サーバーを削除していいかどうかわからない」など、アカウント管理者が困ってしまう問題が少なくありません。
Alibaba Cloudでは、ServelessのプロダクトFunction Computeを中心に、ActionTrail、OSS、RAMと連携して、リソースが作成されると同時に、作成者の情報を作成されるリソースに自動的にTagをつける仕組みがあります。 

本Qiita記事では、Alibaba CloudのPythonSDKを利用して、ECS Instances(仮想サーバー)が作成されたら、自動的にTag付けの仕組みを構築します。

# 利用するAlibaba Cloudのプロダクト, SDK

1. [Security Token Service](https://jp.alibabacloud.com/help/doc-detail/28756.htm) -> STS<br>一時的にAlibaba Cloudを操作する権限をToken形式で提供するサービス 
2. [Object Storage Service](https://jp.alibabacloud.com/product/oss) -> OSS<br>非構造化データを安全・安価で保存できるオーブジェクトストレージサービス<br>- Bucket / Object  <br>- Trigger
3. [Resource Access Management](https://jp.alibabacloud.com/product/ram) -> RAM<br>Alibaba Cloudの認証/認可サービス  
　- Role (Service Role) : 今回利用するActionTrailやFunction Computeなどのプロダクトが指定したRoleを利用することで、一時的に別サービスを操作できる機能  
　- Policy : Alibaba Cloudを操作する権限
4. [ActionTrail](https://jp.alibabacloud.com/product/actiontrail)<br>Alibaba Cloud上の操作を記録するサービス
5. [Function Compute](https://jp.alibabacloud.com/product/function-compute) -> FC<br>ユーザーが仮想サーバーを作る必要がなく、プログラムを実行してくれるサービス<br>- Service  : Functionの集まり<br>
　- Function : 実行したいプログラム
6. [Virtual Private Cloud](https://jp.alibabacloud.com/product/vpc) -> VPC<br>クラウド上隔離されたネットワーク環境を作成できるサービス<br>- VSwitch : サブネット
7. [Elastic Compute Service](https://jp.alibabacloud.com/product/ecs) -> ECS<br>仮想サーバー<br>- Security Group : 仮想Firewall<br>- Instance : 仮想サーバー
8. [Alibaba Cloud Python SDK](https://www.alibabacloud.com/help/product/108102.htm)  
　- [SDK集(Alibaba Cloud 国際サイト)](https://developer.alibabacloud.com/resource/sdk?id=1) ※ 情報がやや少なめ  
　- [SDK集(Alibaba Cloud 中国サイト) - 阿里云开发工具包（SDK） ](https://developer.aliyun.com/tools/sdk#/python)


# アーキテクチャ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/83c7434b-2299-c3cd-8d70-2da8c4f92e71.png)

## 動作するフロー

1. UserがECSインスタンスを１つ以上作成する
2. ECS Instances作成のEventがActionTrailに反映される <br>
　- [(RunInstancesの)ActionTrailログのサンプル](https://github.com/jobbin/fun_with_serverless/blob/master/add_tag_to_ecs/run_ecs_actiontrail_log.json)
3. ActionTrailは定期的に操作ログのzipファイルをOSS Bucektに保存する
4. 操作ログのzipファイルがOSS Bucketに保存されると同時に、OSS Triggerが起動され、Function ComputeにEventを通知する<br>- [OSS Triggerの中身のサンプル](https://github.com/jobbin/fun_with_serverless/blob/master/add_tag_to_ecs/oss_trigger_info.json)

5. Function ComputeはOSSからのEvent情報を基づいて、対象のActionTrailログのzipを取得する
6. Function ComputeはActionTrailログ情報に基づいて、対象のECS InstancesにOwner Tagをつける

デモ動画 → https://youtu.be/l3ZSbflM_Zk
※　約1分30秒

# ハンズオンの流れ
下記４つのフェーズに分かれて、ハンズオンを進めていきます。

```
0: 諸環境の準備フェーズ
1: 構築フェーズ
    1.1: APIコールのClientの作成
    1.2: Alibaba Cloudの AccountIDの取得と確認
    1.3: OSS関連の作業
    1.4: RAM関連の作業
    1.5: ActionTrail関連の作業
    1.6: FC関連の作業
2: 動作確認フェーズ
    2.1: VPC関連の作業
    2.2: ECS関連の作業
3: 片付けフェーズ
    3.1: ECS関連の作業
    3.2: VPC関連の作業
    3.3: FC関連の作業
    3.4: ActionTrail関連作業
    3.5: OSS関連作業
    3.6: RAM関連作業
```

各ステップの作業については、基本的に下記の構成に従って記載しています。

```
- 作業内容
- 超雑な利用APIの情報
- 実行するコマンド
- 出力結果例
```



# ハンズオン手順

## 0: 諸環境の準備フェーズ

### 0.1: 利用するプロダクトの有効化

下記、まだ有効化されていないプロダクトがあれば、有効化を行います。

- [OSS](https://oss.console.aliyun.com/overview)
- [RAM](https://ram.console.aliyun.com/overview#/overview)
- [ActionTrail](https://actiontrail.console.aliyun.com/)
- [Function Compute](https://fc.console.aliyun.com/overview/)
- [VPC](https://vpc.console.aliyun.com/)
- [ECS](https://ecs-ap-northeast-1.console.aliyun.com/#/home)

### 0.2: ハンズオン専用のRAM Userの作成 / アクセスキーの作成 / 権限付与

1. [【RAMユーザーの作成】](https://jp.alibabacloud.com/help/doc-detail/28647.htm#h2-url-5)を参考に、ハンズオン専用のRAM Userを作成します。
2. [【RAM ユーザーへの権限付与】](https://jp.alibabacloud.com/help/doc-detail/121945.htm)を参考に、下記の権限を作成したRAM Userに付与します。
  - AliyunRAMFullAccess
  - AliyunOSSFullAccess
  - AliyunActionTrailFullAccess
  - AliyunFCFullAccess
  - AliyunVPCFullAccess
  - AliyunECSFullAccess

3. [【AccessKeyの作成】](https://jp.alibabacloud.com/help/doc-detail/53045.htm?parentId=28625)を参考に、ハンズオン専用のAccessKeyを作成します。
※ 作成されたAccessKeyとSecretKeyの情報をどっかで保存し、取り扱いに注意しましょう!

### 0.3: Pythonプログラム実行環境の準備

#### 0.3.1 AliEaters Code支部運営側が提供するJupyter環境へアクセス
※ <font color="red">オレオレ証明書を利用しているため、警告が出ますので、ご了承ください</font>


```
環境:
- Python 3.7.3
- oss2 2.8.0
- aliyun-fc2 2.2.0
- aliyun-python-sdk-core 2.6.0
- aliyun-python-sdk-actiontrail 1.0.0
- aliyun-python-sdk-ram 3.0.0
- aliyun-python-sdk-sts 3.0.0
- aliyun-python-sdk-vpc 3.0.2
- aliyun-python-sdk-ecs 4.9.0
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/fd2f1fc8-c803-4cf6-36d3-946f8ece9821.png)


運用側が提供する環境を利用しない場合は、各自のpython実行環境で下記のコマンドを実行して、aliyun python sdkのインストールをお願いします。

```python

pip install aliyun-python-sdk-core oss2 aliyun-python-sdk-actiontrail aliyun-python-sdk-ram aliyun-python-sdk-sts aliyun-fc2 aliyun-python-sdk-vpc aliyun-python-sdk-ecs
```

#### 0.3.2 Jupyter環境にログイン後の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/38b185d9-9e47-f4d0-5729-3e32a5178956.png)

#### 0.3.3 workディレクトリ配下に移動とPythonファイルの作成

code.zipはのちほどFunction Computeを作成する際に利用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/8c57d6da-8ae1-14e1-c9be-be6f54ae9509.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/2ac9cfda-db15-4c5f-e983-da49624eea67.png)


## 1: 構築フェーズ

### 1.1: APIコールのClientの作成

[AcsClient](https://github.com/aliyun/aliyun-openapi-python-sdk/blob/master/aliyun-python-sdk-core/aliyunsdkcore/client.py#L67)

コマンド: 

```python
#########################################
# APIコールのClientの作成
#########################################
from aliyunsdkcore.client import AcsClient

REGION = "ap-northeast-1"
ACCESS_KEY_ID = "< Your Access Key ID >"
ACCESS_KEY_SECRET = "< Your Secret Key >"
client = AcsClient(ACCESS_KEY_ID, ACCESS_KEY_SECRET, REGION)

```

出力結果例:

```
なし
```

### 1.2: Alibaba Cloudの AccountIDの取得と確認

[呼び出し元のIDの取得（GetCallerIdentity）](https://jp.alibabacloud.com/help/doc-detail/43767.htm)

コマンド: 

```python
#########################################
# AccountIDの取得
#########################################
import json
from aliyunsdksts.request.v20150401.GetCallerIdentityRequest import GetCallerIdentityRequest

request = GetCallerIdentityRequest()
request.set_accept_format('json')
response = json.loads(client.do_action_with_exception(request))

# ACCOUNT_IDの確認
ACCOUNT_ID = response["AccountId"]
print("AccountId = " , ACCOUNT_ID)
```
出力結果例:

```
AccountId =  5644*******6921
```


### 1.3: [OSS](https://jp.alibabacloud.com/product/oss)関連の作業

```
0: 諸環境の準備フェーズ
1: 構築フェーズ
    1.1: APIコールのClientの作成
    1.2: Alibaba Cloudの AccountIDの取得と確認
    1.3: OSS関連の作業   <------------------------------------------------- 今ここ
    1.4: RAM関連の作業
    1.5: ActionTrail関連の作業
    1.6: FC関連の作業
2: 動作確認フェーズ
    2.1: VPC関連の作業
    2.2: ECS関連の作業
3: 片付けフェーズ
    3.1: ECS関連の作業
    3.2: VPC関連の作業
    3.3: FC関連の作業
    3.4: ActionTrail関連作業
    3.5: OSS関連作業
    3.6: RAM関連作業
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/83c7434b-2299-c3cd-8d70-2da8c4f92e71.png)

#### 1.3.0: OSS とは
>Alibaba Cloud Object Storage Service (OSS) は、大容量のデータを格納、バックアップ、アーカイブできるクラウドオブジェクトストレージサービスです。安全性、コスト効率、操作性に優れ、99.999999999% のデータ信頼性を保証しています。

#### 1.3.1: ActionTrailのログ保存用のBucketの作成
[Bucket](https://github.com/aliyun/aliyun-oss-python-sdk/blob/master/oss2/api.py#L324)
[Auth](https://github.com/aliyun/aliyun-oss-python-sdk/blob/master/oss2/auth.py#L65)
[create_bucket](https://github.com/aliyun/aliyun-oss-python-sdk/blob/master/oss2/api.py#L1468)
[oss2のサンプルコード集](https://jp.alibabacloud.com/help/doc-detail/32026.htm#h2--4)

コマンド:

```python
#########################################
# OSS
# 　ActionTrail用のOSS Bucketの作成
#########################################
import oss2

# ユニークなOSS Bucket名にする必要がある
OSS_BUCKET = "action-trail-log" + "-" +  ACCOUNT_ID
OSS_ENDPOINT = "oss-ap-northeast-1.aliyuncs.com"

bucket = oss2.Bucket(oss2.Auth(ACCESS_KEY_ID, ACCESS_KEY_SECRET), OSS_ENDPOINT, OSS_BUCKET)
bucket.create_bucket(permission=oss2.BUCKET_ACL_PRIVATE,
                     input=oss2.models.BucketCreateConfig(oss2.BUCKET_STORAGE_CLASS_STANDARD))

```
出力結果例:

```
<oss2.models.RequestResult at 0x7f772d640828>
```

#### 1.3.2: ActionTrailのログ保存用のBucketの確認
[get_bucket_info](https://github.com/aliyun/aliyun-oss-python-sdk/blob/master/oss2/api.py#L1648)

コマンド: 

```python
# 作成したOSS Bucketの確認
bucket_info = bucket.get_bucket_info()
print('name: ' + bucket_info.name)
print('storage class: ' + bucket_info.storage_class)
print('creation date: ' + bucket_info.creation_date)
```
出力結果例:

```
name: action-trail-log-5644******6921
storage class: Standard
creation date: 2019-08-26T05:10:22.000Z
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/1790b9ea-a8e3-4077-5d55-ea8ace1b9cb4.png)


### 1.4: [RAM](https://jp.alibabacloud.com/product/ram)関連の作業

```
0: 諸環境の準備フェーズ
1: 構築フェーズ
    1.1: APIコールのClientの作成
    1.2: Alibaba Cloudの AccountIDの取得と確認
    1.3: OSS関連の作業   
    1.4: RAM関連の作業   <------------------------------------------------- 今ここ
    1.5: ActionTrail関連の作業
    1.6: FC関連の作業
2: 動作確認フェーズ
    2.1: VPC関連の作業
    2.2: ECS関連の作業
3: 片付けフェーズ
    3.1: ECS関連の作業
    3.2: VPC関連の作業
    3.3: FC関連の作業
    3.4: ActionTrail関連作業
    3.5: OSS関連作業
    3.6: RAM関連作業
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/83c7434b-2299-c3cd-8d70-2da8c4f92e71.png)

#### 1.4.0: RAM とは
>Alibaba Cloud Resource Access Management (RAM) は、ユーザーとそのアクセス権限を制御するサービスです。このサービスにより、ユーザー (従業員、システム、アプリケーションなど) を一元管理して、権限レベルによりリソースへのアクセスを安全に制御できます。

#### 1.4.1: ActionTrail用のRAM Roleの事前確認

[ロールの取得 (GetRole)](https://jp.alibabacloud.com/help/doc-detail/28711.htm)

コマンド: 

```python
###############################################################
# RAM Role
# 　ActionTrail用のRAM Roleの作成、信頼関係の付与、RAM Policyの付与
###############################################################
from aliyunsdkram.request.v20150501.CreateRoleRequest import CreateRoleRequest
from aliyunsdkram.request.v20150501.GetRoleRequest import GetRoleRequest
from aliyunsdkram.request.v20150501.AttachPolicyToRoleRequest import AttachPolicyToRoleRequest
from aliyunsdkram.request.v20150501.ListPoliciesForRoleRequest import ListPoliciesForRoleRequest

# 変数の準備
#  ActionTrail は AliyunActionTrailDefaultRoleを利用して、
#  ログファイルを指定されたOSS Bucketに保存する
ACTION_TRAIL_ROLE = "AliyunActionTrailDefaultRole"

# 指定したRoleの存在確認、存在しない場合はエラー表示
# 想定結果: Error:EntityNotExist.Role
request = GetRoleRequest()
request.set_accept_format('json')
request.set_RoleName(ACTION_TRAIL_ROLE)

response = json.loads(client.do_action_with_exception(request))
print(json.dumps(response, indent=4, sort_keys=True))
```

出力結果例(存在しない場合):

```python

---------------------------------------------------------------------------
ServerException                           Traceback (most recent call last)
<ipython-input-6-bd1c8ab3229f> in <module>
     17 request.set_RoleName(ACTION_TRAIL_ROLE)
     18 
---> 19 response = json.loads(client.do_action_with_exception(request))
     20 print(json.dumps(response, indent=4, sort_keys=True))

/opt/conda/lib/python3.7/site-packages/aliyunsdkcore/client.py in do_action_with_exception(self, acs_request)
    427 
    428         if exception:
--> 429             raise exception
    430         logger.debug('Response received. Product:%s Response-body: %s',
    431                      acs_request.get_product(), body)

ServerException: HTTP Status: 404 Error:EntityNotExist.Role The role not exists:AliyunActionTrailDefaultRole RequestID: F2F22F29-E970-4EC0-A34A-A7452006D404
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/b30102cc-6432-fa9c-ceaa-dbf6993254c4.png)


出力結果例(存在する場合):

<font color="red">[注意] AliyunActionTrailDefaultRole が存在する場合、 1.4.2 ~ 1.4.4 の作業はスキップしてください</font>

```python
{
    "RequestId": "92448093-95EC-487F-8008-C92A92F13F94",
    "Role": {
        "Arn": "acs:ram::5644*****946921:role/aliyunactiontraildefaultrole",
        "AssumeRolePolicyDocument": "{\n    \"Statement\": [{\n            \"Action\": \"sts:AssumeRole\",\n            \"Effect\": \"Allow\",\n            \"Principal\": {\"Service\": [\"actiontrail.aliyuncs.com\"]}}],\n    \"Version\": \"1\"}",
        "CreateDate": "2019-08-29T09:20:41Z",
        "Description": "",
        "RoleId": "337882913879459285",
        "RoleName": "AliyunActionTrailDefaultRole"
    }
}
```

#### 1.4.2: ActionTrail用のRAM Roleの作成、信頼関係の付与
[ロールの作成 (CreateRole)](https://jp.alibabacloud.com/help/doc-detail/28710.htm)

コマンド:

```python
# Roleの作成、信頼関係の付与
#  信頼関係がないと、ActionTrailが AliyunActionTrailDefaultRole を利用できない
request = CreateRoleRequest()
request.set_accept_format('json')
request.set_RoleName(ACTION_TRAIL_ROLE)
ASSUME_ROLE_POLICY_DOCUMENT = '''
{
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "actiontrail.aliyuncs.com"
        ]
      }
    }
  ],
  "Version": "1"
}
'''
request.set_AssumeRolePolicyDocument(ASSUME_ROLE_POLICY_DOCUMENT)

response = json.loads(client.do_action_with_exception(request))
print(json.dumps(response["Role"], indent=4, sort_keys=True))
```

出力結果例:

```python
{
    "Arn": "acs:ram::564******921:role/aliyunactiontraildefaultrole",
    "AssumeRolePolicyDocument": "{\n    \"Statement\": [{\n            \"Action\": \"sts:AssumeRole\",\n            \"Effect\": \"Allow\",\n            \"Principal\": {\"Service\": [\"actiontrail.aliyuncs.com\"]}}],\n    \"Version\": \"1\"}",
    "CreateDate": "2019-08-26T05:14:32Z",
    "Description": "",
    "RoleId": "305293459411671622",
    "RoleName": "AliyunActionTrailDefaultRole"
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/b7c11f35-5016-db00-b046-fa3de8d7047d.png)


#### 1.4.3: ActionTrail用のRAM RoleにPolicyの付与

[ロールに権限付与ポリシーをアタッチ（AttachPolicyToRole）](https://jp.alibabacloud.com/help/doc-detail/28729.htm)

コマンド:

```python
# 作成したRoleにPolicyの付与
#  ActionTrailがログファイルを保存する際にOSSを操作する権限が必要
request = AttachPolicyToRoleRequest()
request.set_accept_format('json')
request.set_PolicyType("System")
request.set_PolicyName("AliyunActionTrailRolePolicy")
request.set_RoleName(ACTION_TRAIL_ROLE)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例:

```python
{"RequestId":"7A2BC976-295A-4E3D-9B7E-EF9D2E652EAA"}
```

#### 1.4.4: ActionTrail用のRAM Roleに付与されたPolicyの確認
[ロールに付与された権限付与ポリシーの一覧表示（ListPoliciesForRole）](https://jp.alibabacloud.com/help/doc-detail/28734.htm)

コマンド:

```python
# 指定したRoleにPolicyを付与したかの確認
request = ListPoliciesForRoleRequest()
request.set_accept_format('json')
request.set_RoleName("AliyunActionTrailDefaultRole")

response = json.loads(client.do_action_with_exception(request))
print(json.dumps(response, indent=4, sort_keys=True))
```

出力結果例:

```python
{
    "Policies": {
        "Policy": [
            {
                "AttachDate": "2019-08-26T05:14:47Z",
                "DefaultVersion": "v3",
                "Description": "\u7528\u4e8eActionTrail\u670d\u52a1\u9ed8\u8ba4\u89d2\u8272\u7684\u6388\u6743\u7b56\u7565\uff0c\u5305\u62ecOSS\u7684\u5bf9\u8c61\u5217\u51fa\u53ca\u5199\u5165\u6743\u9650",
                "PolicyName": "AliyunActionTrailRolePolicy",
                "PolicyType": "System"
            }
        ]
    },
    "RequestId": "80B2F78F-D157-4883-896C-212674EDCAB4"
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/10c21fe0-373a-2af7-0531-353ad74aa207.png)


#### 1.4.5: Function Compute用のRAM Roleの作成、信頼関係の付与

コマンド: 

```python
###############################################################
# RAM Role
# 　Function Compute用のRAM Roleの作成、信頼関係の付与、RAM Policyの付与
###############################################################

# 変数の準備
FC_ROLE = "fc-role"

# Roleの作成、信頼関係の付与
request = CreateRoleRequest()
request.set_accept_format('json')
request.set_RoleName(FC_ROLE)
ASSUME_ROLE_POLICY_DOCUMENT = '''
{
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "fc.aliyuncs.com"
        ]
      }
    }
  ],
  "Version": "1"
}
'''
request.set_AssumeRolePolicyDocument(ASSUME_ROLE_POLICY_DOCUMENT)

response = json.loads(client.do_action_with_exception(request))
print(json.dumps(response["Role"], indent=4, sort_keys=True))
```
出力結果例:

```python

{
    "Arn": "acs:ram::5644*****6921:role/fc-role",
    "AssumeRolePolicyDocument": "{\n    \"Statement\": [{\n            \"Action\": \"sts:AssumeRole\",\n            \"Effect\": \"Allow\",\n            \"Principal\": {\"Service\": [\"fc.aliyuncs.com\"]}}],\n    \"Version\": \"1\"}",
    "CreateDate": "2019-08-26T05:16:17Z",
    "Description": "",
    "RoleId": "3296*****9088489",
    "RoleName": "fc-role"
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/bd52b63b-3810-7fa9-9851-df4daf9b5690.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/f1fa5dde-2672-32e3-4b23-402c85686d58.png)

#### 1.4.6: Function Compute用のRoleにPolicy(AliyunOSSFullAccess)の付与

コマンド:

```python
# 作成したRoleにPolicy(AliyunOSSFullAccess)の付与
request = AttachPolicyToRoleRequest()
request.set_accept_format('json')
request.set_PolicyType("System")
request.set_PolicyName("AliyunOSSFullAccess")
request.set_RoleName(FC_ROLE)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```
出力結果例:

```python
{"RequestId":"FDE146EA-2377-46DF-8628-8578B0F10C95"}
```

#### 1.4.7: Function Compute用のRoleにPolicy(AliyunECSFullAccess)の付与

コマンド:

```python
# 作成したRoleにPolicy(AliyunECSFullAccess)の付与
request.set_PolicyName("AliyunECSFullAccess")

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```
出力結果例:

```python
{"RequestId":"73816F3A-9EC6-43AE-80B1-33A699D38BD7"}
```


#### 1.4.8: Function Compute用のRoleにPolicyを付与したかの確認

コマンド:

```python
# 指定したRoleにPolicyを付与したかの確認
request = ListPoliciesForRoleRequest()
request.set_accept_format('json')
request.set_RoleName(FC_ROLE)

response = json.loads(client.do_action_with_exception(request))
print(json.dumps(response, indent=4, sort_keys=True))
```
出力結果例:

```python
{
    "Policies": {
        "Policy": [
            {
                "AttachDate": "2019-08-30T04:45:08Z",
                "DefaultVersion": "v1",
                "Description": "\u7ba1\u7406\u5bf9\u8c61\u5b58\u50a8\u670d\u52a1(OSS)\u6743\u9650",
                "PolicyName": "AliyunOSSFullAccess",
                "PolicyType": "System"
            },
            {
                "AttachDate": "2019-08-30T04:46:12Z",
                "DefaultVersion": "v2",
                "Description": "\u7ba1\u7406\u4e91\u670d\u52a1\u5668\u670d\u52a1(ECS)\u7684\u6743\u9650",
                "PolicyName": "AliyunECSFullAccess",
                "PolicyType": "System"
            }
        ]
    },
    "RequestId": "D3222802-FC86-4FA2-9354-584EC150702B"
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/8e50b465-ee56-0d31-a01c-da00ee2215f1.png)


#### 1.4.9: OSS Trigger用のRoleの作成

コマンド:

```python
###############################################################
# OSS Trigger Role
# 　OSS Trigger用のRAM Roleの作成、信頼関係の付与、RAM Policyの付与
###############################################################

# 変数の準備
OSS_INVOCATION_ROLE = "AliyunOSSEventNotificationRole"

# Roleの作成、信頼関係の付与
request = CreateRoleRequest()
request.set_accept_format('json')
request.set_RoleName(OSS_INVOCATION_ROLE)
ASSUME_ROLE_POLICY_DOCUMENT = '''
{
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "oss.aliyuncs.com"
        ]
      }
    }
  ],
  "Version": "1"
}
'''
request.set_AssumeRolePolicyDocument(ASSUME_ROLE_POLICY_DOCUMENT)

response = json.loads(client.do_action_with_exception(request))
OSS_INVOCATION_ROLE_ARN = response["Role"]["Arn"]
print("OSS_INVOCATION_ROLE_ARN : ", OSS_INVOCATION_ROLE_ARN)
```

出力結果例:

```python
OSS_INVOCATION_ROLE_ARN :  acs:ram::5644*****46921:role/aliyunosseventnotificationrole
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/4b4bf1a5-430f-c1e4-fb55-f090e63d100b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/21bef045-a6b5-62c0-22bf-1483b2dd4102.png)

#### 1.4.10: OSS Trigger用のRoleにPolicy(AliyunOSSEventNotificationRolePolicy)の付与

コマンド:

```python
# 作成したRoleにPolicy(AliyunOSSEventNotificationRolePolicy)の付与
request = AttachPolicyToRoleRequest()
request.set_accept_format('json')
request.set_PolicyType("System")
request.set_PolicyName("AliyunOSSEventNotificationRolePolicy")
request.set_RoleName(OSS_INVOCATION_ROLE)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例:

```python
{"RequestId":"274AEBFB-9141-4204-BE97-D02B9F2C2262"}
```

#### 1.4.11: OSS Trigger用のRoleにPolicyを付与したかの確認

コマンド:

```python
# 指定したRoleにPolicyを付与したかの確認
request = ListPoliciesForRoleRequest()
request.set_accept_format('json')
request.set_RoleName(OSS_INVOCATION_ROLE)

response = json.loads(client.do_action_with_exception(request))
print(json.dumps(response, indent=4, sort_keys=True))
```

出力結果例:

```python
{
    "Policies": {
        "Policy": [
            {
                "AttachDate": "2019-08-26T05:40:32Z",
                "DefaultVersion": "v1",
                "Description": "\u7528\u4e8eOSS\u670d\u52a1\u4e8b\u4ef6\u901a\u77e5\u529f\u80fd\u89d2\u8272\u7684\u6388\u6743\u7b56\u7565",
                "PolicyName": "AliyunOSSEventNotificationRolePolicy",
                "PolicyType": "System"
            }
        ]
    },
    "RequestId": "0310E003-9415-4BC3-ADE7-9BDB85B2CA67"
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/891a8a39-779c-5534-3a67-201a5d983fe5.png)


### 1.5: [ActionTrail](https://jp.alibabacloud.com/product/actiontrail)関連の作業

```
0: 諸環境の準備フェーズ
1: 構築フェーズ
    1.1: APIコールのClientの作成
    1.2: Alibaba Cloudの AccountIDの取得と確認
    1.3: OSS関連の作業   
    1.4: RAM関連の作業   
    1.5: ActionTrail関連の作業  <------------------------------------------------- 今ここ
    1.6: FC関連の作業
2: 動作確認フェーズ
    2.1: VPC関連の作業
    2.2: ECS関連の作業
3: 片付けフェーズ
    3.1: ECS関連の作業
    3.2: VPC関連の作業
    3.3: FC関連の作業
    3.4: ActionTrail関連作業
    3.5: OSS関連作業
    3.6: RAM関連作業
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/83c7434b-2299-c3cd-8d70-2da8c4f92e71.png)

#### 1.5.0: ActionTrail とは
>ActionTrail は、リソースの操作履歴の記録、操作履歴の検索、操作履歴の OSS バケットへの保存が可能です。操作履歴を分析することで、リソースの変更管理はもちろん、セキュリティ管理やコンプライアンス監査にも対応できます。

#### 1.5.1: ActionTrailの確認

[DescribeTrails](https://jp.alibabacloud.com/help/doc-detail/28842.htm)

コマンド:

```python
###############################################################
# ActionTrail
# 　ActionTrailの作成、OSS Bucketの設定、ActionTraioの有効化
###############################################################
from aliyunsdkactiontrail.request.v20171204.CreateTrailRequest import CreateTrailRequest
from aliyunsdkactiontrail.request.v20171204.StartLoggingRequest import StartLoggingRequest
from aliyunsdkactiontrail.request.v20171204.DescribeTrailsRequest import DescribeTrailsRequest

# 変数の準備
ACTION_TRAIL = "audit-trail" # Your ActionTrail
ACTION_TRAIL_ROLE = "AliyunActionTrailDefaultRole"

# ActionTrailの確認
request = DescribeTrailsRequest()
request.set_accept_format('json')

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例(存在しない場合):

<font color="red">[注意] TrailListが空きでない場合は、すでにTrailが存在しているため、1.5.2 ~ 1.5.5までの手順をご確認していただいて、足りていない部分のみ対応してください</font>

```python
{"TrailList":[],"RequestId":"DEACF710-5F24-46CF-A918-B2A62F043F19"}
```


#### 1.5.2: ActionTrailの作成

[CreateTrail](https://jp.alibabacloud.com/help/doc-detail/28841.htm)

コマンド:

```python
request = CreateTrailRequest()
request.set_accept_format('json')
request.set_Name(ACTION_TRAIL)
request.set_OssBucketName(OSS_BUCKET)
request.set_RoleName(ACTION_TRAIL_ROLE)

response = json.loads(client.do_action_with_exception(request))
print(json.dumps(response, indent=4, sort_keys=True))
```

出力結果例:

```python
{
    "EventRW": "Write",
    "HomeRegion": "ap-northeast-1",
    "Name": "audit-trail",
    "OssBucketName": "action-trail-log-56443******921",
    "RequestId": "CAA3916C-7614-4C5B-84A7-91B03656078E",
    "RoleName": "aliyunactiontraildefaultrole"
}
```

#### 1.5.3: 作成したActionTrailの確認

[DescribeTrails](https://jp.alibabacloud.com/help/doc-detail/28842.htm)

コマンド:

```python
# ActionTrailの確認、デフォルトはStatus無効(Fresh)になっている
request = DescribeTrailsRequest()
request.set_accept_format('json')

response = json.loads(client.do_action_with_exception(request))
print(json.dumps(response["TrailList"][0], indent=4, sort_keys=True))
```

出力結果例:

```python
{
    "EventRW": "Write",
    "HomeRegion": "ap-northeast-1",
    "IncludeGlobalServiceEvent": true,
    "Name": "audit-trail",
    "OssBucketName": "action-trail-log-56443********921",
    "OssKeyPrefix": "",
    "Region": "ap-northeast-1",
    "RoleName": "aliyunactiontraildefaultrole",
    "SlsProjectArn": "",
    "SlsWriteRoleArn": "",
    "Status": "Fresh",
    "Type": "Action"
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/b2dc2b1c-5b48-a5e6-00bc-edc83660f533.png)


#### 1.5.4: 作成したActionTrailの有効化

[StartLogging](https://jp.alibabacloud.com/help/doc-detail/28844.htm)

コマンド:

```python
request = StartLoggingRequest()
request.set_accept_format('json')
request.set_Name(ACTION_TRAIL)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例:

```python
{"RequestId":"D8CD1E8A-DDFF-42EC-ABB8-059D83EC8075"}
```

#### 1.5.5: 作成したActionTrailの確認, Statusの確認

[DescribeTrails](https://jp.alibabacloud.com/help/doc-detail/28842.htm)

コマンド:

```python
# ActionTrailのStatusの確認、Statusが Fresh -> Enable
request = DescribeTrailsRequest()
request.set_accept_format('json')

response = json.loads(client.do_action_with_exception(request))
print(json.dumps(response["TrailList"][0], indent=4, sort_keys=True))
```

出力結果例:

```python
{
    "EventRW": "Write",
    "HomeRegion": "ap-northeast-1",
    "IncludeGlobalServiceEvent": true,
    "Name": "audit-trail",
    "OssBucketName": "action-trail-log-564*****6921",
    "OssKeyPrefix": "",
    "Region": "ap-northeast-1",
    "RoleName": "aliyunactiontraildefaultrole",
    "SlsProjectArn": "",
    "SlsWriteRoleArn": "",
    "Status": "Enable",
    "Type": "Action"
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/3338a651-f888-f86f-7bdc-287a6feb2947.png)

### 1.6: [FC](https://jp.alibabacloud.com/product/function-compute)関連の作業

```
0: 諸環境の準備フェーズ
1: 構築フェーズ
    1.1: APIコールのClientの作成
    1.2: Alibaba Cloudの AccountIDの取得と確認
    1.3: OSS関連の作業   
    1.4: RAM関連の作業   
    1.5: ActionTrail関連の作業  
    1.6: FC関連の作業  <------------------------------------------------- 今ここ
2: 動作確認フェーズ
    2.1: VPC関連の作業
    2.2: ECS関連の作業
3: 片付けフェーズ
    3.1: ECS関連の作業
    3.2: VPC関連の作業
    3.3: FC関連の作業
    3.4: ActionTrail関連作業
    3.5: OSS関連作業
    3.6: RAM関連作業
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/83c7434b-2299-c3cd-8d70-2da8c4f92e71.png)

#### 1.6.0: FC とは
>Alibaba Cloud Function Compute はイベント駆動型のフルマネージドコンピューティングサービスです。お客様はサーバーなどインフラストラクチャを管理する必要がなくなりコーディングに集中できます。
>Function Compute はコンピューティングリソースを提供し、柔軟かつ信頼性の高い方式でコードを実行できます。またコード実行時支払う必要があるのは消費したリソースの分だけで、コードを実行しなければ料金は発生しません。

#### 1.6.1: 変数の準備とFC Clientの作成

[fc2.Client](https://github.com/aliyun/fc-python-sdk/blob/master/fc2/client.py#L49)


コマンド:

```python
###############################################################
# Function Compute
# 　Serviceの作成、Functionの作成、OSS Triggerの作成
###############################################################
import fc2

# 変数の準備
FC_ENDPOINT = "https://" + ACCOUNT_ID + "." + REGION + ".fc.aliyuncs.com" # Function Compute Endpoint
ROLE_ARN = "acs:ram::"+ ACCOUNT_ID +":role/fc-role" # Function Compute Role ARN
FC_SERVICE = "resource_management" # Function Compute Service Name
FC_FUNCTION = "fc_function" # Function Compute Function Name

# FC Clientの作成
fc_client = fc2.Client(
    endpoint=FC_ENDPOINT,
    accessKeyID=ACCESS_KEY_ID,
    accessKeySecret=ACCESS_KEY_SECRET
    )
```

出力結果例:

```python
なし
```

#### 1.6.2: FC Serviceの作成

[CreateService](https://jp.alibabacloud.com/help/doc-detail/52877.htm#createservice)
※ [Service](https://jp.alibabacloud.com/help/doc-detail/52877.htm#service)

[list_services](https://github.com/aliyun/fc-python-sdk/blob/master/fc2/client.py#L331)


コマンド:

```python
# FC Serviceの作成
service = fc_client.create_service(serviceName=FC_SERVICE, role=ROLE_ARN)

response = fc_client.list_services()
for service in response.data["services"]:
    print("Function compute : ", service["serviceName"])
```

出力結果例:

```python
Function compute :  resource_management
Function compute :  *********
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/54e8ff3a-5ad0-d659-bb33-e7d5f95a7b05.png)

#### 1.6.3: FC Functionの作成
[create_function](https://github.com/aliyun/fc-python-sdk/blob/master/fc2/client.py#L395)

[FC Functionのプログラム](https://github.com/jobbin/fun_with_serverless/blob/master/add_tag_to_ecs/index.py)

※ 運営側が提供されるJupyter環境を利用しない場合は [Function Compute用のcode.zip](https://joe-public.oss-ap-northeast-1.aliyuncs.com/code.zip) をカレントディレクトリに保存してください。

コマンド:

```python
# FC Functionの作成
# service, function, rumtime, event handler, codeのpath を設定する必要がある
response = fc_client.create_function(
                                    FC_SERVICE, 
                                    FC_FUNCTION, 
                                    'python3', 
                                    'index.handler', 
                                    codeZipFile = 'code.zip',
                                    environmentVariables = {'TAG_NAME': 'Owner'}
                                    )
# 確認
print(json.dumps(response.data, indent=4, sort_keys=True))
```

出力結果例:

```python
{
    "codeChecksum": "13189467078313270400",
    "codeSize": 1274,
    "concurrencyLimit": 1,
    "createdTime": "2019-08-26T05:56:48Z",
    "description": "",
    "environmentVariables": {
        "TAG_NAME": "Owner"
    },
    "functionId": "18401af3-71ec-49d3-b3a8-e04fbf3581ef",
    "functionName": "fc_function",
    "handler": "index.handler",
    "initializationTimeout": 30,
    "initializer": null,
    "lastModifiedTime": "2019-08-26T05:56:48Z",
    "memorySize": 256,
    "runtime": "python3",
    "timeout": 60
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/093b4807-f755-d96a-1d0c-ed4bdad110cd.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/62b7264a-8259-7b8b-fb5f-42b8f7af2d2f.png)


#### 1.6.4: OSS Triggerの作成

[CreateTrigger](https://jp.alibabacloud.com/help/doc-detail/52877.htm#createtrigger) 

[OSS Triggerの中身のサンプル](https://github.com/jobbin/fun_with_serverless/blob/master/add_tag_to_ecs/oss_trigger_info.json)

コマンド:

```python
# OSS Triggerの作成
#  trigger名,triggerの種類, 対象の操作event(今回は oss:ObjectCreated:PutObject ), 
#  対象のOSS Bucket, OSS用のRAM Roleを指定する必要がある
OSS_TRIGGER = "oss-trigger"
OSS_TRIGGER_CONFIG = {"events": ["oss:ObjectCreated:PutObject"]}
OSS_SOURCE_ARN = "acs:oss:ap-northeast-1:" + ACCOUNT_ID + ":" + OSS_BUCKET
TRIGGER_TYPE = "oss"

response = fc_client.create_trigger(
                                    FC_SERVICE, 
                                    FC_FUNCTION, 
                                    OSS_TRIGGER, 
                                    TRIGGER_TYPE,
                                    OSS_TRIGGER_CONFIG, 
                                    OSS_SOURCE_ARN, 
                                    OSS_INVOCATION_ROLE_ARN
                                )
# 確認
print(json.dumps(response.data, indent=4, sort_keys=True))
```

出力結果例:

```python
{
    "createdTime": "2019-08-26T05:57:14Z",
    "description": "",
    "invocationRole": "acs:ram::564*******46921:role/aliyunosseventnotificationrole",
    "lastModifiedTime": "2019-08-26T05:57:14Z",
    "qualifier": null,
    "sourceArn": "acs:oss:ap-northeast-1:564*******6921:action-trail-log-5644********921",
    "triggerConfig": {
        "events": [
            "oss:ObjectCreated:PutObject"
        ],
        "filter": {
            "key": {
                "prefix": "",
                "suffix": ""
            }
        }
    },
    "triggerId": "c5478f0b-91cc-4231-8d19-3738dc3a01e5",
    "triggerName": "oss-trigger",
    "triggerType": "oss"
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/706b0f95-8cdc-5463-e71b-5e72bdf70f2e.png)

## 2: 動作確認フェーズ

### 2.1: [VPC](https://jp.alibabacloud.com/product/vpc)関連の作業

```
0: 諸環境の準備フェーズ
1: 構築フェーズ
    1.1: APIコールのClientの作成
    1.2: Alibaba Cloudの AccountIDの取得と確認
    1.3: OSS関連の作業   
    1.4: RAM関連の作業   
    1.5: ActionTrail関連の作業  
    1.6: FC関連の作業  
2: 動作確認フェーズ
    2.1: VPC関連の作業  <------------------------------------------------- 今ここ
    2.2: ECS関連の作業
3: 片付けフェーズ
    3.1: ECS関連の作業
    3.2: VPC関連の作業
    3.3: FC関連の作業
    3.4: ActionTrail関連作業
    3.5: OSS関連作業
    3.6: RAM関連作業
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/83c7434b-2299-c3cd-8d70-2da8c4f92e71.png)

#### 2.1.0: VPC とは
>Alibaba Cloud Virtual Private Cloud (VPC) では、クラウド上で分離されたネットワークを構築して、外部からのアクセスが制限された安全で環境でリソースを運用できます。独自の IP アドレス範囲を選択し、ルーティングテーブルとネットワークゲートウェイを設定して、ネットワークを制御できます。オンプレミスのネットワークを VPC に接続することでリソースを増強し、Alibaba Cloud をデータセンターの拡張機能のソリューションとして活用できます。

#### 2.1.1: VPCの作成

[CreateVpc](https://jp.alibabacloud.com/help/doc-detail/35737.htm)

コマンド:

```python
###############################################################
# VPC
#   VPC, VSwitchの作成
###############################################################

# VPCの作成
from aliyunsdkvpc.request.v20160428.CreateVpcRequest import CreateVpcRequest

request = CreateVpcRequest()
request.set_accept_format('json')
# CidrBlockが重複した場合はエラーなる
request.set_CidrBlock("172.16.0.0/12")
response = json.loads(client.do_action_with_exception(request))

# 確認
VPC_ID = response["VpcId"]
print("VPC_ID : ", VPC_ID)
print("\n")
print(json.dumps(response, indent=4, sort_keys=True))
```

出力結果例:

```python
VPC_ID : vpc-6weel8******m8wr5de


{
    "RequestId": "6625BD2B-9778-463D-BF73-948499224933",
    "ResourceGroupId": "rg-acfnwmebvyioq2i",
    "RouteTableId": "vtb-6wetp1kgb16sdhi47qhv8",
    "VRouterId": "vrt-6wejcqgmwnbsx5lfe5xpv",
    "VpcId": "vpc-6weel8******m8wr5de"
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/94665ea1-dd40-66bf-c8e6-fc2b2aaa8ad7.png)


#### 2.1.2: VSwithの作成

[CreateVSwitch](https://jp.alibabacloud.com/help/doc-detail/35745.htm)

コマンド:

```python
# VSwithの作成
from aliyunsdkvpc.request.v20160428.CreateVSwitchRequest import CreateVSwitchRequest

# 変数の準備
# 東京リージョン(ap-northeast-1) に Zoneが２つある
CIRDER_BLOCK = "172.16.100.0/24"
ZONE_ID = "ap-northeast-1a"

request = CreateVSwitchRequest()
request.set_accept_format('json')
request.set_CidrBlock(CIRDER_BLOCK)
request.set_VpcId(VPC_ID)
request.set_ZoneId(ZONE_ID)

response = json.loads(client.do_action_with_exception(request))

# 確認
VSWITCH_ID = response["VSwitchId"]
print("VSWITCH_ID : " + VSWITCH_ID)
print("\n")
print(json.dumps(response, indent=4, sort_keys=True))
```

出力結果例:

```python
SECURITY_GROUP_ID :  sg-6we2p57hosr5u4l1e100


{
    "RequestId": "E391B162-5CA6-480B-9B7E-5845BF242AA3",
    "SecurityGroupId": "sg-6we2p57hosr5u4l1e100"
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/4a5d1a25-37df-c96c-0b42-a77678d55982.png)

### 2.2: [ECS](https://jp.alibabacloud.com/product/ecs)関連の作業

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/83c7434b-2299-c3cd-8d70-2da8c4f92e71.png)

```
0: 諸環境の準備フェーズ
1: 構築フェーズ
    1.1: APIコールのClientの作成
    1.2: Alibaba Cloudの AccountIDの取得と確認
    1.3: OSS関連の作業   
    1.4: RAM関連の作業   
    1.5: ActionTrail関連の作業  
    1.6: FC関連の作業  
2: 動作確認フェーズ
    2.1: VPC関連の作業  
    2.2: ECS関連の作業  <------------------------------------------------- 今ここ
3: 片付けフェーズ
    3.1: ECS関連の作業
    3.2: VPC関連の作業
    3.3: FC関連の作業
    3.4: ActionTrail関連作業
    3.5: OSS関連作業
    3.6: RAM関連作業
```


#### 2.2.0: ECS とは
>Alibaba Cloud Elastic Compute Service (ECS) は、信頼性と拡張性に優れた分散コンピューティングリソースをオンデマンドで提供するオンラインコンピューティングサービスです。ECS を使用すると、クラウドコンピューティング環境を完全に制御できます。

#### 2.2.1: Security Groupの作成

[CreateSecurityGroup](https://jp.alibabacloud.com/help/doc-detail/25553.htm)

コマンド:

```python
###############################################################
# ECS
#   Security Group, ECS Instanceの作成
###############################################################

# Security Groupの作成
#  ECSインスタンスを作成する際に、Security Group の設定が必須
from aliyunsdkecs.request.v20140526.CreateSecurityGroupRequest import CreateSecurityGroupRequest

request = CreateSecurityGroupRequest()
request.set_accept_format('json')
request.set_VpcId(VPC_ID)
response = json.loads(client.do_action_with_exception(request))

# 確認
SECURITY_GROUP_ID = response["SecurityGroupId"]
print("SECURITY_GROUP_ID : " , SECURITY_GROUP_ID)
print("\n")
print(json.dumps(response, indent=4, sort_keys=True))
```

出力結果例:

```python
SECURITY_GROUP_ID :  sg-6we2p57hosr5u4l1e100


{
    "RequestId": "E391B162-5CA6-480B-9B7E-5845BF242AA3",
    "SecurityGroupId": "sg-6we2p57hosr5u4l1e100"
}
```

#### 2.2.2: ECS Instanceの作成

[RunInstances](https://jp.alibabacloud.com/help/doc-detail/63440.htm)

[(RunInstancesの)ActionTrailログのサンプル](https://github.com/jobbin/fun_with_serverless/blob/master/add_tag_to_ecs/run_ecs_actiontrail_log.json)

コマンド:

```python
# ECS Instanceの作成
from aliyunsdkecs.request.v20140526.RunInstancesRequest import RunInstancesRequest

# 変数の準備
IMAGE_ID = "ubuntu_18_04_64_20G_alibase_20190624.vhd"
INSTANCE_TYPE = "ecs.t5-lc1m1.small" # ecs.t5-lc1m1.small / ecs.t5-lc1m2.small / ecs.t5-lc2m1.nano

# ImageID, Instance type, Security group, VSwitch, Zoneを指定する
request = RunInstancesRequest()
request.set_accept_format('json')
request.set_ImageId(IMAGE_ID)
request.set_InstanceType(INSTANCE_TYPE)
request.set_SecurityGroupId(SECURITY_GROUP_ID)
request.set_VSwitchId(VSWITCH_ID)
request.set_ZoneId(ZONE_ID)

# 確認
# ECS Instanceが作成されてから, Tagをつけられるまで(場合によって)2~3分かかる
response = json.loads(client.do_action_with_exception(request))
INSTANCE_ID = response["InstanceIdSets"]["InstanceIdSet"][0]
print("INSTANCE_ID :  ", INSTANCE_ID)
print("\n")
print(json.dumps(response, indent=4, sort_keys=True))
```

出力結果例:

```python
INSTANCE_ID :   i-6we2p57hosr5u4kv712b


{
    "InstanceIdSets": {
        "InstanceIdSet": [
            "i-6we2p57hosr5u4kv712b"
        ]
    },
    "RequestId": "7940576C-0C22-4019-AD97-E99EA1396AA1"
}
```

#### 2.2.3: Tagの確認

[DescribeInstances](https://jp.alibabacloud.com/help/doc-detail/25506.htm)

コマンド:

```python
# Tagの確認
from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest
request = DescribeInstancesRequest()
request.set_accept_format('json')
request.set_InstanceIds('["' + INSTANCE_ID + '"]')

response = json.loads(client.do_action_with_exception(request))
print(json.dumps(response["Instances"]["Instance"][0]["Tags"], indent=4, sort_keys=True))
```

出力結果例(Tag付けされる前):

```python
KeyError                                  Traceback (most recent call last)
<ipython-input-32-120be11c2ae2> in <module>
      6 
      7 response = json.loads(client.do_action_with_exception(request))
----> 8 print(json.dumps(response["Instances"]["Instance"][0]["Tags"], indent=4, sort_keys=True))

KeyError: 'Tags'
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117156/c27aeb89-ba9d-2217-8d96-118c33f93fb9.png)


出力結果例(Tag付けされた後):

```python
{
    "Tag": [
        {
            "TagKey": "Owner",
            "TagValue": "handson"
        }
    ]
}
```

![uploading-0]()


## 3: 片付けフェーズ

<font color="red">[注意]Alibaba Cloudのリソースを削除する際に、リソース間の依存関係を考慮して、順番に削除する必要がある</font>

```
0: 諸環境の準備フェーズ
1: 構築フェーズ
    1.1: APIコールのClientの作成
    1.2: Alibaba Cloudの AccountIDの取得と確認
    1.3: OSS関連の作業   
    1.4: RAM関連の作業   
    1.5: ActionTrail関連の作業  
    1.6: FC関連の作業  
2: 動作確認フェーズ
    2.1: VPC関連の作業  
    2.2: ECS関連の作業  
3: 片付けフェーズ  <------------------------------------------------- 今ここ
    3.1: ECS関連の作業
    3.2: VPC関連の作業
    3.3: FC関連の作業
    3.4: ActionTrail関連作業
    3.5: OSS関連作業
    3.6: RAM関連作業
```

### 3.1: ECS関連の作業

#### 3.1.1: ECS Insatanceの停止

[StopInstance](https://jp.alibabacloud.com/help/doc-detail/25501.htm)

コマンド:

```python
###############################################################
# ECS
#   ECS,Security Groupの削除
#   ※ ECS Instanceは停止の状態ではないと、削除できない
###############################################################

# ECS Insatanceの停止
#  codeの場合、ECS Instanceを停止してから、削除する
from aliyunsdkecs.request.v20140526.StopInstanceRequest import StopInstanceRequest

request = StopInstanceRequest()
request.set_accept_format('json')
request.set_InstanceId(INSTANCE_ID)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例:

```python
{"RequestId":"DE4FCCD1-76C8-4A02-912C-FEEE25524BE1"}
```

#### 3.1.2: ECS Insatanceの削除
[DeleteInstance](https://jp.alibabacloud.com/help/doc-detail/25507.htm)

コマンド:

```python
# ECS Insatanceの削除
from aliyunsdkecs.request.v20140526.DeleteInstanceRequest import DeleteInstanceRequest

request = DeleteInstanceRequest()
request.set_accept_format('json')
request.set_InstanceId(INSTANCE_ID)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例:

```python
{"RequestId":"DE4FCCD1-76C8-4A02-912C-FEEE25524BE1"}
```

#### 3.1.3: Security Groupの削除

[DeleteSecurityGroup](https://jp.alibabacloud.com/help/doc-detail/25558.htm)

コマンド: 

```python
# Security Groupの削除
from aliyunsdkecs.request.v20140526.DeleteSecurityGroupRequest import DeleteSecurityGroupRequest

request = DeleteSecurityGroupRequest()
request.set_accept_format('json')
request.set_SecurityGroupId(SECURITY_GROUP_ID)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例:

```python
{"RequestId":"DE4FCCD1-76C8-4A02-912C-FEEE25524BE1"}
```

### 3.2: VPC関連の作業 
#### 3.2.1: VSwitchの削除
[DeleteVSwitch](https://jp.alibabacloud.com/help/doc-detail/35746.htm)

コマンド: 

```python
###############################################################
# VPC
#   VPC, VSwitchの削除
###############################################################

# VSwitchの削除
from aliyunsdkvpc.request.v20160428.DeleteVSwitchRequest import DeleteVSwitchRequest

request = DeleteVSwitchRequest()
request.set_accept_format('json')
request.set_VSwitchId(VSWITCH_ID)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例:

```python
{"RequestId":"DE4FCCD1-76C8-4A02-912C-FEEE25524BE1"}
```

#### 3.2.2: VPCの削除
[DeleteVpc](https://jp.alibabacloud.com/help/doc-detail/35738.htm)

コマンド:

```python
# VPCの削除
from aliyunsdkvpc.request.v20160428.DeleteVpcRequest import DeleteVpcRequest

request = DeleteVpcRequest()
request.set_accept_format('json')
request.set_VpcId(VPC_ID)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例:

```python
{"RequestId":"DE4FCCD1-76C8-4A02-912C-FEEE25524BE1"}
```

### 3.3: FC関連の作業

#### 3.3.1: OSS Triggerの削除

[DeleteTrigger](https://jp.alibabacloud.com/help/doc-detail/52877.htm?spm=a21mg.p38356.b99.115.478551252Pk6ba#deletetrigger)

コマンド:

```python
###############################################################
# Function Compute
#   OSS Trigger,FC Function, FC Serviceの削除
#
# RAM Role
#   RoleのPolicyのDetach, Role削除
###############################################################

# OSS Triggerの削除
response = fc_client.delete_trigger(FC_SERVICE, FC_FUNCTION, OSS_TRIGGER)
print("Function Compute Trigger : ", response)
```

出力結果例:

```python
Function Compute Trigger :  None
```

#### 3.3.2: FC Functionの削除

[DeleteFunction](https://jp.alibabacloud.com/help/doc-detail/52877.htm#deletefunction)

コマンド:

```python
# FC Functionの削除
response = fc_client.delete_function(FC_SERVICE, FC_FUNCTION)
print("Function Compute Function : ", response)
```

出力結果例:

```python
Function Compute Function :  None
```

#### 3.3.3: FC Serviceの削除

[DeleteService](https://jp.alibabacloud.com/help/doc-detail/52877.htm#deleteservice)

コマンド:

```python
# FC Serviceの削除
response = fc_client.delete_service(FC_SERVICE)
print("Function Compute Service : ", response)
```

出力結果例:

```python
Function Compute Service :  None
```

#### 3.3.4: FC Roleから AliyunOSSFullAccess, AliyunECSFullAccess をDetach

[DetachPolicyFromRole](https://jp.alibabacloud.com/help/doc-detail/28730.htm)

コマンド: 

```python
# FC Roleから AliyunOSSFullAccess, AliyunECSFullAccess をDetach
from aliyunsdkram.request.v20150501.DetachPolicyFromRoleRequest import DetachPolicyFromRoleRequest

request = DetachPolicyFromRoleRequest()
request.set_accept_format('json')
request.set_PolicyType("System")
request.set_PolicyName("AliyunOSSFullAccess")
request.set_RoleName(FC_ROLE)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))

request.set_PolicyName("AliyunECSFullAccess")
response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例:

```python
{"RequestId":"771894E5-E539-492E-B9B5-752319BDE965"}
{"RequestId":"B7D88E8B-98B6-41AF-9FFD-382B85A780F4"}
```

#### 3.3.5: FC Roleの削除

[ロールの削除 (DeleteRole)](https://jp.alibabacloud.com/help/doc-detail/28714.htm)

コマンド:

```python
from aliyunsdkram.request.v20150501.DeleteRoleRequest import DeleteRoleRequest

request = DeleteRoleRequest()
request.set_accept_format('json')
request.set_RoleName(FC_ROLE)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例:

```python
{"RequestId":"771894E5-E539-492E-B9B5-752319BDE965"}
```

#### 3.3.6: OSS Trigger Roleから AliyunOSSEventNotificationRolePolicy をDetach

コマンド:

```python
# OSS Trigger Roleから AliyunOSSEventNotificationRolePolicy をDetach
request = DetachPolicyFromRoleRequest()
request.set_accept_format('json')
request.set_PolicyType("System")
request.set_PolicyName("AliyunOSSEventNotificationRolePolicy")
request.set_RoleName(OSS_INVOCATION_ROLE)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例:

```python
{"RequestId":"771894E5-E539-492E-B9B5-752319BDE965"}
{"RequestId":"B7D88E8B-98B6-41AF-9FFD-382B85A780F4"}
```

#### 3.3.7: OSS Trigger Roleの削除

コマンド:

```python
# OSS Trigger Roleの削除
request = DeleteRoleRequest()
request.set_accept_format('json')
request.set_RoleName(OSS_INVOCATION_ROLE)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例:

```python
{"RequestId":"DA7DB2A3-269C-4B6D-BBDF-4B73BFCE1994"}
```

### 3.4: ActionTrail関連作業

#### 3.4.1: ActionTrailの削除

[DeleteTrail](https://jp.alibabacloud.com/help/doc-detail/28847.htm)

コマンド:

```python
###############################################################
# ActionTrail
#   Trailの削除
#
# RAM Role
#   RoleのPolicyのDetach, Role削除
###############################################################

# ActionTrailの削除
from aliyunsdkactiontrail.request.v20171204.DeleteTrailRequest import DeleteTrailRequest

request = DeleteTrailRequest()
request.set_accept_format('json')
request.set_Name(ACTION_TRAIL)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例:

```python
{"RequestId":"DA7DB2A3-269C-4B6D-BBDF-4B73BFCE1994"}
```

#### 3.4.2: AliyunActionTrailDefaultRole から AliyunActionTrailRolePolicy をDetach

[DetachPolicyFromRole](https://jp.alibabacloud.com/help/doc-detail/28730.htm)

コマンド:

```python
# [Role] AliyunActionTrailDefaultRole から AliyunActionTrailRolePolicy をDetach
request = DetachPolicyFromRoleRequest()
request.set_accept_format('json')
request.set_PolicyType("System")
request.set_PolicyName("AliyunActionTrailRolePolicy")
request.set_RoleName(ACTION_TRAIL_ROLE)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例:

```python
{"RequestId":"DA7DB2A3-269C-4B6D-BBDF-4B73BFCE1994"}
```

#### 3.4.3: AliyunActionTrailDefaultRole の削除

[ロールの削除 (DeleteRole)](https://jp.alibabacloud.com/help/doc-detail/28714.htm)

コマンド: 

```python
# [Role] AliyunActionTrailDefaultRole の削除
request = DeleteRoleRequest()
request.set_accept_format('json')
request.set_RoleName(ACTION_TRAIL_ROLE)

response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
```

出力結果例:

```python
{"RequestId":"DA7DB2A3-269C-4B6D-BBDF-4B73BFCE1994"}
```

### 3.5: OSS関連作業

#### 3.5.1: OSS Objectの削除

コマンド:

```python
###############################################################
# OSS
#   OSS Object, OSS Bucketの削除
###############################################################

# OSS Objectの削除
bucket = oss2.Bucket(oss2.Auth(ACCESS_KEY_ID, ACCESS_KEY_SECRET), OSS_ENDPOINT, OSS_BUCKET)

for obj in oss2.ObjectIterator(bucket):
    list = obj.key.split("/")
    oss_object = list[-1]
    response = bucket.delete_object(obj.key)
    print("Delete OSS Object ",oss_object, " , Status Code : ", response.status)
    # 出力例: Delete OSS Object  HelloWorld.py  :  204
```

出力結果例:

```python
Delete OSS Object  Actiontrail_ap-northeast-1_20190826055055_1002_1_666_fd5e1891bfb2be089c3d975b481c668a.gz  , Status Code :  204
Delete OSS Object  Actiontrail_ap-northeast-1_20190826060521_1002_2_796_e3aedc1ac46c7143d0ac0c4f03b4130d.gz  , Status Code :  204
Delete OSS Object  Actiontrail_ap-northeast-1_20190826060600_1002_2_832_24071ce00d1ffc27cc1f53e86af45db6.gz  , Status Code :  204
Delete OSS Object  Actiontrail_ap-northeast-1_20190826061705_1002_1_477_dad1f031744547ae9f37bac3138c725f.gz  , Status Code :  204
* * *
* * * 
```

#### 3.5.2: OSS Bucketの削除

コマンド:

```python
# OSS Bucketの削除
response = bucket.delete_bucket()
print("Delete OSS Bucket ",OSS_BUCKET, " , Status Code : ", response.status)
```

コマンド:

```python
Delete OSS Bucket  action-trail-log-5644*****921  , Status Code :  204
```

### 3.6: RAM関連作業
<font color="red">[超重要] 必ず実施してください ! </font>
Alibaba Cloudアカウントにログインして、ハンズオン最初に作成したRAM Userを削除します。

### 3.7: 作業終了

以上、[AliEaters Code支部#2](https://alibabacloud.connpass.com/event/142937/) の作業はすべて終了しました ! お疲れ様でした !