kaakaa Blog

この世は極楽 空にはとんぼ

commandモジュールがパイプを使えないことを経験した

という話。

LibreOfficeインストール用のPlaybookを書いてる時に、複数rpmファイルをlocalinstallする必要があったので、こんなタスクを書いた。

    - command: find LibreOffice_{{ detail_version }}_Linux_x86-64_rpm/RPMS/ -name *.rpm | xargs yum -y localinstall

エラーになった。

TASK [command] ******************************************************************
fatal: [192.168.33.14]: FAILED! => {"changed": true, "end": "2015-06-08 09:53:27.678648", "stdout": "", "cmd": ["find", "LibreOffice_4.4.3.2_Linux_x86-64_rpm/RPMS/", "-name", "*.rpm", "|", "xargs", "yum", "-y", "localinstall"], "start": "2015-06-08 09:53:27.662475", "delta": "0:00:00.016173", "stderr": "find: paths must precede expression: |\nUsage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]", "rc": 1, "invocation": {"module_name": "command", "module_args": {"_raw_params": "find LibreOffice_4.4.3.2_Linux_x86-64_rpm/RPMS/ -name *.rpm | xargs yum -y localinstall"}}, "stdout_lines": [], "warnings": []}

findの-nameオプションの引数 *.rpm をダブルクオートで囲ってないのが原因だと思って調べまくってたけど解決できず、ようやくcommandモジュールにパイプやリダイレクト等を使用できないことを知る。

ansibleでshellやcommandを使う時の注意点 - Qiita

commandモジュールじゃなくてshellモジュールを使えばいいだけだった。

    - shell: find LibreOffice_{{ detail_version }}_Linux_x86-64_rpm/RPMS/ -name *.rpm | xargs yum -y localinstall

shellモジュールの方が出来ること多いから、commandモジュールいらなくね?って疑問に言及しているエントリを見つけた。

Ansibleのshellモジュールとcommandモジュールの使い分け | bacchi.me

shellモジュールは記述されたコマンドを/bin/shで実行するけど、commandは違うよという話。 ほんまかいな。

まぁ、使えるコマンド制限されてたほうがセキュリティ的に頑丈だよねってことだろうか。


shellモジュールとcommandモジュールの違いが気になってきたのでソースを見てみた。 (結果は、よくわかりませんでした)

ansible/mod_args.py at 5622fc23bc51eebde538b582b5e020c885511f31 · ansible/ansible

shellモジュールが使われてる場合は '_uses_shell' フラグを True にして、アクション名をcommandに書き換えている。 ということは、shellもcommandも同じ動きをする?

'_uses_shell' が使われている箇所を調べるためにansible-playbook実行した時のトレースを見てみる。 Python スクリプトの動作をトレースする - とあるSIerの憂鬱

[vagrant@localhost ~]$ python -m trace --trace /usr/local/src/ansible/bin/ansible-playbook -i hosts  pptgallery-playbook.yml --ask-pass | grep '_uses_shell'
SSH password:
mod_args.py(125):             args['_uses_shell'] = True

設定されてるだけで使われてなかった。。。

とりあえずここまで。


蛇足

来日行こうか迷う。


Pallbearer - Saint Vitus 2014 - YouTube

fluentd-plugin-lets-chatを作った

fluentdのプラグインを作るために色々調べたので備忘録。

概要

REST API経由でsdelements/lets-chatへメッセージを送信してくれるプラグイン

kaakaa/fluent-plugin-lets-chat

背景

Gitbucketを遊びで使ってて、Gitbucketの飛ばすWebhookをLets Chatに飛ばしたかった。

  • Let's ChatのREST APIではリクエストパラメータのJSONの中にtextフィールドを持ってなきゃいけない
  • fluentdに対して `json={}` でない形式でデータを送った時に、fluentdのin_httpプラグインだと解析してくれない(ように見えた)
    • GitbucketのWebhookが `payload={}` の形式でリクエスト飛ばすので、それを処理したかった
    • => なので、 `KEY={}` の `KEY` の部分をconfで指定できるようなHttpInputプラグインを拡張したプラグイン書いた
  • Gitbucketの飛ばすwebhookの内容が大量なので、必要な情報だけをフィルターかけてLets Chatに飛ばしたかった
    • => なので、JSONがネストしてたりする場合もあるので、ネストしていてもキー指定できるようなOutputプラグインい書いた
    • => ただし、JSONの中にArray入ってる場合は強制的に1番目の要素を引っこ抜いてる現状

こう書くとFilterプラグインが必要そうだけど、Filterプラグインの使い方がいまいち掴めなかったので、InputプラグインとOutputプラグインでほげほげしてる。

調べたこと

Fluentdプラグインの書き方については下記を参考にした。

fluentdのためのプラグインをイチから書く手順(bundler版) - たごもりすメモ

  • 自分の環境(Ruby2.0.0)では、上記のやり方に加えて development_dependencyに test-unit を追加する必要があった。

途中、プラグインをインストールしているはずなのに、Fluentd(td-agent)がプラグインを見つけてくれない問題が起こった時には、下記サイトのやり方で原因を見つけた。

Fluentdの自作プラグインがロードできないのでソースの中身を追ってみる… - kk_Atakaの日記


HttpInputプラグインを拡張するやり方、およびテストの書き方については fluent-plugin-heroku-syslog を参考にした

また、本家のin_http.rbなども参考にした。

fluentd/in_http.rb
fluentd/test_in_http.rb

おわりに

Let's ChatはUIもモダンな感じだし、簡易的だけどREST APIも付いてるので自分でホストできるチャットツールとしては優秀だと思う。
SlackやらHipChatを使える人はそっちで十分だと思うけど、色んなしがらみによって外部ツールが使いづらいひとは試してみてはどうでしょう(主にSIer方面)。

Fluentプラグインはコード量が多くならないし、Github見ればいくつもサンプルが転がってるのでコーディング方面ではあまり躓かないけど、どういう動きをしてるのかを掴むまでは辛いものがあった。
まぁ、そこら辺はFluentdのコード読めな話なので精進が足りなかったということで。

蛇足

Royal Thunder良い。

ログインフォームを使ってログインするようなページへのアクセ

Go-lang勉強。

ログインフォームのあるようなサイトにGo-langのhttpパッケージを使ってログインする。

ログインしたいのは Log in - Swipe

フォームの情報送るにはPostForm使うと楽っぽいけど、今回は

  • リファラを設定しないとログインさせてくれない
  • cookieJar使ってログイン情報持ち回りたい

という背景があったので、PostFormだと上記が満たせない感じ。

なので、Request作ってフォームの情報はbodyに流し込む下記のような方法で。

package main

import (
        "net/http"
        "net/http/cookiejar"
        "io/ioutil"
        "bytes"
)

func main() {
        cookieJar, _ := cookiejar.New(nil)

        client := &http.Client {
                Jar: cookieJar,
        }

        // Login to swipe.to
        var str = []byte("Email=hogehoge%40example.com&Password=foobar")
        req, _ := http.NewRequest("POST", "https://www.swipe.to/login", bytes.NewBuffer(str))
        req.Header.Set("Referer", "https://www.swipe.to/home")
        req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

        res, _ := client.Do(req)

        // Create New Doc
        req2, _ := http.NewRequest("POST", "https://www.swipe.to/edit/create", nil)
        req2.Header.Set("Referer", "https://www.swipe.to/home")
        res2, _ := client.Do(req2)
        body, _ := ioutil.ReadAll(res2.Body)
        defer res2.Body.Close()

        println(string(body))
}

なんか勘違いしてる感が拭えない。

社内勉強会でGradle布教活動をしてきた

結果

「Gradle使おうぜ!」 => 失笑

資料


次のステップとして、今のプロジェクトがEclipseな感じなので、akhikhl/wuff をベースにTychoとかOSGI周りとか良いかもしれない

compare-gradle-buildsプラグインについて

Gradle in ActionやGradle徹底入門で紹介されてて気になったので触って見てる。

checkstyleの設定ファイルが違った時にどのぐらいチェック結果が変わるのかを見れるかと思ったが、現在のバージョンだとZipアーカイブの比較しか出来ないっぽい。

Chapter 64. Comparing Builds

64.2.2. Supported build outcomes

Only support for comparing build outcomes that are zip archives is supported at this time. This includes jar, war and ear archives.

Future versions will provide support for comparing outcomes such as test execution (i.e. which tests were executed, which tests failed, etc.)

今後に期待。

しかし、GradleないしGroovyは今後大丈夫だろうか。。。
Groovy 2.4 And Grails 3.0 To Be Last Major Releases Under Pivotal Sponsorship | Pivotal P.O.V.


ちなみに、compare-gradle-buildsプラグインでの比較時にデフォルトで実行されるのは

gradle clean assemble

だが、実行するタスクを変更するにはホストに下記のようなbuild.gradleを書けば良い。

apply plugin: 'compare-gradle-builds'

compareGradleBuilds {
        sourceBuild {
                projectDir "Hoge"
                tasks = ["hoge","check"]
        }
        targetBuild {
                projectDir "Fuga"
                tasks = ["check"]
        }
}

起動中のEC2インスタンスにリダイレクトするアプリ書

Node.js使ってEC2の起動中のインスタンスにリダイレクトするWebアプリ書いてみた。
Herokuに立てておけば、起動するたびに変わるPublic IPアドレスも気にならない。

kaakaa/aws-front

使い方は上記GithubリポジトリのHerokuボタンからデプロイページへ行き、AWSaccess_keyあたりを入力するだけ。
(Herokuのevn入力時にrequireの指定とかって出来るのかな)

AWS_FRONT_TAGSの所に key=value 形式でEC2インスタンスのタグを指定したフィルタリングできる。


もちろんAWSには静的IPをEC2インスタンスに割り当てるElastic IPあるので、普通はコッチを使う。
Elastic IP アドレス(EIP) - Amazon Elastic Compute Cloud

今回は書き辺りを目的として、自分で作ってみたりした。

  • Heroku Buttonの素振り
  • HerokuでNodeアプリを動かしてみる
  • lodashを触ってみる

Heroku Buttonのデプロイページでenvをrequiredで無くする設定は普通にあった。
app.json env values required by default | Heroku Dev Center

node-webkit-builderを実行できない

備忘。

mllrsohn/node-webkit-builder をnpm installして実行しようとするとエラーとなる。

env: node\r: No such file or directory

これは既知の問題のようで、GithubのIssuesではvimのコマンドで解決する方法が紹介されていた。

env: node\r: No such file or directory

    • -

ただ、viのコマンドをコマンドラインで実行できるか分からなかったので、.travis.ymlでは下記を参考に sed コマンドで改行コードを変換する処理を事前にやっておくことでとりあえず解決したようだ。

linux - How to convert DOS/Windows newline to Unix newline in bash script? - Stack Overflow

sed $'s/\r$//'     # DOS to Unix

sed コマンドで元のファイルに上書き保存する方法は下記を参考に。

sedコマンドでファイルを上書き編集 | OpenGroove

      • -

.travis.ymlのafter_successはこんな感じになった。

after_success:
- npm install -g bower
- npm install
- sed -i -e $'s/\r$//' node_modules/node-webkit-builder/bin/nwbuild
- "./build.sh"