5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

これは今年もやるよ!AWS Lambda縛り Advent Calendar 2015の20日目の記事である。


AWS Lambdaからfacebookの自分自身もしくは特定ページのタイムラインへ投稿してみよう。ただ残念なことに、facebookにはincoming webhookの仕組みがない。そのためfacebookのアクセストークンを取得するにはかなり面倒な手順が必要となる。

検証環境

今回の検証は、以下の環境で実施した。

version
OS Ubuntu 14.04.3 (3.13.0-71-generic)
python 2.7.10
pip 7.1.2
aws-cli 1.9.12
lambda-uploader 0.5.0
requests 2.8.1
facebook-sdk 0.4.0

AWS Lambda用IAMユーザとIAMロールを作成

AWS Lambda Developers Guide等を参考に、AWS Lambda用IAM UserとIAM Roleを作成する。

IAM User

今回は検証のため、AdministratorAccess権限を持ったIAM Userを作成した。本来はきっちり権限を制限した方が良い。

AdministratorAccess
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "*",
      "Resource": "*"
    }
  ]
}

またこのユーザのAccess Keyを取得し、AWS CLIに設定した。

awscli
$ aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************J5NA shared-credentials-file    
secret_key     ****************uUMd shared-credentials-file    
    region           ap-northeast-1      config-file    ~/.aws/config

IAM Role

今回のLambda Functionは他のAWSリソースにはアクセスしないため、CloudWatch Logsへ出力できる権限だけ持つ lambda_basic_execution を適用したIAM Roleを作成した。

lambda_basic_execution
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    }
  ]
}

後に必要となるため、Role ARN をメモしておく。

Facebookに投稿するアクセストークンの取得

Facebookのアクセストークンを取得するには、結構面倒な手順(facebookアプリの作成 & OAuth コールバックを処理するhttp endpointの作成)が必要だ。これはAWS Lambdaとは関係無い話でもあるため、手順は別のページにまとめている。そのページを参考にしながら、User Access TokenとPage Access Tokenを取得して欲しい。

なお今回は、取得したアクセストークンをeventとしてLambda Functionに与える形を取っているが、リクエスト毎に変更されるものでもないため、S3やDynamoDBなどに保存しても良いだろう。

Lambda Functionの作成

pythonを用いてLambda Functionを作成し、lambda-uploaderを用いてAWS Lambdaに登録する。

Lambda Functionの設定ファイル作成

lambda-uploaderで用いるlambda.jsonを次のように作成する。

lambda.json
{
  "name": "facebook_publisher",
  "description": "Post a message to facebook timeline",
  "region": "ap-northeast-1",
  "handler": "facebook_publisher.lambda_handler",
  "role": "arn:aws:iam::<AccountID>:role/lambda_basic_execution",
  "timeout": 300,
  "memory": 256 
}

メモしておいたIAM RoleのARNをroleに設定すること。

requirements.txtの作成

今回はFacebookのGraphAPIをラップするFacebook SDK for Pythonを利用する。このFacebook SDK for Pythonはrequestsに依存しているが、これら二つのライブラリをrequirements.txtに記述しておけば、Lambda Functionと同梱してAWSにアップロードされる。

requirements.txt
requests
facebook-sdk

Lambda Functionの作成

トークンとメッセージをeventとして入力されると、自分自身もしくはトークンを取得したfacebookページにメッセージを投稿するLambda Function(facebook_publisher.py)を作成する。

facebook_publisher.py
#!/usr/bin/env python
# -*- encode: utf-8 -*-

from __future__ import print_function

import json
import facebook


class Timeline:
    def __init__(self, user_token, page_token):
        self.user_endpoint = facebook.GraphAPI(user_token)
        self.page_endpoint = facebook.GraphAPI(page_token)

    def post_me(self, msg):
        self.user_endpoint.put_object('me', 'feed', message=msg)
        print('posted to my timeline: %s' % msg)

    def post_page(self, msg):
        self.page_endpoint.put_wall_post(message=msg)
        print('posted to page timeline: %s' % msg)


def lambda_handler(event, context):
    user_token = event['token']['user_access']
    page_token = event['token']['page_access']
    target = event['target']
    message = event['message']
    try:
        timeline = Timeline(user_token=user_token, page_token=page_token)
        if target == 'me':
            timeline.post_me(message)
        elif target == 'page':
            timeline.post_page(message)
        else:
            print('%s is invalid' % target)
            return False
    except Exception as e:
        print('[%s] %s' % (type(e).__name__, str(e)))
        return False

    return True

AWS Lambdaへアップロード

labmda-uploaderを利用して、Lambda Functionと関連ライブラリをAWS Lambdaへアップロードする。

$ tree .
.
├── facebook_publisher.py
├── lambda.json
└── requirements.txt
$ 
$ lambda-uploader 
λ Building Package
λ Uploading Package
λ Fin

AWS LambdaからFacebookのタイムラインへ投稿

では、AWS CLIからAWS Lambdaへイベントを発行し、AWS LambdaからFacebookへメッセージを投稿してみる。

イベントファイルの作成

今回の検証では、他のサービスから呼び出されるのではなく、手動でイベントを発行するので、次のイベントファイル(event.json)を作成する。

event.json
{
  "token": {
    "page_access": "<取得したFacebookのPage Access Token>", 
    "user_access": "<取得したFacebookのUser Access Token>"
  },
  "target": "<me|page> 自分のタイムラインに投稿する場合はme、facebookページに投稿する場合はpage",
  "message": "<投稿するメッセージ>"
}

イベント発火

では、AWS CLIからイベントを発火させよう。

$ aws lambda invoke --invocation-type RequestResponse --function-name facebook_publisher --payload file://event.json output.txt
{
    "StatusCode": 200
}

発火時に指定したoutput.txtを確認すれば、Lambda Functionからの戻り値がわかる。

output.txt
vagrant@trusty64:~/python/aws_lambda$ cat output.txt 
true

投稿結果

上記の手順により、自分自身のタイムラインやfacebookページのタイムラインへAWS Lambdaから投稿できた。

スクリーンショット 2015-12-15 0.24.02.png

スクリーンショット 2015-12-15 0.24.54.png

AWS Lambdaの結果は、CloudWatch Logsから確認できる。

スクリーンショット 2015-12-15 0.28.49.png

まとめ

AWS Lambda以前の部分で苦労はあるものの、facebookの自分のタイムラインやページのタイムラインへAWS Lambdaからメッセージを投稿することができた。例えばreleaseタグをgithubへpushしたらfacebookページへ告知するなど、なんかイイカンジに使えないかと考えている。

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?