
大友(@yomon8)です。
過去に以下の記事でLambdaからSAPへの接続を書きました。このときにはSAP JCoを使ってJavaで開発しています。
SAP JCoとAWS Lambdaを利用したSAP ABAPとAWSサービス間の連携
お客様でもPythonを使われているところも増えているように感じます。実はPythonでもPyRFCというライブラリを使うことでSAPに接続することができます。
実際にSAPのデータをPythonでデータを扱うのに便利なPandasに読み込む方法なども試したことがあります。
SAP ERPのデータをBigQueryに簡易ETLする(Pandas利用)
今回は更に進めてServerless FrameworkでデプロイしたAWS LambdaからSAPに接続して、SAP CCMSの情報を取得することを試してみます。
構成
構成は以下の図の通りです。

| SAP ERP | EC2上にSAP ABAPインスタンスをインストールしています。※1 |
| AWS Lambda + ECR | Lambdaコンテナイメージで実装しています。コンテナでLambdaを動かせるよううになったお陰でSAP NW SDKなどのようにネイティブライブラリを扱いやすくなりました。 |
| SecretsManager | SAPへの接続情報をセキュアに保管します |
| Serverless Framework | AWS Lambdaとコンテナイメージを格納するECRもデプロイします |
※1 本記事ではSAP CALでインストールしたIDESマシンを利用しています。CALについてはこの辺り(AWS、Azure、Google Cloud)を参考にしてください。
ソースコード
コードは以下のリポジトリに公開しています。
https://github.com/beex-inc/serverless-sap-ccms
使ってみる
前提条件
使ってみるまでの前提条件は以下になります。
- SAP ABAPインスタンスがAWS EC2上で起動している
- CCMS読み込み権限を持つSAPユーザが準備できている
- LambdaからSAP ABAPインスタンスにRFC接続がアクセス可能
- LambdaをデプロイするSubnetからAWS SecretsManager・ECRにアクセス可能
- SAP Netweaver SDKをダウンロードできるSユーザを持っている
- 適切な権限のAWS IAMユーザを持っていて
- AWS CLIがインストールされている(aws configure済み)
- 作業マシンにDockerがインストールされている(本手順ではLinux上で作業を行います)
リポジトリをクローン
上記に記載したGithubリポジトリからソースコードをクローンします。
$ git clone https://github.com/beex-inc/serverless-sap-ccms.git
SAP NetWeaver RFC SDK取得・配置
以下の情報を参照してダウンロードしてきます。Sユーザが必要になります。
SAP NetWeaver Remote Function Call (RFC) Software Development Kit (SDK)
2573790 - Installation, Support and Availability of the SAP NetWeaver RFC Library 7.50
今回ダウンロードしたのは「nwrfc750P_10-70002752.zip」 というファイルです。参考までにダウンロード画面を貼っておきます。

以下のように resources/フォルダ以下に解凍します。
$ ls -1 resources/ nwrfc750P_10-70002752.zip nwrfcsdk $ cd resources/ $ unzip nwrfc750P_10-70002752.zip Archive: nwrfc750P_10-70002752.zip creating: nwrfcsdk/bin/ # 省略 inflating: nwrfcsdk/lib/libsapnwrfc.so inflating: nwrfcsdk/lib/libsapucum.so inflating: SIGNATURE.SMF
これでSAP NetWeaver RFC SDKの準備が完了しました。
このタイミングでresoruces/ディレクトリにいるので、元のディレクトリに戻っておきます。
cd ..
認証情報をSecretsManagerに保管
SAPに接続するための認証情報等をSecretsManagerに登録します。まずはSecretsManagerに設定する値をJSON形式で準備します。(値はダミー値です)
cat <<EOF > ./sap_creds.json { "sid": "ABA", "ashost": "192.0.2.1", "sysnr": "00", "client": "800", "user": "sapuser", "passwd": "password" } EOF
これを以下のコマンドでSecretsMangerに登録します。このサンプルではSecretIDは「serverless/sap/ccms」としています。
AWS_REGION=ap-northeast-1 SECRET_NAME=serverless/sap/ccms aws secretsmanager create-secret --region ${AWS_REGION} --name ${SECRET_NAME} aws secretsmanager put-secret-value --region ${AWS_REGION} --secret-id ${SECRET_NAME} --secret-string file://sap_creds.json
SecretsManagerの画面から確認すると、SAPへの接続情報が登録されているのが確認できます。(値はダミー値です)

Serverless Framework準備
インストール
本構成ではServerless Frameworkをデプロイ利用します。インストールされてない場合はインストールします。
npm install -g serverless
手元の環境は以下のServerlessのバージョンを利用しています。
$ sls --version Framework Core: 3.21.0 Plugin: 6.2.2 SDK: 4.3.2
設定ファイル準備
リポジトリのルートディレクトリに移動して以下のようにconifg.ymlを準備します。値はダミー値です。regionとSecurity GroupとSubnetIDだけ設定すれば動きます。
cat <<EOF > config.yml region: ap-northeast-1 securityGroupIds: - sg-xxxxxx subnetIds: - subnet-xxxxx secretName: serverless/sap/ccms lambdaEnv: extCompany: DUMMY extProduct: DUMMY externalUserName: DUMMY traceLevel: 0 EOF
デプロイ
ここまで準備したら以下のようにsls deployコマンドで環境をデプロイできます。最初はECR等も作るので少し時間がかかります。
$ sls deploy Deploying serverless-sap-ccms to stage dev (ap-northeast-1) ✔ Service deployed to stack serverless-sap-ccms-dev (456s) functions: ccms: serverless-sap-ccms-dev-ccms
Cloudformationを見るとスタックが作成されています。

Lambdaも作成されいますので、こちらを実行してみます。

動作確認
SAP CCMSの画面です、動作確認として以下にあるResponseTimeDialog のメトリクスを取得してみます。246msecですね。

本Lambdaの実行方法ですが、MTEを特定するのに必要なContextとObjectとMTEの情報をLambdaのイベント情報をとして渡すことで、CCMS情報を取得するように書いています。
具体的には上記のResponseTimeDialogを取得する場合は以下のようなイベントを渡します。context_nameは環境によって変わる値になります。
{ "context_name": "vhcalabaci_ABA_00", "object_name": "Dialog", "mte_name": "ResponseTimeDialog" }
まずはAWSのマネジメントコンソールから実行してみます。

246msecが無事に取得できているようです。

Serverless Frameworkから以下のように直接実行することも可能です。
$ sls invoke --function ccms --data '{ "context_name": "vhcalabaci_ABA_00", "object_name": "Dialog", "mte_name": "ResponseTimeDialog"}' { "mte": { "context_name": "vhcalabaci_ABA_00", "object_name": "Dialog", "mte_name": "ResponseTimeDialog" }, "current_value": 246 }
片付け
まずはLambdaやECRの片付けから。ルートディレクトリで以下のコマンドを実行します。
sls remove
SecretsManagerも片付けておきます。
$ aws secretsmanager delete-secret --region ap-northeast-1 --secret-id serverless/sap/ccms
SecretsManagerは削除しても実体が消えるまで猶予期間があります。その間もう一度手順を試してみたくなったらrestore-secretコマンドで復旧することも可能です。
$ aws secretsmanager restore-secret --region ap-northeast-1 --secret-id serverless/sap/ccms
引っかかったポイント
最後に引っかかったポイントを書いておきます。
PyRFCの前提条件
Dockerfileを見ると書いてあります。
まずはOSのパッケージとして以下が必要になります。ネイティブライブラリのビルドに必要なパッケージとなります。
# Install OS dependencies RUN yum update -y \ && yum install -y \ gcc \ gcc-c++
内部的にCythonを利用しており、pipでpyrfcをインストールする場合にCythonが前提で必要です。以下のようにPoetry管理から外して明示的に事前にインストールすることで無事pyrfcをインストールできました。
# Install the function's dependencies using poetry RUN pip install poetry cython RUN poetry config virtualenvs.create false COPY pyproject.toml ${LAMBDA_TASK_ROOT} COPY poetry.lock ${LAMBDA_TASK_ROOT} RUN poetry install
dev_rfc.logの出力制御
SAP Netweaver RFC SDKはdev_rfc.logという名前のログファイルを出力します。このログの出力をそのものを抑制するのは調べた感じではできなそうでした。
Lambda用のベースイメージである「public.ecr.aws/lambda/python」では、ホームディレクトリは「${LAMBDA_TASK_ROOT}」で指定される/var/taskというディレクトリです。Lambda実行時の/var/task は書き込み不可なので、ここにdev_rfc.log を出力しようとしてエラーメッセージが表示されます。(エラーメッセージだけで実際のエラーにはなりませんが、気持ち悪い)
以下のようにRFC_TRACE_DIR をLambdaで書き込み可能な/tmpに吐き出すことで、このエラーを回避できます。
# Set location for dev_rfc.log
ENV RFC_TRACE_DIR /tmp