Display Nameが設定されていないとBOTの名前になってしまうバグが有った。
毎回Display Nameを設定してねっていうのが面倒になったし、 そもそも設定しなくても出るようにしてたはずだったのだがそうなっていなかったので修正した。
これでDisplay Nameが設定されてなくてもユーザ名が出るようになった。
あー、Docker imageのダイエットしたいな・・・
Display Nameが設定されていないとBOTの名前になってしまうバグが有った。
毎回Display Nameを設定してねっていうのが面倒になったし、 そもそも設定しなくても出るようにしてたはずだったのだがそうなっていなかったので修正した。
これでDisplay Nameが設定されてなくてもユーザ名が出るようになった。
あー、Docker imageのダイエットしたいな・・・
2019/2/16 22:42 ながらに追記
世の中の子持ちエンジニアの人たちがどうやって家事をこなしながら勉強やアウトプットしているのかを知りたい。
— まひと / Mahito (@Mahito) 2019年2月14日
続々とコメントが寄せられているのでとりあえず昼休みにまとめてみた。
こういう勉強会もあるらしい
来てるコメントの中ではまだこれぐらいしかまだやってないのでもう少しいろいろやってみようと思う。
Linuxは ip
コマンドになったのにMacはifconfigだったりするのでなかなか ip
に慣れないところ、知り合いに以下のツールを教えてもらった。
% /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" % brew install iproute2mac % ip a lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384 inet 127.0.0.1/8 lo0 inet6 ::1/128 inet6 fe80::1/64 scopeid 0x1 ...
これでMacでも ip
コマンドが使える様になるのでようやく自分の中で ip
コマンドが根付きそうである。
なんかタイトルのエラーが出た。
Error 1298: Unknown or incorrect time zone: 'UTC'
ググったところ簡単に解決策が見つかった。
以下のコマンドで解決できるらしい。
$ mysql_tzinfo_to_sql /usr/share/zoneinfo/|sudo mysql -u root mysql
MySQL :: MySQL 5.6 リファレンスマニュアル :: 4.4.6 mysql_tzinfo_to_sql — タイムゾーンテーブルのロード
この記事はSlack Advent Calendar 2018の7日目の記事です。
(8日目を書いた後に7日目が空いていたので書くことにしたため日付を前後して書いております)
800人近い人がワイワイしているSlackコミュニティに所属しているのだが、 昨年まで年間の発言数ランキングなどを作ってくれていた人がいなくなったこともあり、 今年の発言ランキングをどうしようかと考えていたが、 自分でつくろう、なんなら週間ランキングも出してしまおうと思い作ることにした。
まずは1週間の発言ランキングを毎週月曜日の9時に #general にBOTがPostすること。
Cloud FunctionsからBigQueryに転送するために利用するトピックを作成
SlackのEvent APIから送られてくるデータをCloud Pub/Subに送るためのFunctionを作成。
今回はPythonを選択。
from flask import make_response from google.cloud import pubsub_v1 import os import json def _event_handler(data, event_type, subtype=None): if event_type == 'message' and subtype == None: publisher = pubsub_v1.PublisherClient() topic_name = os.environ['TOPIC_NAME'] payload = { 'channel': data['channel'], 'user': data['user'], 'ts': data['ts'], } publisher.publish(topic_name, json.dumps(payload).encode('utf-8')) return make_response('OK', 200) def get_slack_event(request): slack_event = request.get_json() if 'challenge' in slack_event: return slack_event.get("challenge") if "event" in slack_event: event = slack_event.get("event") event_type = event.get("type") subtype = event.get("subtype") return _event_handler(event, event_type, subtype) return make_response("[NO EVENT IN SLACK REQUEST] These are not the droids\ you're looking for.", 404, {"X-Slack-No-Retry": 1})
flask google-cloud-pubsub
Event SubscriptionsのRequest URL に対して3で作成したCloud Functionsのアクセス先を設定。
今回はTimestamp, Channel ID, User IDを取得することにしているのでこの3つを設定。
次に設定するDataflowで利用するためのディレクトリを作成
BigQueryでデータが取れることを確認。
Query
SELECT user, count(ts) as post FROM `table_name` group by user order by post desc LIMIT 10
Cloud Schedulerから起動するCloud Functionsを設定
今回は user_weekly_post_count
という名前で作成
BigQueryにはユーザIDしか入っていないのでこちらでusers.infoから名前を取得しています。
import json import os from datetime import date, timedelta from flask import make_response from google.cloud import bigquery from slackclient import SlackClient def create_query_string(): query_string = """ SELECT user, count(ts) as post FROM `cloudtu-dev-02962067.ogura_bigdata_counter.messages` where TIMESTAMP('{} 00:00:00') <= ts and ts < TIMESTAMP('{} 00:00:00') group by user order by post desc LIMIT 10""" today = date.today() start = (today - timedelta(days=8)).isoformat() end = (today - timedelta(days=1)).isoformat() return (start, end, query_string.format(table_name, start, end)) def query_user_weekly_post_count(request): request_json = request.get_json() if not (request_json and 'key' in request_json): return make_response("Authentication error", 403) client = bigquery.Client() start, end, query = create_query_string() query_job = client.query(query) results = query_job.result() # Waits for job to complete. slack_token = os.environ["SLACK_API_TOKEN"] key = os.environ["KEY"] sc = SlackClient(slack_token) result = '1週間({}~{})のPost数ランキング\n'.format(start, end) rank = 0 for row in results: user = sc.api_call( "users.info", user=row.user ) user_name = user["user"]["name"] rank += 1 result += '{} : {} ({} posts)\n'.format(rank, user_name, row.post) sc.api_call( "chat.postMessage", channel="general", text=result ) return make_response(result, 200)
flask google-cloud-bigquery slackclient
先月11月にCloud Schedulerというスケーラブルなcronのサービスが出ていたのでGAEなどを使わずCloud SchedulerからCloud Functionsが多々けるのではないかと思い試してみた。
なお、Cloud Schedulerはベータサービスということもあってか のWeb GUIではBodyの設定をしてもうまく反映されないことがわかったので、CLIから操作した。
コードは以下の通りで、URIとmessage-bodyは各自で設定が必要。
#!/bin/bash gcloud beta scheduler jobs create http user_weekly_post_ranking \ --schedule="0 9 * * 1" \ --uri="https://asia-northeast1-$PROJECT_ID.cloudfunctions.net/user_weekly_post_count" \ --time-zone="Asia/Tokyo" \ --headers="Content-Type=application/json" \ --message-body="{\"key\":\"$KEY\"}"
Cloud Schedulerに「Run now」のボタンがあるので押して動作を確認。
SlackのEvent APIとGCPのサービスを利用することで簡単にSlackデータを蓄積を実現し、また定期的にSlackに統計データを通知する事が可能になりました。
ただ、Dataflowは利用は無料枠がなく使い始めると即お金がかかるのでもう少し安くするためにはCloud FunctionsからストリームでBigQueryにデータを入れる or 一時的に何処かに蓄積したものをBigQueryに投入するなどの工夫が必要になってくると思います。なので、また何か改善した際はブログに書きたいと思います。
この記事はSlack Advent Calendar 2018の8日目の記事です。
レポジトリ
とあるグループ会社に所属するエンジニア有志のSlackがあり、 グループ会社を卒業するとそのSlackチームも卒業し、OB/OGのSlackチームに移動する決まりになっている。
しかしながら、卒業した人から「困ったときに聞ける人がいるのが良かった」や「情報交換の機会が減った」などという声が上がっていたため、なにか方法がないかと検討したが
私「あるWorkspaceの特定のチャンネルにだけ別Workspaceの人達を入れたいな!」
Slack「できるよ!お金払えば!!」
払えるか!!!
というわけで、無料で有料相当の機能を実現すべくSlack APIを使ったメッセージ転送に思い至る。
「あるSlackチームの特定のチャンネルで発言したものが、別のチームの同じチャンネルに転送されて会話ができる」
これだけです。
某Slackチームには #blackhole という発言が一定時間で消えていく人気チャンネルがあるので、2点間をつなぐ、つまりwormholeだなと安直な感じで名前をつけてみた。なおwikipediaで見ても大体あってる。
ワームホール (wormhole) は、時空構造の位相幾何学として考えうる構造の一つで、時空のある一点から別の離れた一点へと直結する空間領域でトンネルのような抜け道である。 ワームホール - Wikipedia
ただ、2点間ではなく複数Slackチームがつながるような設計にしてあったりする。
最初期の実装は以下を使って実装していた
このときのメッセージ転送の設計こうなっていたらしい
雑な発表資料
レポジトリ
当初はBOTの名前とアイコンで転送していたのだが、postMessage APIにユーザ名やアイコンを指定できることがわかったので、発言したユーザの名前とアイコンを使うようにしたことで一気に使いやすくなった。 そして当初うまく動いているように見えたのだが、数日ごとにRabbitMQのプロセスが張り付いて再起動を余儀なくされることに。。。
RabbitMQなんて捨ててやる!時代はマネージドなメッセージングサービスだという思いにいたりCloudnを捨ててマネージドなメッセージングサービスかつ無料で使えそうなGCPにお引越しをして実装2に移行。
GCP上で以下を使って実装
Githubのレポジトリを更新するとCloud Buildが動いてContainer Registryにコンテナを登録してくれるように。 RTM APIで受けたメッセージをCloud PubSubにPublishし、wormholeとして接続される側がそれをSubscribeする。 Cloud Datastoreでメタデータを管理し、Postされたメッセージが更新、削除された際にその変更削除を転送先に伝搬させる際に使われる。 だいたい$1/月ぐらいで運用できている。
これはかなり安定して動かせていたものの、やはり時おりHubotが謎のエラーで落ちる。 あとCofeeScriptで書いていたので書きづらい。 毎度コンテナを復旧させるのが面倒なので、リクエストに応じて処理をするEvent drivenなCloud Functionsのほうが良いのではと思い実装3を検討
当時はまだCloud FunctionsにPythonが出てきていなかったのでNodeで書いてみるものの、 Functionごとの環境変数の設定や同じ関数名が動かせない(といううろ覚えの記憶)と、 やりたいことができないのでCoud Functionsを断念。(コードもレポジトリ管理する前に見切った)
結果として自分が得意なRubyにしたほうが一から実装してもあとの機能追加がきっと楽だと思って実装そのものを乗り換えることに。
現在動かしているのがこのバージョン
メッセージングの設計自体は実装2からさほぼ変更はなし。
slack-ruby-clientのRTM clientが定期的にログも出さずにコネクションが切断されるという問題(下記リンク参照)があったものの、エラーハンドリングなどで対応して現在安定稼働中。
Slack-side disconnects · Issue #208 · slack-ruby/slack-ruby-client · GitHub
ただ、やはりRTM clientの動作が不安定なのとCloud Functionsの機能追加などで実装3のEvent APIベースに戻そうかと悩んでいるところ。
直近はreactionのremoveの挙動が多分不思議な事になってるのでそれの修正をするが、 slack-wormholeのissuesにあげてることぐらいはやりたいなと思ってる。
もし使う人がいてバグ報告や要望があれば暇を見て実装したり直したりしたいところ。
紆余曲折を経たもののSlackチーム間をSlack APIを使って無料でつなぐプログラムを開発した。
今後も改良や修正は続けていくつもりなので利用者からのフィードバックお待ちしております!
Spinnakerの pipeline をUIではなくレビューができるコード形式にしたい
これを参考に
$ hal config features edit --pipeline-templates true + Get current deployment Success + Get features Success + Edit features Success + Successfully updated features.
$ hal deploy apply + Get current deployment Success + Prep deployment Success Problems in default.provider.dockerRegistry.spinnaker-gcr-account: - WARNING Your docker registry has no repositories specified, and the registry's catalog is empty. Spinnaker will not be able to deploy any images until some are pushed to this registry. ? Manually specify some repositories for this docker registry to index. Problems in default.security: - WARNING Your UI or API domain does not have override base URLs set even though your Spinnaker deployment is a Distributed deployment on a remote cloud provider. As a result, you will need to open SSH tunnels against that deployment to access Spinnaker. ? We recommend that you instead configure an authentication mechanism (OAuth2, SAML2, or x509) to make it easier to access Spinnaker securely, and then register the intended Domain and IP addresses that your publicly facing services will be using. + Preparation complete... deploying Spinnaker + Get current deployment Success + Apply deployment Success + Deploy spin-clouddriver Success + Deploy spin-front50 Success + Deploy spin-orca Success + Deploy spin-deck Success + Deploy spin-echo Success + Deploy spin-gate Success + Deploy spin-igor Success + Deploy spin-kayenta Success + Deploy spin-rosco Success + Run `hal deploy connect` to connect to Spinnaker.
テンプレートは現状HTTP(S) 経由でしか使えない。
サンプルのテンプレート(本家のほうは動かない. metadataが必要らしい)
schema: "1" id: barebones metadata: name: barebones description: this is test. scopes: [global] variables: [] stages: - id: wait type: wait config: waitTime: 5
githubのページからDL
$ wget https://github.com/spinnaker/roer/releases/download/v0.11.3/roer-linux-amd64
バイナリが落ちてくるのであとは実行権限を付与。 ついでに名前も変えておく。
$ file roer-linux-amd64 roer-linux-amd64: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped $ chmod +x roer-linux-amd64 $ mv roer-linux-amd64 roer
GKEでSPINNAKER_APIを設定するのはこっち 参照
$ roer pipeline-template publish template.yml