CloudWatch – Teams通知連携

SlackからTeamsに移行して久しい弊社では、CloudWatch AlarmやGhost InspectorのSlack通知のためだけにSlackを起動しているような人がいました。

見落としや業務効率の低下を招くので、Teamsに一本化してやろうというお話。
Ghost InspectorのTeams連携についてはGhost Inspector – Teams通知連携を参照。

軽く調べたらWebhookを使えばいいらしい。簡単~~~!!

1. Teamsのコネクタを作成

Slackで言うところのIntegration。

通知を受け取りたいチャネルにて、下記の設定を行う。
通知用のチャネルを作るのが良さそう。

チャネル右上の「・・・」からコネクタを選択
Incoming Webhookを「構成」
適当な名前とアイコンを設定して「作成」
WebhookURLが表示されるのでコピーしておく。

※忘れてしまっても、コネクタ > 構成済み > Incoming Webhook > (構成済みを展開) > 管理 から再度確認できる。

余談

アイコン画像は下記のように6角形に切り抜かれて使用されるため、周囲の余白をいい感じに調整すると気分が良い。

正方形 → アイコン切り抜き 参考画像

2. Teams通知のLambdaを作成

下記のような関数をさっくりと作成。

参考にした記事のほぼそのまま。
コンパクトにしたかったのでいくらか省略し、組み込みのライブラリだけ使うように書き換えた程度。かっこよくはない。

import json
import logging

from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError


HOOK_URL = "(WebhookURLを記載)"

logger = logging.getLogger()
logger.setLevel(logging.INFO)


def lambda_handler(event, context):
    logger.info("Event: " + str(event))
    
    subjet = event['Records'][0]['Sns']['Subject']
    
    message_json = json.loads(event['Records'][0]['Sns']['Message'])
    logger.info("Message: " + str(message_json))

    newStateReason = message_json['NewStateReason']
    newStateValue = message_json['NewStateValue']
    nameSpace = message_json['Trigger']['Namespace']
    metricName = message_json['Trigger']['MetricName']
    alarm_description = message_json['AlarmDescription']

    # Create contents to POST to Microsoft Teams.
    text = [
        newStateReason,
        "\r\n\r\n",
        "**Alarm State:** {0}          **Name Space:**: {1}".format(newStateValue, nameSpace),
        "**Metric:** {0}".format(metricName),
        "\r\n\r\n",
        alarm_description,
        ]

    request_data = {
        'title': subjet,
        'text': '\r\n\r\n'.join(text)
        }

    # POST to Microsoft Teams.
    request = Request(
        HOOK_URL, 
        data=json.dumps(request_data).encode('utf-8'),
        method="POST"
    )

    try:
        with urlopen(request) as response:
            response_body = response.read().decode('utf-8')
            logger.info(response_body)
    except HTTPError as err:
        logger.error(err.code)
    except URLError as err:
        logger.error(err.reason)

3. SNSトピックを作成

既存の通知先を置き換えることになったので、サブスクリプションの置換のみ。

先程のLambda関数用のサブスクリプションを作成

※SNSトピックとの紐付けは、Lambda関数の「トリガー」設定からでも行なえる。(関数の概要 > トリガーを追加 > SNSを選択 > トピックを選択 > [追加])

4. CloudWatch アラームを作成

既存のアラームの通知先を変えただけなので詳細は省略。

アラームのアクションとして通知先に先程のSNSトピックを指定する。

5. 動作確認

適当にしきい値を下げてアラーム状態にしてみると、コネクタ設定をしたチャネルにて、下記のような投稿が確認できた。

実は設定したのが4月なので、そのときのスクショ
(投稿者の名称が手順と異なるのはそのため)

課題

Teamsは現状、Webhookによる投稿でチャネル通知(Slackの@channel的なメンション)が使えないらしく、アラーム通知に気付きにくいという問題がある。

今後に期待……

参考

PHPの実行環境がEC2かローカルかを簡易的に判定する

概要

PHPUnitで自動テストをしていますが、ローカル環境では動かない機能のテストが一部あったため、実行環境を判定してスキップしてやろうって話。

目標

  • 実行環境の判定関数を作りたいので、適当な判定条件を作る。

条件

  • 本番環境とテスト環境ではテストを実行したいが、ローカル環境では特定のテストを実行したくないので、これらを区別する必要がある。
  • 本番環境とテスト環境はAWSのEC2上で動いている。
  • ローカルの開発環境はxamppやらVM+vagrantやらDockerやら各々色々。
  • PHPUnitはコンソールから直接実行する場合もある。

結果

東京リージョンのEC2を判定する例

function is_local() {
    if (strpos(gethostname(), 'ap-northeast-1.compute.internal') === false) {
        return true;
    }
    return false;
}

備考

  • 「アジアパシフィック (東京)」リージョンのEC2インスタンスはhostnameが ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal といった形式になるようで、ローカルの開発環境ではこうはならないため、都合が良いと判断し採用。
  • $_SERVER['HOSTNAME'] は実行条件によってEC2インスタンス上でもNULLになってしまう場合があったため不採用。
  • gethostname() の挙動が安定しないようなことがあれば再考。
  • PHPの実行時にenvを宣言するみたいなことができるらしく、本来はそうした方がスマートなのかなと思うけど今回は見送り。

wp-config.php が反映されない

解決したので記事書きます。
原因は簡単(BOM)だったのですが、見落とす可能性は高そうです。

現象

WordPressの設定ファイルである「wp-config.php」を編集したが、変更内容が反映されない。

試したこと

  1. 適当に検索してみたところ、編集範囲の外に記述していないかなどが出てきたが、今回は関係が無かった。(権限関係でそもそも編集できないなども出てきたが、今回の現象とは無関係)
  2. 自分が編集しているファイル以外のファイルがロードされている可能性を考えて $ find / -name "wp-config.php" したが、他に同一名のファイルはサーバ上に無かった。
  3. 何かしらブラウザのキャッシュが悪さしている可能性を考えてキャッシュを消してページを読み込んだが、変更内容は反映されていなかった。
  4. 公式のリファレンスを参照してみたが、有用な情報はなかった。
  5. Google is GOD 救済を得た。

解決

適当にググってこちらの情報に行き着いた。

原因は、TeraPadで編集して、保存がUTF-8のBOM無じゃなかったから。
BOM無という言葉はないが、UTF-8Nがそれらしい。未確認だけど、試したら解決した。

WordPress wp-config.phpが反映しない | weblogs

vimで適当に編集していたのでBOMとか全く気にしていなかった。
こんなところでもBOMに苦しめられるとは思わなんだ。

vimでBOMの有無を確認したところ、見事にbomが付いていたので消し飛ばして解決。

※vimにて

:set bomb?
> bomb

:set nobomb
:set bomb?
> nobomb

参考: VimでのBOMの取り扱い – Qiita

wp-configの中にUTF-8のBOM無しで保存するようにと、かなりわかりやすい注意書きがあったので、そこが目に入っていれば気がついたかもしれない。

リモートワーク対策ツールメモ

基本的にリモートデスクトップで作業するんだろうなと思いますが、画面共有や情報共有などについてメモっておきます。役に立つかはわかりません。
ファイルの共有はTeamsやSharePointなどで事足りそうですね。

※リモートワーク時に使えるかは未検証です。

※VPN経由(リモートデスクトップで作業中)で使えるかなども未確認です。

画面共有

※画面共有のやり方を説明している記事のリンク

例)
 Teams: 会議中に自分の画面を共有する – Office サポート

 LINE: LINEで画面共有する方法まとめ【iPhone/Android/PC】 | アプリオ

 Discord: 【Discord】画面共有のやり方/音声共有方法も【PC/スマホ対応】 – DigitalNews365

リモートアシスト

nasが壊れたときに某社サポートが使ってたような遠隔操作ツールです。
Google翻訳をチャットツールみたいに使い始めたときは賢いな~と思いました(余談)。

例)
 TeamViwer

共同プログラミング

エディタは各々自由に選んでいるのでちょっと微妙ですが、共同編集機能(プラグイン)というものもあります。
(TeamViwerとか使ってリモートアシストしてしまう方が早いかもしれない)

例)
 Atom: Teletype for Atom

 Eclipse: DocShare_Plugin

 VS Code: Live Share

 PhpStorm: Code With Me

共有ホワイトボード

お絵かきしながら説明したいなんかに便利。とりあえずGoogleのが安牌?
(そういえば知り合いに画面共有しながらペイントとかパワポ(編集画面)で説明しだす猛者おったな)

※この手のツールを使う場合は、ペン型のポインティングデバイス推奨です。
共用ホワイトボードアプリ紹介:
テレワークで使いたいホワイトボードアプリ5選! – スクラムマスダーの日記

【2021年版】オンラインホワイトボードツールおすすめ6選を徹底比較!(無料あり) | NotePM

(2021/05/26 追記)
アカウント登録不要でサクッと使え、14日間ボードが残る「Whiteboard Fox」は良さげでした(他のアカウント不要系使ったことがないだけですが)


MySQL InnoDB AUTO_INCREMENTの上限値周りでの振る舞いを検証

AUTO_INCREMENTの値が型の上限値に達した際の振る舞いが気になったので、いくつか調べてみました。
AUTO_INCREMENTのドキュメントでは情報が足りませんでした。

例えば、一意性さえ確保できれば良いテーブルのidが上限に達した際に、1から順に再度振り直したくなるようなことがあるかもしれません。(アンチパターンの香り)

影響範囲の調査とか調整とかの工数を考えると、明らかにやるべきでない操作ですが、やむを得ない事情がある場合だってあるかもしれません(弊社には今の所ありません。良かった)。そんなときのために、知見をメモしておきます。

前提

  • UNSIGNED INT 型の上限値: 4294967295
  • UNSIGNED INT型のidカラムにAUTO_INCREMENTを指定

検証

idが上限値に達したテーブルに対し、さらにINSERTを実施する

iddata
10hoge
11hoge
4294967294hoge
4294967295hoge
INSERT INTO `id_test_table` (`id`, `data`) VALUES (NULL, 'hoge');
#1062 - '4294967295' は索引 'PRIMARY' で重複しています。

重複エラーが出て、テーブルにデータは入りません。

idを指定してINSERTする

INSERT INTO `id_test_table` (`id`, `data`) VALUES (1, 'hoge');
iddata
1hoge
10hoge
11hoge
4294967294hoge
4294967295hoge

重複が無ければ、問題なくINSERTできます。

この状態で再度INSERTした場合、次に割り当てられるidはなんでしょうか。

INSERT INTO `id_test_table` (`id`, `data`) VALUES (NULL, 'hoge');
#1062 - '4294967295' は索引 'PRIMARY' で重複しています。

AUTO_INCREMENTの値がリセットされるわけではないため、都合よく「2」などにはならず、当然のように重複エラーとなります。
こんな操作で「2」が入ったら、それこそバグの原因になってしまうので幸い。

AUTO_INCREMENTの値をリセットする

それでは、今度はテーブルのauto incrementをリセットしてみましょう。

ALTER TABLE tbl_name AUTO_INCREMENT = value; でリセットできます。

ALTER TABLE id_test_table AUTO_INCREMENT = 2;

テーブル情報から、現状のauto incrementの値を確認します。

SELECT auto_increment FROM information_schema.tables WHERE table_name = 'id_test_table';
auto_increment	4294967295

ダメみたいですね。

データを一部消してAUTO_INCREMENTの値をリセットする

レコードを一部DELETEしました。

iddata
1hoge
10hoge
11hoge

この状態で、auto incrementの値をリセットしてみます。

ALTER TABLE id_test_table AUTO_INCREMENT = 15;
SELECT auto_increment FROM information_schema.tables WHERE table_name = 'id_test_table';
auto_increment	15

この場合は無事「15」になりました。

INSERT INTO `id_test_table` (`id`, `data`) VALUES (NULL, 'hoge');
iddata
1hoge
10hoge
11hoge
15hoge

問題なくINSERTされます。

「指定したidの値より大きい値を持つレコードがある場合、変更できない」という仕様のようです。

15より低い値で入れてみると、やはり更新されません。

ALTER TABLE id_test_table AUTO_INCREMENT = 10;
SELECT auto_increment FROM information_schema.tables WHERE table_name = 'id_test_table';
auto_increment	16

冒頭の「idの採番を1から振り直す」なんてことをしたい場合には、指定したい値以上のidを持つレコードを削除してやる必要がありそうです。とんでもねえなおい。

実際に「idの採番を1から振り直す」ようなケースでは、テーブルにid:1~上限値までのデータが全て残っているような状態は珍しいのではないでしょうか。

つまるところ、
「指定したい値以上のidを持つレコードを削除」は
「テーブルのレコードを全て削除」とほぼ同じ意味になりそうです。

とんでもねえなおい。

結論

テーブルの設計段階で型を十分に検討するべき。

参考