ようへいの日々精進XP

よかろうもん

hub でハブられそうになったのでメモ 〜 まぼろしのプルリクエスト 〜

追記

プルリクエストは静かにクローズされました. 丁寧にコメント頂いて嬉しかったです.

github.com

これは

qiita.com

初老丸 Advent Calendar 2018 第 1 日目の記事になる予定です.

tl;dr

octorelease という Gem をリリースする際に過去のプルリクエストを git log から拾ってリリースノートを自動生成するツールを利用しようとしたら, それに依存する hub でハマってしまったのでメモしておきます.

github.com

github.com

何にハマったのか

octorelease (厳密に言うと, hub) を利用するにあたって, 事前に Github API を利用する為に ${HOME}/.config/hub に以下のような設定を YAML で設定しておきます.

---
github.com:
  - user: xxxxxx
    oauth_token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

この YAML の書き方が実は問題だったのです... (後述)

rake octorelease を実行すると以下のような例外が発生しました.

rake aborted!
NoMethodError: undefined method `[]=' for nil:NilClass
/path/to/vendor/bundle/ruby/2.5.0/gems/hub-1.12.4/lib/hub/github_api.rb:511:in `block in yaml_load'
/path/to/vendor/bundle/ruby/2.5.0/gems/hub-1.12.4/lib/hub/github_api.rb:502:in `each'
/path/to/vendor/bundle/ruby/2.5.0/gems/hub-1.12.4/lib/hub/github_api.rb:502:in `yaml_load'
/path/to/vendor/bundle/ruby/2.5.0/gems/hub-1.12.4/lib/hub/github_api.rb:483:in `load'
/path/to/vendor/bundle/ruby/2.5.0/gems/hub-1.12.4/lib/hub/github_api.rb:456:in `initialize'
/path/to/vendor/bundle/ruby/2.5.0/gems/octorelease-0.0.6/lib/octorelease.rb:9:in `new'
/path/to/vendor/bundle/ruby/2.5.0/gems/octorelease-0.0.6/lib/octorelease.rb:9:in `block in <top (required)>'
...
Tasks: TOP => octorelease

例外メッセージを見る限りだと, octorelease が依存している hub というライブラリで問題が発生しているようです.

何がどうだったのか

octorelease が依存しているライブラリ

hub というコマンドラインツールで, ライブラリとしても利用が可能なようです. あまり詳しく見ていないので, 間違っていたら指摘をお願い致します.

github.com

ちなみに, 現在は Golang で書き直されているようです.

デバッグしてみる

例外のメッセージを見てみると, hub の github_api.rb というコードの 511 行目で何か起きているようです. 以下, 前後のコードの抜粋です.

...
      def yaml_load(string)
        hash = {}
        host = nil
        string.split("\n").each do |line|
          case line
          when /^---\s*$/, /^\s*(?:#|$)/
            # ignore
          when /^(.+):\s*$/
            host = hash[$1] = []
          when /^([- ]) (.+?): (.+)/
            key, value = $2, $3
            host << {} if $1 == '-'
            host.last[key] = value.gsub(/^'|'$/, '')
          else
            raise "unsupported YAML line: #{line}"
          end
        end
        hash
      end
..

メソッド名を見ると, YAML ファイル (${HOME}/,config/hub) を読み込んで解析するようなメソッドのようですので, irb を起動してこのメソッドをデバッグしてみたいと思います. 用意する YAML ファイルは, 以下のような内容となります.

github.com:
  - user: foobar
    oauth_token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

試しに Ruby 標準の YAML ライブラリを利用して解析してみます. 尚, 検証に利用する Ruby の環境は以下の通りです.

$ ruby --version
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17

以下のように, Ruby 標準 YAML ライブラリの load_file メソッドを利用してファイルから YAML を読み込みます.

irb(main):001:0> require 'yaml'
=> true
irb(main):003:0> YAML.load_file('sample.yml')
=> {"github.com"=>[{"user"=>"foobar", "oauth_token"=>"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}]}

ちゃんと解析されて Ruby のハッシュオブジェクトとして読み込まれました. 次に hub で YAML を読み込んでみます. octrelease のソースコードを見る限りだと, hub の Hub::GitHubAPI::FileStore というクラスをインスタンス化する際に YAML ファイルを引数として渡してあげると良さそうです.

irb(main):004:0> require 'hub'
=> true
irb(main):006:0> Hub::GitHubAPI::FileStore.new 'sample.yml'
Traceback (most recent call last):
...
        5: from /path/to/vendor/bundle/ruby/2.5.0/gems/hub-1.12.4/lib/hub/github_api.rb:456:in `initialize'
        4: from /path/to/vendor/bundle/ruby/2.5.0/gems/hub-1.12.4/lib/hub/github_api.rb:483:in `load'
        3: from /path/to/vendor/bundle/ruby/2.5.0/gems/hub-1.12.4/lib/hub/github_api.rb:502:in `yaml_load'
        2: from /path/to/vendor/bundle/ruby/2.5.0/gems/hub-1.12.4/lib/hub/github_api.rb:502:in `each'
        1: from /path/to/vendor/bundle/ruby/2.5.0/gems/hub-1.12.4/lib/hub/github_api.rb:511:in `block in yaml_load'
NoMethodError (undefined method `[]=' for nil:NilClass)

冒頭の例外と同じ内容の例外が発生しました. この例外を回避する為, 試行錯誤した結果, 以下のような YAML ファイルの中身にすることで例外を回避することを確認しました. (github.com: 以下に半角スペースのインデントが無い状態です.)

github.com:
- user: xxxxxx
  oauth_token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

この YAML を一行にすると以下のようになります.

---\ngithub.com:\n- user: foobar\n  oauth_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n

これを, 標準の YAML ライブラリで読み込んでみます.

irb(main):001:0> require 'yaml'
=> true
irb(main):002:0> YAML.load("---\ngithub.com:\n- user: foobar\n  oauth_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n")
=> {"github.com"=>[{"user"=>"foobar", "oauth_key"=>"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}]}

一応, YAML として読み込むことが出来るようですが, こちら をざっくりと読んでみたところ, YAML 自体は半角スペースによるインデントを使って構造化しているので, 半角スペースでインデントは必須なんではなかろうかと考えていますが, github.com: 以下に半角スペースのインデントが無い状態でも問題は無いようです.

デバッグしてみる (2) 〜 何が起きているのか 〜

インデントが無い YAML でも問題は無かったのですが, 少々納得がいかなかったので, 引き続きデバッグを進めてみたいと思います.

hub の github_api.rb, 511 行目前後にフォーカスしてみます.

...
          when /^([- ]) (.+?): (.+)/
            key, value = $2, $3
            host << {} if $1 == '-'
            host.last[key] = value.gsub(/^'|'$/, '')
...

文字列として読み込まれた YAML を 1 行毎に正規表現を使ってキャプチャして特殊変数の $1$3 に放り込んでいるようです. そして, $1- であれば, host という変数に空の {} (ハッシュ) を追加して, $2 をハッシュのキー (変数 key) として, $3key に対する値 (変数 value) としてハッシュを生成していくことを意図しているようです.

では, このコードを含む yaml_load メソッドだけを切り出して, 以下のような小さなコードでデバッグしてみたいと思います. デバッグには byebug という Gem で配布しているデバッガを利用します.

require 'minitest/autorun'

class HubYamlLoadTest < Minitest::Test
  def test_yaml_load_my_pattern
    yaml = "---\ngithub.com:\n  - user: foobar\n    oauth_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"
    expect = {"github.com"=>[{"user"=>"foobar", "oauth_key"=>"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}]}
    assert_equal yaml_load(yaml), expect
  end
end

def yaml_load(string)
  hash = {}
  host = nil
  string.split("\n").each do |line|
    case line
    when /^---\s*$/, /^\s*(?:#|$)/
      # ignore
    when /^(.+):\s*$/
      host = hash[$1] = []
    when /(^[- ]) (.+?): (.+)/
      key, value = $2, $3
      host << {} if $1 == '-'
      require 'byebug'; byebug # ここにデバッガを差し込む
      host.last[key] = value.gsub(/^'|'$/, '')
    else
      raise "unsupported YAML line: #{line}"
    end
  end
  hash
end

byebug の詳しい使い方については, 他の書籍やサイトをご覧下さい.

このテストコードを実行してみます.

$ bundle exec ruby test.rb
Run options: --seed 54106

# Running:


[25, 34] in /Users/kawahara/sandboxies/octorelease/test.rb
   25:       host = hash[$1] = []
   26:     when /(^[- ]) (.+?): (.+)/
   27:       key, value = $2, $3
   28:       host << {} if $1 == '-'
   29:       require 'byebug'; byebug
=> 30:       host.last[key] = value.gsub(/^'|'$/, '')
   31:     else
   32:       raise "unsupported YAML line: #{line}"
   33:     end
   34:   end
(byebug)

byebug のプロンプトが現れ, デバッガを差し込んだ次の行で処理が一時停止しています. この状態で, 各変数にどのような値が格納されているのか確認しています.

...
(byebug) key
"- user"
(byebug) value
"foobar"
(byebug) host
[]

変数 host[] と空の配列になっており, 変数 host はハッシュである前提で host.last[key] が実行されるので, キーに変数 key が代入することが出来ずに例外が発生してしまっているようです.

デバッグしてみる (3) 〜 じゃあ, どうするのか 〜

以下のような変更を加えてみます.

$ diff -u test.rb fix.rb
--- test.rb     2018-11-22 07:09:51.000000000 +0900
+++ fix.rb      2018-11-22 07:09:42.000000000 +0900
@@ -25,7 +25,8 @@
       host = hash[$1] = []
     when /(^[- ]) (.+?): (.+)/
       key, value = $2, $3
-      host << {} if $1 == '-'
+      host << {} if $1 == '-' or $2 =~ /^\s*-\s*/
+      key.gsub!(/^\s*-\s*|^\s*/, '')
       require 'byebug'; byebug
       host.last[key] = value.gsub(/^'|'$/, '')
     else

この状態で, 変更したコード (fix.rb) を実行してみます.

$ bundle exec ruby fix.rb
Run options: --seed 49205

# Running:


[26, 35] in /Users/kawahara/sandboxies/octorelease/fix.rb
   26:     when /(^[- ]) (.+?): (.+)/
   27:       key, value = $2, $3
   28:       host << {} if $1 == '-' or $2 =~ /^\s*-\s*/
   29:       key.gsub!(/^\s*-\s*|^\s*/, '')
   30:       require 'byebug'; byebug
=> 31:       host.last[key] = value.gsub(/^'|'$/, '')
   32:     else
   33:       raise "unsupported YAML line: #{line}"
   34:     end
   35:   end
(byebug) key
"user"
(byebug) value
"foobar"
(byebug) host
[{}]

変数 host に空のハッシュ {} が格納されていることを確認しました. では, デバッガを外して実行してみます.

$ bundle exec ruby fix.rb
Run options: --seed 17705

# Running:

.

Finished in 0.001235s, 809.7167 runs/s, 809.7167 assertions/s.

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

いい感じですね. また, github.com: 以下に半角スペースのインデントが無い YAML でも正しく解析されるかも検証しておきたいので, 以下のようにテストを書きました.

require 'minitest/autorun'

class HubYamlLoadTest < Minitest::Test
  def test_yaml_load_ok_pattern
    yaml = "---\ngithub.com:\n- user: foobar\n  oauth_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"
    expect = {"github.com"=>[{"user"=>"foobar", "oauth_key"=>"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}]}
    assert_equal yaml_load(yaml), expect
  end

  def test_yaml_load_my_pattern
    yaml = "---\ngithub.com:\n  - user: foobar\n    oauth_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"
    expect = {"github.com"=>[{"user"=>"foobar", "oauth_key"=>"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}]}
    assert_equal yaml_load(yaml), expect
  end
end

def yaml_load(string)
  hash = {}
  host = nil
  string.split("\n").each do |line|
    case line
    when /^---\s*$/, /^\s*(?:#|$)/
      # ignore
    when /^(.+):\s*$/
      host = hash[$1] = []
    when /(^[- ]) (.+?): (.+)/
      key, value = $2, $3
      host << {} if $1 == '-' or $2 =~ /^\s*-\s*/
      key.gsub!(/^\s*-\s*|^\s*/, '')
      # require 'byebug'; byebug
      host.last[key] = value.gsub(/^'|'$/, '')
    else
      raise "unsupported YAML line: #{line}"
    end
  end
  hash
end

これを実行してみます.

$ bundle exec ruby fix.rb
Run options: --seed 30867

# Running:

..

Finished in 0.003929s, 509.0354 runs/s, 509.0354 assertions/s.

2 runs, 2 assertions, 0 failures, 0 errors, 0 skips

いい感じです. 2 つの YAML パターンが, この yaml_load メソッドで解析出来るようになったはずです.

で, どうしたのか

まぼろしのプルリクエス

hub のリポジトリを見ると, Ruby で実装された hub は既にサポートされていないのではと思ってしまう程, master ブランチには Golang のコードが並んでいます. ブランチを github:1.12-stable を切り替えると様子が一変して Ruby で実装された hub を拝むことが出来ます. さらに, .travis.yml を見ると, 以下のようにテスト対象にはいにしへの Ruby バージョンが並んでいます.

sudo: false
language: ruby
before_install:
  - script/bootstrap
  - export PATH=~/bin:"$PATH"
script: script/test
bundler_args: --without development --deployment --jobs=3 --retry=3
cache: bundler
rvm:
  - 1.8.7
  - 1.9.2
  - 1.9.3
  - 2.0.0
  - 2.1.5
  - 2.2.0-preview2
notifications:
  email: false

どうやら, Ruby 版の hub はメンテナンスされていないようです. また, #1591 を見ろということでリンクが張っていますが, このリンクを踏んでも 404 となりページが存在していません. このページが無いことすらメンテナンスされていないということは本当にメンテナンスされていないと思って間違いないようです.

ですが, 一応, 以下のようなプルリクエストを作成してみました.

github.com

きっとマージされること無く, ひっそりとクローズされることでしょう.

なぜ, オレオレ YAML パーサーなのか

既にサポートされていないであろう Ruby 版 hub の .travis.yml を見ながら考えました. そもそも Ruby には YAML を読み込んだり, 書き出したりするライブラリがあるのに, なぜ hub にはオレオレ YAML パーサーが実装されているのか. 答えのようなコミットを発見しました.

github.com

2013 年の 12 月くらいまでは標準の YAML パーサーを利用していたようですが, YAML を解析する速度が思ったよりも遅かった為, オレオレ YAML パーサーに書き換えたとのことでした.

なるほどです. 実際に標準の YAML とオレオレパーサーでどのくらいの速度の違いがあるかについては別の機会に検証してみたいと思います.

ということで

octorelease から始まって, それが依存する hub のソースコードを見ながら色々と学びがありました. きっとプルリクエストはマージされずにまぼろしとなってしまうとは思いますが, これを糧に引き続き Ruby 道に精進して参る所存です.

有難うございました.

2018 年 11 月 21 日 (水)

ジョギング

  • 山王公園往復
  • 左の踵に痛みがあったので, ゆっくりとしたペースで走る

日課

  • お休み
  • そろそろ, 再開する

ゴーン会長

  • 不正して得た金額が我々庶民の想像を超越しているので, 連日, 報道で報じられていても「フーン」という感じにしかならない
  • 悪いことをしたら必ずその報いがあるということだけは理解した

今夜の鍋

  • 利尻昆布をお土産でいただいていたので, それを使って出汁をとってみた
  • 出汁のとり方が正しいのか解らないが, なんだかスープにしっかりとした旨味があるというか, 少しの酒と醤油で味を整えるだけで美味しいスープになった気がする
  • 具材はいつものやつ

2018 年 11 月 20 日 (火)

ジョギング

  • 左足踵に痛みがあったのでお休み
  • 結局, 踵というか「ふくらはぎ」に強い張りがあっただけ

日課

  • お休み
  • そろそろ, 再開したいところだけど, 肋骨が引き続き痛い

Golang ハンズオン

gmohoscon.connpass.com

ハンズオン資料や以下のコードも良く出来ていたと思うし, 何より, 講師やサポートメンバーの方のケアが最高だった. こんなホスピタリティが高いハンズオンは初めてかもしれない.

Golang 自体については, 自分の理解度の低さに辛くなったので, 改めて Golang について勉強するぞ!という強い思いに至った次第.

github.com

とんとん

久しぶりに美人居酒屋で. 鮭のホイル焼きと湯豆腐を食べる. 今日でキープしていたボトルが無くなった. 次の来店時にキープしよう.

2018 年 11 月 19 日 (月)

ジョギング

  • 山王公園を往復 30 分くらい
  • 右足の強い張りが顕著, 要集中的なマッサージ

日課

  • お休み
  • そろそろ, 再開したいところだけど, 肋骨が引き続き痛い

今日も鍋

  • 根菜鍋
  • 昆布で出汁をとった

furikake を gem 化してリリースしました

tl;dr

inokara.hateblo.jp

先日, 作成した furikake について, 色々と修正した上で gem 化してリリースしました.

furikake | RubyGems.org | your community gem host

ということで

furikake の始め方が変わりました

詳細は

README をご一読下さい.

github.com

セットアップ

gem 化に伴い, gem コマンドや bundler を利用してインストールすることが出来ます. また, 従来は .furikake.yml を手動で生成していましたが, 以下のように setup コマンドを実行することで生成することが出来ます.

$ bundle exec furikake setup

以下のように .furikake.yml が出力されます.

resources:
  aws:
    - clb
    - vpc_endpoint
    - security_group
    - ec2
    - kinesis
    - lambda
    - alb
    - directory_service
    - elasticsearch_service
    - vpc
    - rds
backlog:
  projects:
    - space_id: 'your-backlog-space-id'
      api_key: 'your-backlog-api-key'
      top_level_domain: 'your-backlog-top-level-domain'
      wiki_id: your-wiki-id
      wiki_name: 'your-wiki-name'
      header: >
        # Test Header

        [toc]

        ## Sub Header
      footer: >
        ## Test Footer

        ### Sub Footer

あとは, 環境に応じて space_idapi_key 等の情報を修正して下さい. また, resources キー以下の属性値はドキュメント化する AWS リソースの一覧となります. 将来的には, この属性値を削除することで, 指定したリソースのみドキュメント化出来るようにする予定です.

リソースタイプの実装

Markdown だけでなく, CSVGoogle SpreadSheet 等の異なるフォーマットにも対応する為, 内部処理を少し修正しています. それに伴い, 以下のように, リソースタイプの実装が少しだけシンプルにしたつもりです.

module Furikake
  module Resources
    module Ec2
      def report(format = nil)
        instance = get_resources
        contents = {
          title: 'EC2',
          resources: [
            {
               subtitle: '',
               header: ['Name', 'Instance ID', 'Instance Type',
                        'Availability Zone', 'Private IP Address',
                        'Public IP Address', 'State'],
               resource: instance
            }
          ]
        }
        Furikake::Formatter.shaping(format, contents)
      end

      def get_resources
        ec2 = Aws::EC2::Client.new
        params = {}
        instances = []
        loop do
          res = ec2.describe_instances(params)
...

get_resources メソッドは従来から変更はありませんが, report メソッドには以下のようなハッシュオブジェクトと Furikake::Formatter クラスのクラスメソッド shaping だけを呼び出すようにしています.

...
        contents = {
          title: 'EC2',
          resources: [
            {
               subtitle: '',
               header: ['Name', 'Instance ID', 'Instance Type',
                        'Availability Zone', 'Private IP Address',
                        'Public IP Address', 'State'],
               resource: instance
            }
          ]
        }
        Furikake::Formatter.shaping(format, contents)
...

↑ ここの部分だけを AWS リソースに応じて修正する感じです. (get_resources の実装は従来どおり必要です.)

テストの追加

まずは気になるところからテストを追加しています. 個々のリソースタイプについても随時テストを追加していく予定です.

以上

furikake の更新情報でした. よろしければ, furikake を使って頂きましてフィードバック頂けると嬉しいです.

2018 年 11 月 18 日 (日)

ジョギング

福岡でのランナー達のメッカ、大濠公園まで走ってきた。#帰りは電車 #大濠公園

大濠公園まで走ってみた. だいたい 45 分くらい. 往復するつもりだったけど, 赤坂駅から電車に乗って自宅に帰った...

次回は自転車か電車で行って走ろうかな.

日課

  • お休み
  • そろそろ, 再開したいところだけど, 肋骨, 実はまだ治っていない感

2018 年 11 月 17 日 (土)

ジョギング

  • 山王公園を往復 30 分くらい
  • うーん, 走っていても体のきつさが抜けないし, 足の痛みも引き続き... 困った

日課

  • お休み
  • そろそろ, 再開したいところだけど, 肋骨が引き続き痛い

正三おじさんの退職祝い

久しぶりの香椎, 俺たちの「よしもと」にて正三おじさんの退職祝いを盛大に執り行った (笑).

多美子おばさんも参加してくれて, とても盛り上がったと思う. おじさん, おばさん共に楽しんで頂けたようで本当に良かった.

2018 年 11 月 16 日 (金)

ジョギング

  • 山王公園を往復 30 分くらい
  • 回復傾向, やっぱり体を動かした方が回復具合は良いような気がする

日課

  • お休み

免許更新

  • 久しぶりのゴールド返り咲き
  • 安全運転を肝に命じて, ゴールドの免許に恥じないドライバーになるぞ

Serverless Meetup Fukuoka

今日もさくらインターネットさんのオフィスで.

Serverless という文脈でこれほどの人が集まるのか (Serverless に興味があるのか) ということを再認識した.

簡単なお疲れ様会は「串カツ田中」で. お腹いっぱい食べて飲んだりしたけど 3000 円弱ということで, このコスパの破壊力に驚いた.

AWS リソースを Backlog Wiki によしなにドキュメント化 (一覧化) するツール, その名も furikake を作った

tl;dr

ギョームにて AWS リソース一覧を Backlog WikiExcel にまとめる度になんて不毛な作業をやっているんだろうと自問自答を繰り返しておりました.

そう, EC2 を追加したり削除する度にそれらの WikiExcel 表は誰がいったい更新するんだ, きっとそのうち誰もこの WikiExcel 表はメンテナンスされなくなるんだろう, そして, なにかトラブルが起きた時には情報が古いままになっているとか...せめてコマンド一発でこれらの WikiExcel 表が更新できたらどんなに嬉しいものかと...思いは強くなっていきました.

ということで, JAWS-UG もくもく会を利用して, この不毛な状態から脱すべく俺得ツールをざくっと作ってみました.

作ったもの

furikake

github.com

名前は「ふりかけ」です. 特に意味は無いつもりでしたが, 実装している間に思いついたのが, 白いごはんに彩りを添える「ふりかけ」のように, 真っ白な WikiExcel シートに各種情報という彩りを添えるという意味をこじつけてみました.

とりあえず,「ふりかけ」には以下のような機能を実装しました.

  • 指定した AWS アカウントの指定したリソース一覧を取得して Backlog Wiki に投稿する
  • 一覧を取得したい AWS リソースは出来るだけ簡単なコードで追加出来ること (とりあえず, 自分が確認したかったリソースは追加した, AWS リソース以外にも対応可能だと思う)
  • 投稿先は出来るだけ簡単なコードで追加出来ること (とりあえず, 現状は Backlog Wiki だけ)
  • シンプルなコマンドラインツール

ひとまず, 自分がやりたいことは実現出来たので, 今後は色々と便利そうな機能を追加していきたいと考えています.

使い方

インストールは git clone でしばらくはお願い致します.

$ git clone git@github.com:inokappa/furikake.git
$ bundle install --path vendor/bundle

リソース一覧を貼り付けたい Backlog Wiki を作成します. この時に Wiki 名は適当で構いません. また, Wiki の本文は適当な文字を入れて下さい. (コンテンツが無いと Wiki は作成できないようです) 作成した Wiki の ID を控えておきます.

Wiki を作成したら, 以下のような .furikake.yml を作成します. (.furikake.yml の名前は固定しています)

backlog:
  projects:
    - space_id: 'your-backlog-space-id'
      api_key: 'your-backlog-api-key'
      top_level_domain: 'your-backlog-top-level-domain'
      wiki_id: your-wiki-id
      wiki_name: 'your-wiki-name'
      header: >
        # Test Header
      footer: >
        # Test Footer

headerfooter はリソース一覧の上下に挿入されるコンテンツとなります. 上記の例では # Test Header# Test Footer がリソース一覧の前後に挿入されますので, 実際の出力は以下のような内容にとなります.

# Test Header

# リソース一覧

## EC2

...

## ELB

# Test Footer

尚, Backlog Wiki への投稿については, 以下のライブラリを利用していますので, パラメータ名等はこのライブラリに依存します.

github.com

.furikake.yml を作成したら, 以下のコマンドを実行して投稿される予定のリソース一覧を確認してみます.

$ bundle exec furikake show

以下のように出力されます.

$ bundle exec furikake show
# インフラ構成 (自動更新テスト用)
## 全体構成
ここに構成図なんかはっちゃったりして
## リソース一覧

### EC2

Name|Instance ID|Instance Type|Availability Zone|Private IP Address|Public IP Address|State
:-|:-|:-|:-|:-|:-|:-
...

## 詳細情報
### リポジトリ
* ソースコードの URL とか張ったりして

特に問題無いようであれば, 以下のコマンドを実行して Backlog Wiki にリソース一覧を投稿します.

$ bundle exec furikake publish

今のところ, 失敗する以外は, 特にメッセージが出ません. 冒頭で作成した Backlog Wiki を見ると, 以下のようにいい感じでリソースの一覧 (図では EC2 だけですが...) を確認することが出来ます.

f:id:inokara:20181116143637p:plain

いい感じです.

ちっぷす

Tips というか, 「ふりかけ」は利用者のニーズによって, 出来るだけ拡張し易く作ったつもりです (まだ, たくさんの改善の余地はありますが...). 例えば, リソース一覧に含めたい AWS リソースがある場合, ソースコードlib/furikake/resources/ 以下に簡単なコードを置くことでリソースの種類を追加することが出来ます. 以下, README にも記載していますが, ELB (Classic Load Balancer) のリソース一覧を取得するコードです.

module Furikake
  module Resources
    module Clb
      def report
        resources = get_resources
        headers = ['LB Name', 'DNS Name', 'Instances']
        if resources.empty?
          info = 'N/A'
        else
          info = MarkdownTables.make_table(headers, resources, is_rows: true, align: 'l')
        end
        documents = <<"EOS"
### ELB (CLB)

#{info}
EOS
        
        documents
      end

      def get_resources
        elb = Aws::ElasticLoadBalancing::Client.new
        elbs = []
        elb.describe_load_balancers.load_balancer_descriptions.each do |lb|
          elb = []
          elb << lb.load_balancer_name
          elb << lb.dns_name
          elb << (lb.instances.map(&:to_h).map {|a| a[:instance_id] }).join(',')
          elbs << elb
        end
        elbs
      end

      module_function :report, :get_resources
    end
  end
end

report というメソッド名を遵守して頂いて, 且つ, 以下のようなフォーマットのデータを返すように実装するといい感じになります.

[['ID', 'Name', 'Status'], ['ID', 'Name', 'Status'], ['ID', 'Name', 'Status']]

ただし, 現在はソースコードを追加した後で, lib/furikake/resource.rbtypes にリソース名を追加する必要があります...ごめんなさい.

module Furikake
  class Resource
    def initialize
    end
    
    def generate
      types = %w(
        ec2 alb clb lambda elasticsearch_service
        kinesis rds directory_service
      )

      documents = ""
      types.each do |type|
        require "furikake/resources/#{type}"
        eval "documents.concat(Furikake::Resources::#{type.camelize}.report)"
        documents.concat("\n")
      end
      documents
    end
  end
end

以上

まだまだ

「ふりかけ」には改善の余地がたくさんあります. 例えば, Backlog Wiki 以外の Github Wiki や Gist 等に投稿出来るようにしたいなと考えています. また, Excel 表も考慮して CSV 出力も出来ればなあと考えています. また, 機能以外にもエラー処理が残念ながら不十分ですので, 今後, ぼちぼち整備していこうかな〜と思っています.

awspec

「ふりかけ」の実装にあたり, awspec の実装をめちゃくちゃ参考にしてみました. めちゃくちゃ参考にした割には...残念な感じになっているかもしれませんが, awspec は AWS リソースを取得して色々する処理を書く時にとても参考になると思います. そして, awspec 同様にリソースの種類の追加は比較的容易に行えるようになっているはずですので, awspec のような成長を遂げてくれるとやばい感じになると思います.

ということで,「awspec だ〜いすき♡」(ハズキルーペ CM 風)

ということで

興味を持って頂けた方, ぜひ, 触って頂いてフィードバックを頂けると嬉しいでござります.

2018 年 11 月 15 日 (木)

ジョギング

  • 山王公園を往復 30 分くらい
  • 右足がめちゃくちゃ張っていて痛いことに今更気づく

日課

  • お休み

JAWS-UG 福岡もくもく会

今日はさくらインターネットさんのオフィスで.

ざっくりやりたいコードは書けたので, あとは拡張し易くしつつ, テストを書いて gem 化してみようと思う.

あと, 青柳さんが, 明日の Serverless Meetup 福岡で喋る資料を使って LT をしてくれた. 毎回, 青柳さんの資料は丁寧な作りで話も解りやすくて勉強になった.

夕飯

もくもく会の後, 近所の気になっていた焼き鳥屋さんにて. 板わさを頼んだらワラジみたいは蒲鉾が出てきたのには笑ってしまったが, 焼き鳥自体は自分の口では 40 点くらい.