かまたま日記3

プログラミングメイン、たまに日常

GoogleのAPIトークンをS3に保存する

GoogleAPI Clientには Google::Auth::TokenStore というトークンを保存するためのインターフェースが存在していて、デフォルトでは

  • Google::Auth::Stores::FileTokenStore
  • Google::Auth::Stores::RedisTokenStore

のふたつがある。これのS3バージョン。 ひとつ下の記事FileTokenStore を置き換えられる。

GCSじゃないの?というツッコミは無しで...w cacheは厳密にはいらないけど何回も呼ぶときがあるかなと思って用意しました。

require 'googleauth/token_store'
require 'aws-sdk'

class S3TokenStore < Google::Auth::TokenStore
  def initialize(bucket_name:, path_prefix:)
    @bucket = Aws::S3::Resource.new.bucket(bucket_name)
    raise "Bucket(#{bucket_name}) not exists" unless @bucket.exists?
    @path_prefix = path_prefix
    @cache = {}
  end

  def load(id)
    @cache[id] ||= begin
      object = object(id)
      if object.exists?
        object.get.body
      end
    end
  end

  def store(id, token)
    object(id).put(body: token)
    @cache[id] = token
  end

  def delete(id)
    object(id).delete
    @cache.delete(id)
  end

  private
  def object(key)
    @bucket.object("#{@path_prefix}#{key}")
  end
end

GmailをAPI経由で取得する

GmailAPI経由で未読のメールを1件検索して既読にするサンプル。OAuthのトークンがない場合はコンソールに出てくるURLをブラウザで開いて認証後に出てくるコードを入力する。

require 'google/apis/gmail_v1'
require 'googleauth/stores/file_token_store'

Gmail = Google::Apis::GmailV1
OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'

def credentials(email)
  @credentials ||= begin
    client_id = Google::Auth::ClientId.new(
      'xxxxx.apps.googleusercontent.com',
      'xxxxx'
    )
    token_store = Google::Auth::Stores::FileTokenStore.new(file: "#{ENV['HOME']}/google_credentials.yaml")
    authorizer = Google::Auth::UserAuthorizer.new(client_id, Gmail::AUTH_SCOPE, token_store)
    user_id = email
    credentials = authorizer.get_credentials(user_id)
    if credentials.nil?
      url = authorizer.get_authorization_url(base_url: OOB_URI)
      puts "Open the following URL in your browser and authorize the application."
      puts url
      puts "Enter the authorization code:"
      code = gets
      credentials = authorizer.get_and_store_credentials_from_code(
        user_id: user_id, code: code, base_url: OOB_URI
      )
    end
    credentials
  end
end

email = 'foo@gmail.com'
gmail = Gmail::GmailService.new
gmail.authorization = credentials(email)

result = gmail.list_user_messages(email, max_results: 1, q: 'label:inbox label:unread')
result.messages.each do |m|
  puts m.id
  puts gmail.get_user_message(email, m.id).snippet
  r = Gmail::ModifyMessageRequest.new
  r.remove_label_ids = ["UNREAD"]
  result = gmail.modify_message(email, m.id, r)
end

BashのPS4でデバッグが捗る

Bashset -xとするとデバッグモードとして処理内容が逐次出力されますが、PS4という環境変数で出力内容を調整できます。


test.sh

#!/usr/bin/env bash

PS4='+ [${BASH_SOURCE}:${LINENO}] ${FUNCNAME:+$FUNCNAME(): }'
set -x

hello() {
  name=$1
  echo "Hello $name"
}

hello 'World'

これを実行すると、以下のようにソース名(BASH_SOURCE)と行数(LINENO)、関数の場合は関数名(FUNCNAME)が出力されます。

% bash test.sh
+ [test.sh:11] hello World
+ [test.sh:7] hello(): name=World
+ [test.sh:8] hello(): echo 'Hello World'

シェルスクリプトで再実行するための関数

retry() {
  command="$@"
  local try_count=0
  local retry_limit=3
  local wait_seconds=300
  until sh -c "$command"; do
     [ $try_count -eq $retry_limit ] && return 1
     sleep $wait_seconds
     try_count=$(expr $try_count \+ 1)
  done
}

# example
retry ls -ltra hoge

北海道旅行に行ってきた

8/10~13 の3泊で北海道に行ってきました。

1日目(8/10)

直前に飛行機を取ろうとしましたが、羽田発の便は全滅だったので茨城空港から出発。東京駅から500円のバス便があるのでそれを利用しました。茨城空港ガルパン推しがヤバかったです。

12時前に新千歳に着いてそのまま電車で小樽へ。澤崎水産で特選ちらし丼を注文、ウニがとろけました。

f:id:kamatama_41:20160810144409j:plain

その後は近くの店で生とうもろこしを食べ(これがものすごく甘かった..!)、小樽運河クルージングして札幌に戻りこの日は終了。

2日目(8/11)

朝から旭川に車を走らせ昼前に旭山動物園に到着。この日は北海道にしては結構暑く、いろいろな動物を見ましたが、ほぼすべての動物が日陰で寝てましたw そんな中でテナガザルの機敏な動きはかなり感心させられるもので、観客も集まってました。

その後あさひかわラーメン村にて利尻昆布ホタテを使ったラーメンを食べ、滝川市へ。

f:id:kamatama_41:20160811142913j:plain

滝川市でローカルの花火大会に参加。the 地元の花火大会という感じで規模的には小さなものでしたが、打ち上げ場所のすぐ近くで見れたので迫力はすごかったです。

3日目(8/12)

旭川から出発し、美瑛の青い池に。いい青でした。

f:id:kamatama_41:20160812095314j:plain

その後四季彩の丘富良野ファーム富田六花亭カンパーナに寄り自然を満喫。富良野のホテルへ。

夜は何もすることが無いかなと思ってたのですが、地元のお祭的なものが駅前で開催されてて小学校低学年くらいのちびっ子たちのライブを楽しめました、演奏めちゃ上手かった。

4日目(8/13)

朝に出て昼前に札幌へ戻り、回転寿しのトリトンへ。この日のオススメのボタンエビが濃厚で美味でした...!

f:id:kamatama_41:20160813131324j:plain

その後、北海道大学でクラーク博士に会ったり雪印パーラーで(ジャンボじゃない)パフェを食べたりして、新千歳空港へ戻り東京へ帰りました。

まとめ

北海道はとにかく広くて隣の観光地に行くのにも車で50kmとか走らないといけないので大変でした(3日間の運転距離約500km)。が今まで経験したことのない自然だったり食べ物だったりを経験できて良かったです。北海道はデッカイドウでした...!

シン・ゴジラを観た

かなり評判が良かったので見てきました。感想としては評判に違わぬ内容で面白かったです。

全体的に日本よりなところ(アメリカが完全悪者扱い)とかは賛否が別れるかと思いますが、庵野節ってことで僕はアリかなと思いました、ところどころでエヴァネタとかも入ってたり。

長谷川博己さんの演技が個人的にはすごく良かったと思います、カッコいい。

Terraformをバージョン管理できるtfenvを作った

github.com

名前を見てもお分かりのようにrbenvと同じような感じのterraformのバージョン管理ツールです*1。複数プロジェクトをterraformで管理しててそれぞれのバージョンが分かれてる場合を想定して作ってます。

ぜひぜひ、使ってみてください!

基本的な使い方(v0.3.x 系)

詳しい使い方は READMEを見て下さいということで

Install/Uninstall

GitHubから任意のパスにcloneしてtfenv/binにパスを通すだけ。 アンインストールはそのパスを消すだけです。

tfenv install

指定したバージョンをインストールしますlatestで最新版をインストールします。

$ tfenv install 0.7.0
$ tfenv install latest # latest version

tfenv use

利用するバージョンを切り替えます。

$ tfenv use 0.7.0

tfenv list

現在インストールしているバージョンを列挙します。

% tfenv list
0.7.0
0.7.0-rc4
0.6.16
0.6.2
0.6.1

tfenv list-remote

インストール可能なバージョンをリモートから取得して列挙します。

% tfenv list-remote
0.7.0
0.7.0-rc4
0.7.0-rc3
0.7.0-rc2
0.7.0-rc1
0.6.16
0.6.15
...

.terraform-version

rbenvの.ruby-versionと同じような機能で、プロジェクトルートに.terraform-versionというファイルを置いておくとそのファイルに書かれたバージョンを優先して利用します。また、引数なしのtfenv installでそのバージョンをインストール出来るようになります。

*1:ソースコード的にも結構使わせてもらってます