AWS
oracle
nodejs
lambda

AWS Lambda (Node.js-v4.3.2)からOracleに接続する(ORA-21561への対応)

More than 1 year has passed since last update.

ORA-21561の部分に関して2016/11/7に追記しています。

AWS Lambda(in VPC)からOracleに接続する時に数時間ハマったので記録として残しておきます

気付いてしまえばたいしたことないんですが、途中にある「ORA-21561: OID generation failed」のへの対応で全作業時間の9割程度なやんでいました


AWS Lambda (Node.js-v4.3.2)の実行環境に近いEC2環境の構築

AWS Lambda (Node.js-v4.3.2)の実行環境に近いEC2環境の構築を参考にしてください


Oracle InstantClientのインストール

Instant Client Downloads for Linux x86-64(要ログイン)からrpmをダウンロードします

必要なものは以下の2つです

oracle-instantclient12.1-basic-12.1.0.2.0-1.x86_64.rpm

oracle-instantclient12.1-devel-12.1.0.2.0-1.x86_64.rpm

ダウンロードしたらインストールします


terminal

$ sudo rpm -i oracle-instantclient12.1-basic-12.1.0.2.0-1.x86_64.rpm oracle-instantclient12.1-devel-12.1.0.2.0-1.x86_64.rpm



nodejsからOracleへの接続


接続するためのコードを書く


プロジェクトの作成とoracledbのインストール


terminal

$ mkdir oracletest

$ cd oracletest
$ npm init
$ npm install oracledb --save


テスト用コードの作成

process.env.NODE_ORACLEDB_* に関しては適宜書き換え・環境変数として渡すなどしてください

※接続用の環境変数は公式のテストコードを参考にしてます


index.js

'use strict';

process.env.NODE_ORACLEDB_USER='user'
process.env.NODE_ORACLEDB_PASSWORD='password'
process.env.NODE_ORACLEDB_CONNECTIONSTRING='hostname:port/servicename'

const oracledb = require('oracledb');

exports.handler = function(event, context, callback) {
console.log('start');
oracledb.getConnection({
user : process.env.NODE_ORACLEDB_USER,
password : process.env.NODE_ORACLEDB_PASSWORD,
connectString : process.env.NODE_ORACLEDB_CONNECTIONSTRING,
},
function(err, connection) {
if (err) { callback(err); return; }
console.log('connected');
connection.execute("SELECT * FROM [table] WHERE ROWNUM < 10", [], function(err, result) {
if (err) { callback(err); return; }
callback(null, result.rows);
});
});
}



test.js

'use strict';

const t = require('./index');
t.handler({}, {}, function(error, result){
console.log(error);
console.log(result);
});



実行


terminal

$ node test.js

start
[Error: ORA-21561: OID generation failed
]
undefined


ORA-21561: OID generation failedへの対応

2016/11/07追記 ここから

その後動作を確認したりいろいろしていたところ、「DHCP Options Sets」の設定の問題だと気付きました。

VPC内で独自でDNSサーバーを構築している関係で、デフォルトで設定されているはずの「domain-name = ap-northeast-1.compute.internal」を解除していたようです。

domain-nameを追加した設定を作成し、DHCP Options setに設定したところ、LOCALDOMAINの設定なしで動作することを確認できました。

2016/11/07追記 ここまで

ぐぐるとわかりますが、/etc/hostsを書き換えるのが標準的な対応のようです

今回は、AWS Lambdaのため設定ファイルに触れないのでどうしたらいいのか悩みました

問題は自ホストのホスト名が引けないことが原因なので以下の対応を行いました


  • VPCのDNS Hostnamesを有効してVPCローカルなドメインを自ホストに紐付ける

  • 環境変数(LOCALDOMAIN)を利用して検索対象のドメインを設定、上記のドメインを引けるようにする

LOCALDOMAIN='ap-northeast-1.compute.internal'

※ ap-northeast-1の部分はVPCのリージョンによって切り分ける必要があります

AWS Lambdaの環境変数を使えばリージョンごとの切り替えは自動にできそうです

コードはこのようになりました(3行目が追加されただけ)


index.js

'use strict';

process.env.LOCALDOMAIN='ap-northeast-1.compute.internal';
process.env.NODE_ORACLEDB_USER='user'
process.env.NODE_ORACLEDB_PASSWORD='password'
process.env.NODE_ORACLEDB_CONNECTIONSTRING='hostname:port/servicename'

const oracledb = require('oracledb');

exports.handler = function(event, context, callback) {
console.log('start');
oracledb.getConnection({
user : process.env.NODE_ORACLEDB_USER,
password : process.env.NODE_ORACLEDB_PASSWORD,
connectString : process.env.NODE_ORACLEDB_CONNECTIONSTRING,
},
function(err, connection) {
if (err) { callback(err); return; }
console.log('connected');
connection.execute("SELECT * FROM [table] WHERE ROWNUM < 10", [], function(err, result) {
if (err) { callback(err); return; }
callback(null, result.rows);
});
});
}



再実行


terminal

$ node test.js

start
connected
null
[ [ 1, 2, 3], [ 3, 4, 5] ]


Lambdaへのアップロード

まずはアップロード用にzipアーカイブを作成します


terminal

zip -r oracletest.zip package.json index.js node_modules/



実行結果

アップロードして実行すると以下のようなエラーが発生しました


LogOutput

START RequestId: c4365deb-89fc-11e6-a186-f96f2fe34754 Version: $LATEST

2016-10-04T06:35:52.219Z c4365deb-89fc-11e6-a186-f96f2fe34754 start
2016-10-04T06:35:52.357Z c4365deb-89fc-11e6-a186-f96f2fe34754 Error: libclntsh.so.12.1: cannot open shared object file: No such file or directory
at Error (native)
at Object.Module._extensions..node (module.js:434:18)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Module.require (module.js:353:17)
at require (internal/module.js:12:17)
at Object.<anonymous> (/var/task/node_modules/oracledb/lib/oracledb.js:35:19)
at Module._compile (module.js:409:26)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
END RequestId: c4365deb-89fc-11e6-a186-f96f2fe34754
REPORT RequestId: c4365deb-89fc-11e6-a186-f96f2fe34754 Duration: 187.52 ms Billed Duration: 200 ms Memory Size: 128 MB Max Memory Used: 15 MB
Process exited before completing request


OracleのSharedObjectのアップロード

アーカイブにsoファイルを含んでいないためだと思われるので、必要そうなものをピックアップして一緒にzipします


terminal

mkdir lib

cp /usr/lib/oracle/12.1/client64/lib/libclntsh.so.12.1 ./lib/
cp /usr/lib/oracle/12.1/client64/lib/libclntshcore.so.12.1 ./lib/
cp /usr/lib/oracle/12.1/client64/lib/libipc1.so ./lib/
cp /usr/lib/oracle/12.1/client64/lib/libmql1.so ./lib/
cp /usr/lib/oracle/12.1/client64/lib/libnnz12.so ./lib/
cp /usr/lib/oracle/12.1/client64/lib/libocci.so ./lib/
cp /usr/lib/oracle/12.1/client64/lib/libociei.so ./lib/
cp /usr/lib/oracle/12.1/client64/lib/libons.so ./lib/
cp /lib64/libaio.so.1 ./lib/

AWS Lambdaの環境変数を見るとわかりますが、LD_LIBRARY_PATHにプロジェクトのlibディレクトリが含まれているようなのでsoファイルをlibディレクトリ以下にコピーしています


Lambdaへの再アップロード

再アップロード用にzipファイルを作成します。


terminal

zip -r oracletest.zip package.json index.js node_modules/ lib/


最初のアップロードでは直接AWS Lambdaにアップロードできましたが、今回はsoファイルのを含むため、直接アップロード可能な50MBを超えています

そのため、今回はzipファイルをs3にアップロードし、AWS Lambda側ではそのリンクを指定してアップロードします


再実行結果

以上の対応で問題なくAWS Lambda(nodejs)からOracleへの接続ができるようになりました。

※ 再実行で出ていた取得したレコードはログではなく、AWS Lambdaの実行結果として返却されています


LogOutput

START RequestId: d6e7bac8-8a01-11e6-8fbc-1b17ce22866f Version: $LATEST

2016-10-04T07:12:01.578Z d6e7bac8-8a01-11e6-8fbc-1b17ce22866f start
2016-10-04T07:12:01.938Z d6e7bac8-8a01-11e6-8fbc-1b17ce22866f connected
END RequestId: d6e7bac8-8a01-11e6-8fbc-1b17ce22866f
REPORT RequestId: d6e7bac8-8a01-11e6-8fbc-1b17ce22866f Duration: 389.55 ms Billed Duration: 400 ms