PythonをACMS Apexから呼び出してみる

ACMS Apex 実験室 ～ 実験その１「Pythonと連携」

# はじめに
本記事では、ACMS ApexからPythonのスクリプトを実行する実験を行います。
ACMS Apexの外部アプリを使えばpythonコマンドを起動できるのは試すまでもないことなので、ここでは仮想環境を使って実行できる環境を目指してみます。
Pythonの仮想環境を構築する方法にはいくつかの選択肢がありますので、実際の条件に合わせて適宜工夫していただければと思います。

# 対象読者
Pythonでできることはいろいろありますが、システム間の処理の間にPythonでの処理をしたい方や、PythonでAI、WebAPIを使いたいといったことを考えている、次のようなエンジニアあたりが対象になります。

* Linuxが普通に扱える<BR>
どのレベルを普通というかは賛否両論あると思いますが…<BR>
コマンドラインで操作ができて、この記事に書いてあることが理解できる程度、と考えてください。
* ACMS Apexが操作できる<BR>
エンタープライズ・データ連携基盤 シルバーコース受講者相当の知識があるとよいです。<BR>
本筋から外れるところは説明を端折りますので、各自補完していただけることを期待します。
* Pythonが多少わかる<BR>
仮想環境の構築などは、ある程度自分で調べられることを前提に説明を端折っています。
プログラムの説明も端折ります。

# 注意事項

いわゆる「やってみた」系の記事ですので、無保証、無サポートです。

* ここで構築する環境は動作が保証されたものではありません。<BR>
あくまでお試し程度に「使ってみる」ことを目的とした環境を構築します。
* フリーソフトや評価版を使うので、メーカーサポートはありません。<BR>
自己解決できない場合は、本記事のコメント欄でご相談ください。<BR>
解決できるかどうかはわかりませんが…

# 前提条件
前の記事「[ACMS Apexの検証環境を高速で用意する](https://qiita.com/rytksm/items/bac60927d5b7a58336b7)」で作った環境を使います。

# 環境
前に作った環境に加えて、次のソフトウェアを使用します。

* Python(OSのデフォルトと3.7.3)
* pyenv
* venv

## Pythonの仮想環境について
本記事では、pyenvとvenvでPythonの仮想環境を構成します。
つまり、pyenvで複数のバージョンのPythonを同居させ、venvでプロジェクト毎のパッケージ導入を管理するということです。
ACMS Apexにはアプリケーション連携機能があるので、様々な条件でPythonスクリプトを実行できるように環境を構築しておいたほうが良いです。[^1]
例えば、ある業務から連携するアプリケーションはPython3.5で作成され、すでに実稼働しているとします。このとき、新しい業務に対応しようとしたとき、前提となるライブラリがPython3.5では動かないなどの理由で別のバージョンを選択せざるを得ないといったことはよくある話です。また、システムを統合する際には、たとえPythonそのもののバージョンが同じでも、導入するパッケージやバージョンが異なることもあるでしょう。
こういったことも考慮して、複数の仮想環境を用意することができるようにしておくことをお勧めします。
ここでは仮想環境にvenvを使いましたが、もしPython3.3より前のバージョンを使う可能性があるなら、virtualenvなど他の仮想環境にしましょう。

# 構築手順

まずはteraterm等を使い、acmsユーザでログインしてください。

## 必要なパッケージをインストールする
いろいろと必要なパッケージをあらかじめインストールしておきます。

``` shell
sudo yum -y install git wget gcc zlib-devel bzip2 bzip2-devel readline readline-devel sqlite sqlite-devel openssl openssl-devel libffi-devel
```

## pyenvをインストールする
次の手順で操作します。

``` shell
# 現状のPythonのバージョンを確認
python --version
# ホームディレクトリに移動
cd
# pyenvをインストール
curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash
vi ~/.bashrc
-----最後に追加
# settings for pyenv
export PATH="/home/acms/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
-----
source ~/.bashrc
pyenv -v
```

## 仮想環境を作る
まずはこの環境で使うPython3.7.3をインストールします。

``` shell
# 一応、何もインストールされていないのを見ておく
pyenv versions
# 一応、最新バージョンを見ておく
pyenv install --list
# Python3.7.3をインストールする
pyenv install 3.7.3
# インストールされたことを確認する
pyenv versions
# Pythonのバージョンを確認する(まだOSデフォルトのPythonが使われているはず)
python --version 
```

次に仮想環境を作成し、必要なパッケージを追加します。

``` shell
# 仮想環境格納用ディレクトリ作成
mkdir pyvenv
# プロジェクトファイル格納用ディレクトリ作成
mkdir -p project/test1
cd project/test1
# このディレクトリ配下で使用するPythonのバージョンを指定
pyenv local 3.7.3
python --version
# 仮想環境を作成
python -m venv /home/acms/pyvenv/test1
# 作成した仮想環境に切り替え
source /home/acms/pyvenv/test1/bin/activate
# pipが古いので最新版に更新
pip install --upgrade pip
# 必要なライブラリをインストール
pip install pandas scipy
```

ここまでで、仮想環境"pyvenv/test1"の出来上がりです。
プロジェクト用として"project/test1"も作りました。仮想環境のディレクトリを別にしておくと、git等でソースコードを管理する場合のパッケージが入らないので容量が節約できます。
次に、簡単に動作を確認してみましょう。
まずはデータファイルを用意します。

``` shell
vi values.csv
```
``` csv:values.csv
count,result
1,9.7
2,10.2
3,9.4
4,10.1
5,10.1
```

CSVファイルを読み出して各種統計値を求めるPythonスクリプトを作ります。[^2]

``` shell
vi calcstat.py
```

``` python:calcstat.py
import sys
import pandas as pd
import numpy as np
from scipy import stats
np.set_printoptions(precision=3)

# CSVからデータを読み出す
csv_data = pd.read_csv(filepath_or_buffer=sys.argv[1])
print(csv_data.size)
print(csv_data)
# NumPyのArrayに変換
x = np.array(csv_data.result.values.tolist())

# 標本数
n = x.shape[0]
# 平均
xbar = np.mean(x, axis=0)
# 分散
v = np.var(x, axis=0, ddof=1)
# 標準偏差
s = np.std(x, axis=0, ddof=1)
# 標準得点
z = stats.zscore(x, axis=0, ddof=1)
print('result A')
print('average %s' % xbar)
print('variance %s' % v)
print('stdev %s' % s)
print('z score')
print(z)
```

実際に動かした出力は次のようになります。

``` shell
(test1) [acms@apex-01-mst test1]$ python ./calcstat.py
10
   count  result
0      1     9.7
1      2    10.2
2      3     9.4
3      4    10.1
4      5    10.1
result A
average 9.9
variance 0.1149999999999998
stdev 0.33911649915626313
z score
[-0.59   0.885 -1.474  0.59   0.59 ]
(test1) [acms@apex-01-mst test1]$
```

うまく動かない場合、仮想環境に切り替わっているか確認してみてください。仮想環境に切り替わっている場合、プロンプトに"(仮想環境名)"が表示されているはずです。
仮想環境に切り替えるには```source /home/acms/pyvenv/test1/bin/activate```を実行します。

動作が確認出来たら、念のため仮想環境から抜けておきます。

``` shell
deactivate
```

# ACMS ApexとPythonの連携
Pythonを実行することができるようになったので、ACMS Apexから呼び出します。

## ACMS Apex連携用スクリプトの作成
先ほど作ったPythonスクリプトを呼び出すシェルスクリプトを作ります。

``` shell
vi calcstat.sh
chmod +x calcstat.sh
```

``` shell:calcstat.sh
#!/bin/sh
# calc statistics
# $1 : csv file name
# $2 : result file name

# pythonコマンドの標準出力をリダイレクトする一時ファイルをカレントディレクトリに作る
wd=`pwd`
tmpfile=`mktemp -p $wd`
trap "rm -f $tmpfile" EXIT

# 仮想環境に切り替えてpythonスクリプトを実行して仮想環境から抜ける
source /home/acms/pyvenv/test1/bin/activate
python /home/acms/project/test1/calcstat.py $1 >> $tmpfile
deactivate

# 処理結果ファイルに出力パラメータ値を設定する
echo average=`cat $tmpfile | grep 'average' | cut -f 2 -d ' '` >> $2
echo variance=`cat $tmpfile | grep 'variance' | cut -f 2 -d ' '` >> $2
echo stdev=`cat $tmpfile | grep 'stdev' | cut -f 2 -d ' '` >> $2
echo section=end >> $2
```

## 各種設定と実行
ACMS Apexに実行用の各種設定をします。
業務グループ等は前回作成したものを流用します。

###管理画面にログイン
母艦のブラウザで下記のURLを開く
http://192.168.249.20:8080/login.html

|項目|値|
|:---|:---|
|テナント|(入力しない)|
|オペレーターID|OP_TEST|
|パスワード|<パスワード>|

###アプリケーション(外部アプリ)を作成する

[▼マスター] - [▼アプリケーション] - [アプリケーション]
[新規作成]

|項目|値|
|:---|:---|
|業務グループ|WG_TEST|
|アプリケーション名|Python呼び出し|
|アプリケーションタイプ|外部アプリ実行|
|貸出|しない|
|アプリケーションポートグループ|APG_TEST|
|実行モジュールパス|/home/acms/project/test1/calcstat.sh|

外部アプリ入力パラメーター
[新規作成] ×2

|パラメーター名|必須区分|パラメーター値|デフォルト値|オプション文字列|オプション文字列の出力条件|オプション文字列の連結|
|:--|:--|:--|:--|:--|:--|:--|
|infile|必須|%input_file%||値があったらオプション文字列と値を出力|しない|
|resultfile|必須|%result_file%||値があったらオプション文字列と値を出力|しない|

[▼ アプリ実行結果情報]

|項目|値|
|:---|:---|
|データ出力|しない|

出力パラメーター
[新規作成] ×3

|パラメーター名|必須区分|
|:--|:--|
|average|必須|
|variance|必須|
|stdev|必須|

[保存]
[OK]
[アクション▼] - [開始]

###外部アプリ実行フローを作成する
[▼マスター] - [▼アプリケーション] - [フロー]
[新規作成]

|項目|値|
|:---|:---|
|業務グループ|WG_TEST|
|フロー名|Python呼び出し|
|貸出|しない|
|アプリケーションポートグループ|APG_TEST|

フロー入力パラメーターには何も設定しない
[フローエディター]をクリック
画面右のパレットのドロップダウンリストで[アプリケーションジョブ]を選択
[外部アプリ実行]の上でマウスの左ボタンを押し、そのまま[START]の横のマスまで移動して離す
画面右のパレットのドロップダウンリストで[コントロールジョブ]を選択
[正常終了]の上でマウスの左ボタンを押し、そのまま[EXTERNAL_APL_E...]の横のマスまで移動して離す
[START]の右側の丸でマウスの左ボタンを押し、そのまま[EXTERNAL_APL_E...]の左側の丸まで移動して離す
[EXTERNAL_APL_E...]の右側の丸でマウスの左ボタンを押し、そのまま[NORMAL_END]の左側の丸まで移動して離す
[EXTERNAL_APL_E...]の文字をクリック

|項目|値|
|:---|:---|
|フロー名|Python呼び出し|
|ジョブ名|Python呼び出し|
|アプリケーション名|Python呼び出し|
[OK]

(操作後のフロー図)
![Python呼び出しフロー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344679/b09c3908-a69f-5257-979a-385d07a3038f.png)

[保存]
[OK]
[アクション▼] - [開始]

###アプリケーションを実行する
母艦側でテスト用のファイルを用意する

```text:values.csv
count,result
1,9.7
2,10.2
3,9.4
4,10.1
5,10.1
```

[▼データ操作] - [ロード（フロー）]

|項目|値|
|:---|:---|
|業務グループ|WG_TEST|
|フロー名|Python呼び出し|
|データファイル|[ファイル選択]をクリックしてvalues.csvを指定|
|パラメーター|(空白)|
|予約登録|□する(チェックしない)|
|処理予定日時|(空白)|
|強制登録|□する(チェックしない)|

[実行]

###実行結果を確認する
[▼状況] - [トップフロー]

|登録日時|簡易遷移状況|トップフロータスク状態|
|:---|:---|:---|
|(時刻)|:load=>:Python呼び出し|完了|

[▼状況] - [タスク]

|登録日時|業務グループ|ターゲットのID|ターゲットのID|ターゲットのID|ターゲットのID|
|:---|:---|:---|:---|:---|:---|
|(時刻)|WG_PythonTest|Python呼び出し||完了||
|(時刻)|WG_PythonTest|Python呼び出し||完了||
|(時刻)|WG_PythonTest|load||完了||

Python呼び出しの右の[詳細]をクリック
[▶実行結果]をクリック
出力パラメータを確認

|キー|値|
|:---|:---|
|average|9.9|
|stdev|0.33911649915626313|
|variance|0.1149999999999998|

お疲れさまでした。以上でACMS ApexからPythonスクリプトを実行する実験は完了です。
最後まで読んでいただき、ありがとうございました。

[^1]: pyenvを使うと、.pyenv/versionsの下にバージョンごとのディレクトリが作られて、その下にインストールしたパッケージが置かれます。従って、Pythonのバージョンが同じでパッケージのバージョンが異なる環境が作れません。このような環境が必要な場合に普通どうするのかわかりません。別のユーザを作ってpyenvをインストールするとかでしょうか？ご存じの方、教えてください。
[^2]: このスクリプトが何をやっているかは、次のURLを見るとよくわかります！<br>[データ解析ならPythonが最高！第3回](https://www.ydc.co.jp/column/0002/20180119-1.html)