AWS Service health dashboardのRSSを、Slackに一括登録する


背景

  • Personal Health dashboardがありつつ、やはりService health dashboardの情報は、それはそれとして購読したい。
  • SlackにRSSリーダーがあるけど、1 URLずつ /feed subscribe https://.....rss と実行する必要があり拷問である。複数をベタっと貼ってもエラーになる。どうにか一括登録したい。
  • https://status.aws.amazon.com/rss/all.rss という全部入りがあるけど、使ってないリージョンのまで入ってるので、購読すると無駄にうるさい。また直近15記事しかなく、広域障害発生時は猛烈に流れて使い物にならないことが想定できる。製品ごとリージョンごとRSSで見るしかなさそう
  • ググると手製の東京リージョンOPMLとか見つかるけど、数年前のものだったりする。常に最新のRSSであってほしい

解法

  • https://status.aws.amazon.com/ からRSSのURLを、グローバルサービス、リージョナルサービスにバラして、ほしいリージョンだけにする。CLIで。
  • Slack API から /feed subscribe コマンドを実行して登録する

RSSのURLぜんぶ取ってくる

curlしたものをモゴモゴして取ってきます。

curl -s https://status.aws.amazon.com/ \
| perl -wpl -e 's|\"|\n|g' | grep "/rss/" \
| perl -wpl -e 's|^|https://status.aws.amazon.com|g' \
| sort -u \
>  all.txt

グローバルとリージョナルに分割する

URLリストを眺めると、リージョナルサービスにはリージョン名がURLに含まれており、グローバルサービスはサービス名だけであることがわかります。すっごく雑に、

  • ハイフンが複数個なければグローバルサービス
  • ハイフンが複数個あるならリージョナルサービス

とバラせそうでした。

cat all.txt \
| grep -Ev '.*-.*-.*-' > global-products.txt

cat all.txt \
| grep -E '.*-.*-.*-' > regional-products.txt

最初はハイフンの有無で分けてみたのですが、以下の例外があることがわかり、「ハイフンが複数個の有無」で、としました。

https://status.aws.amazon.com/rss/import-export.rss
https://status.aws.amazon.com/rss/management-console.rss
https://status.aws.amazon.com/rss/s3-us-standard.rss

リージョンごとに分割

せいぜい2 - 3リージョンしか使ってないでしょうから、欲しいリージョンのものだけに絞りたい、なので分割します。

rm -f regional-products.*.txt
cat regional-products.txt \
| rev | awk -F'[.-]' '{print $0 " " $2 "-" $3 "-" $4}' | rev \
| awk '{print "echo " $2 " >> regional-products." $1 ".txt"}' \
| bash

SlackのAPIトークンを発行する

SlackのAPI chat.command を利用するためレガシートークンを用意してください。

このトークンは、トークンの発行者の権限の範囲で、トークンの発行者の名義で、広範にAPIを使えてしまうトークンであるため、厳重に保管してください。

手元にrubyをインストールする

2.6系で最新を選んでおけばいいのではないでしょうか。この後で使う slack-ruby-client も入れておいてください。

brew install rbenv ruby-build
rbenv install 2.6.6
rbenv global 2.6.6
gem install slack-ruby-client

Slackに一括登録するRubyスクリプトを用意する

https://gist.github.com/sasasin/28fbb22d3e40dd8518be5f2f30df5e42 をテキトーな場所に転がしてください。

以下のように動かすことができます。

export SLACK_API_TOKEN="xoxp-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
./slack_slash_command.rb "#general" "/feed" "subscribe https://status.aws.amazon.com/rss/iam.rss"

Slackに一括登録する

これまでの情報を総合して、以下のように実行することで一括登録できます。

export SLACK_API_TOKEN="xoxp-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
export CHANNEL_NAME="#投稿先チャンネル名"
cat global-products.txt \
| xargs -L1 -I XXX ./slack_slash_command.rb "${CHANNEL_NAME}" "/feed" "subscribe "XXX
cat regional-products.ap-northeast-1.txt \
| xargs -L1 -I XXX ./slack_slash_command.rb "${CHANNEL_NAME}" "/feed" "subscribe "XXX
cat regional-products.us-east-1.txt \
| xargs -L1 -I XXX ./slack_slash_command.rb "${CHANNEL_NAME}" "/feed" "subscribe "XXX

CodeBuildで定期実行する

一回やってそれきりではないはず。利用するAWS製品もリージョンも増減していくでしょうから、それなり簡単に自動登録したいでしょう。CodeBuildで定期実行させましょう。

こんなbuildspecです。

version: 0.2

env:
  parameter-store:
    # 格納先のSSMパラメータストア名は好みで
    SLACK_CHANNEL_NAME: "/CodeBuild/SLACK_CHANNEL_NAME"
    SLACK_API_TOKEN: "/CodeBuild/SLACK_API_TOKEN"

phases:
  install:
    commands:
      - gem install slack-ruby-client
      - curl -s -o ./slack_slash_command.rb https://gist.githubusercontent.com/sasasin/28fbb22d3e40dd8518be5f2f30df5e42/raw/0294724cc31abeb2f02b04ac05fd95d28732d37d/slack_slash_command.rb
      - chmod +x slack_slash_command.rb

  build:
    commands:
      - |
        curl -s https://status.aws.amazon.com/ \
        | perl -wpl -e 's|\"|\n|g' | grep "/rss/" \
        | perl -wpl -e 's|^|https://status.aws.amazon.com|g' \
        | sort -u \
        >  all.txt
      - cat all.txt | grep -Ev '.*-.*-.*-' > global-products.txt
      - cat all.txt | grep -E '.*-.*-.*-' > regional-products.txt
      - |
        rm -f regional-products.*.txt
        cat regional-products.txt \
        | rev | awk -F'[.-]' '{print $0 " " $2 "-" $3 "-" $4}' | rev \
        | awk '{print "echo " $2 " >> regional-products." $1 ".txt"}' \
        | bash
      - ls -alF *.txt
      - |
        cat global-products.txt \
            regional-products.ap-northeast-1.txt \
            regional-products.us-east-1.txt \
        | while read FEED_URL; do
            ./slack_slash_command.rb "${SLACK_CHANNEL_NAME}" "/feed" "subscribe ${FEED_URL}"
            sleep 3
        done

  • コンテナイメージは ruby:2.6-buster で動作確認しています
  • チャンネル名やSlackトークンは、SSMパラメータストアなどに入れましょう。 SLACK_CHANNEL_NAME はパブリックチャンネルの場合は #general のように # を付ける必要があります
  • いますぐ使うCodeBuild を参考に、好みの周期で定期実行させます
  • 例として東京とバージニア北部リージョンで動かしてます
  • 当初 sleep 3 は入れずに動かしたら、途中から「お前やりすぎ3秒後にリトライしろ」でコケるようになったので追加してます

参考