Azure Database for MySQLにAzure Functionsから接続して操作する。

クイック スタート:Node.js を使用して Azure Database for MySQL に接続してデータを照会する
を少しアレンジしてAzure Functionsから使用するようにしてみる。

https://docs.microsoft.com/ja-jp/azure/mysql/single-server/connect-nodejs

portalからデータベースの作成

MySQLとリソース名で検索すれば出てくるので、以下の画面から作成をしていきます。

検証用なので一番安いやつでやっていきます。
構成だけ載せておきます。

データベースの追加

初期状態でこのようなデータベースが作成されています。

quickstartdbというデータベースを作成します。

接続の詳細を記録しておきます。
local.settings.jsonに書いてenvで使えるようにします。

SQL_HOST
SQL_USER
SQL_PASSWORD
としておきます。
これらに上記情報を書き込みます。

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "AzureWebJobsStorage": "",
    "STORAGE_CONNECTION_STRING": "",
    "SQL_HOST": "",
    "SQL_USER": "",
    "SQL_PASSWORD": ""
  }
}

操作

func newして新しいファンクションを作っておく。

npm install –save mysql
npm install –save @types/mysql

MySQLReadSample/index.tsの内容は以下

import { AzureFunction, Context, HttpRequest } from "@azure/functions";
import * as mysql from "mysql";
import * as fs from "fs";

const httpTrigger: AzureFunction = async function (
  context: Context,
  req: HttpRequest
): Promise<void> {
  const config = {
    host: process.env.SQL_HOST || "",
    user: process.env.SQL_USER || "",
    password: process.env.SQL_PASSWORD || "",
    database: "quickstartdb",
    port: 3306,
    ssl: {
      rejectUnauthorized: true,
      ca: fs.readFileSync("./BaltimoreCyberTrustRoot.crt.pem", "utf8"),
    },
  };

  console.log(config.host);
  console.log(config.user);
  console.log(config.password);
  console.log(config.ssl.ca);
  const conn = mysql.createConnection(config);

  conn.connect(function (err) {
    if (err) {
      console.log("!!! Cannot connect !!! Error:");
      throw err;
    } else {
      console.log("Connection established.");
      queryDatabase();
    }
  });

  function queryDatabase() {
    conn.query(
      "DROP TABLE IF EXISTS inventory;",
      function (err, results, fields) {
        if (err) throw err;
        console.log("Dropped inventory table if existed.");
      }
    );
    conn.query(
      "CREATE TABLE inventory (id serial PRIMARY KEY, name VARCHAR(50), quantity INTEGER);",
      function (err, results, fields) {
        if (err) throw err;
        console.log("Created inventory table.");
      }
    );
    conn.query(
      "INSERT INTO inventory (name, quantity) VALUES (?, ?);",
      ["banana6", 150],
      function (err, results, fields) {
        if (err) throw err;
        else console.log("Inserted " + results.affectedRows + " row(s).");
      }
    );
    conn.query(
      "INSERT INTO inventory (name, quantity) VALUES (?, ?);",
      ["orange", 154],
      function (err, results, fields) {
        if (err) throw err;
        console.log("Inserted " + results.affectedRows + " row(s).");
      }
    );
    conn.query(
      "INSERT INTO inventory (name, quantity) VALUES (?, ?);",
      ["apple", 100],
      function (err, results, fields) {
        if (err) throw err;
        console.log("Inserted " + results.affectedRows + " row(s).");
      }
    );
    conn.end(function (err) {
      if (err) throw err;
      else console.log("Done.");
    });
  }
};

export default httpTrigger;

上記コードを実行するとコネクション確立時にエラーが出ました。

[start:*func] [2022-07-25T05:49:41.312Z] !!! Cannot connect !!! Error:
[start:*func] [2022-07-25T05:49:41.314Z] [error] Worker 28c4231e-8745-4c3e-8f15-6f93021f9d15 uncaught exception (learn more: https://go.microsoft.com/fwlink/?linkid=2097909 ): Error: self signed certificate in certificate chain     at TLSSocket.<anonymous> (/Users/takumi/Documents/src/private/azure/functions/azfunc-blob-sample/node_modules/mysql/lib/Connection.js:317:48)     at TLSSocket.emit (node:events:527:28)     at TLSSocket._finishInit (node:_tls_wrap:946:8)     at TLSWrap.ssl.onhandshakedone (node:_tls_wrap:727:12)     at TLSWrap.callbackTrampoline (node:internal/async_hooks:130:17)     --------------------     at Protocol._enqueue (/Users/takumi/Documents/src/private/azure/functions/azfunc-blob-sample/node_modules/mysql/lib/protocol/Protocol.js:144:48)     at Protocol.handshake (/Users/takumi/Documents/src/private/azure/functions/azfunc-blob-sample/node_modules/mysql/lib/protocol/Protocol.js:51:23)     at Connection.connect (/Users/takumi/Documents/src/private/azure/functions/azfunc-blob-sample/node_modules/mysql/lib/Connection.js:116:18)     at Object.<anonymous> (/Users/takumi/Documents/src/private/azure/functions/azfunc-blob-sample/dist/MySQLReadSample/index.js:25:14)     at Generator.next (<anonymous>)     at /Users/takumi/Documents/src/private/azure/functions/azfunc-blob-sample/dist/MySQLReadSample/index.js:8:71     at new Promise (<anonymous>)     at __awaiter (/Users/takumi/Documents/src/private/azure/functions/azfunc-blob-sample/dist/MySQLReadSample/index.js:4:12)     at Object.httpTrigger [as default] (/Users/takumi/Documents/src/private/azure/functions/azfunc-blob-sample/dist/MySQLReadSample/index.js:23:12)     at e (/opt/homebrew/Cellar/azure-functions-core-tools@4/4.0.4544/workers/node/dist/src/worker-bundle.js:2:299123)

SSLの証明書が間違っているのが原因でした。

ここのドキュメントに書いてある以下部分からダウンロードした証明書は一体なんだったんだろう。。これのせいでだいぶハマった。

結局、必要な証明書は以下の証明書でした。

DataGridでデータ確認

Data SourceでMySQLを選択します。

Portalの接続の詳細で記録しておいた接続情報を入力します。

SSL証明書を選択します。

テーブルの中身を確認することができました。