Chef実践入門を読んでいる 4
球磨焼酎美味しい
今日の進捗 4.2 まで
- Berkshelfを使って外部クックブックを管理しよう
- roleとenvironmentsを使い分けて、見通し良い感じに書こう
- 複数のノードにまとめて適用する処理はchef-soloにはないので外部のツールを使おう、capとか
- Serverspec更新したよ
roleとenvironmentってなんだろなーと思ってたところが全部書いてた。役割と環境なるほど。 attributeが結構どこからでも定義できるので、うっかりよくわからんとこで上書きしちゃってたーみたいな事故が怖いなと思った。気をつけよう。
4章に入ってパッケージとかノード名とか変わったのでその辺を修正
Serverspec修正 by adarapata · Pull Request #2 · adarapata/chef-practice · GitHub
ちなみに、写経してvm二台立ち上げて片方にchef適用したら以下のエラーが出た。
FATAL: Cannot load configuration from /home/docker/chef-solo/dna.json
調べたらOpenSSHのControll Masterという機能を使って接続するところに問題があったらしく、すでに解決法まで出てた
- ControllMasterをOnにするとsshセッションのコネクションを使いまわすので速度が速い
- 同名ホストでポートだけ分けてたのでソケットファイル名が重複して通信に失敗した
- よって、dna.jsonが作られていない
今回は書いてる通り --ssh-control-master no
を渡して無効にしたら解決した。
このブログなかったら詰んでた気がするので気をつけよう。
Chef実践入門を読んでいる 3
三連休は全力で遊んだ。
今日の進捗 3.6 まで
- 各種リソースの名前と定義方法が書いてたよ
- Attributeはノードに紐づく属性情報を持つし、定義していくといいよ
- data_bagはノードに紐付かない、グローバルなデータを持ちたい時に定義していくといいよ
- cookbookのディレクトリ構造が書いてあったよ
リソース内で参照したディレクトリが存在しなかったら普通に落ちるので、directoryリソースでディレクトリを確保するのは結構あるとのこと。
templateは template/default下を見に行く。cookbook_file は files/default下を見に行く
templateは動的なコンテンツの際に使って、filesは静的なコンテンツを入れるという分け方が望ましい。 Script(bash)リソースは自由度めちゃくちゃ高い。が、冪等性から何まで自分で調べないといけないので手間はかかる。 どうしても細かいことをしたい時に。
createsコマンド大事。not_if, only_ifでもよし。ただ冪等であるかだけで考えるとcreatesの方が伝わりやすそう。
attributeは同じキーの値がノードオブジェクトにある場合はそちらが優先される。
databagはノード感で共有したいデータなどを格納してる。cap用のデプロイユーザとか定義しておいたり。
attributeはあくまでノードに関する情報で、data_bagにはそれ以外の情報を入れるべきとのこと。
リソースの種類は結構な数あったので、その都度調べていくのが一番良さそうだった。
そういえば、前回removeアクションって何に使うんだろうと書いてたけど、色々見てたらapacheを入れた後にwelcome.confをremoveしていてなるほどなとなった。
今日も読んだだけなのでリポジトリに変更なし。
Chef実践入門を読んでいる 2
今日の進捗 2.8~3.2まで
- gitで管理しようぜという話があったよ
- リポジトリの各ディレクトリの説明が書いてあったよ
- vagrant環境以外にchef流す方法を知ったよ
- chefの考え方を知ったよ
- td-agentのレシピを読んだよ
Berkshelfというcookbook用bundler的な役割のツールがあり、その設定ファイルがBerksfile。 少し前にLibrarian-Chefをインストールした記憶があるけど、最近はこっちが主流っぽい。
プロビジョニングは、裏で ssh
で繋いでから sudo chef-solo
を叩いているとのこと。
chefは冪等性という話。 以前rubyのバージョンアップ時に前のバージョンどうなるんだろうと怖かったので、過去のrubyのバージョンを残したままPR出したの思い出した。 書いた状態に収束されるということは、それ以外に関しては何も担保しないので残り続けるのだった・・
td−agentのレシピはこれだった。本の内容とは若干の変更あり
chef-td-agent/default.rb at master · treasure-data/chef-td-agent · GitHub
結構内部で普通にrubyのコード書いてる。
packageのremoveアクションの使いどころってどういう時だろうとふと思った。 元々使ってたけどもう不要になったものをremoveで明示的に消して、いずれコードごと消すみたいな運用かな。
ohaiというツールはシステムの情報を取り出していい感じにjsonにしてくれる便利なやつだった https://github.com/chef/ohai
試しに ohai | head
したらBroken pipeしたので扱いには気をつけようと思う。
本とソース読んだだけなので、特にコミットは無し。
おまけ:弊社イケメンエンジニアからjqという便利コマンドを教えていただきました。
@adarapata jq噛ませて必要な絡むだけ取ると良い。
— P山 (@pyama86) 2016年3月16日
$ cat nodes/webdb.json | jq ".run_list" [ "recipe[dstat]", "recipe[apache]", "recipe[mysql]" ]
便利だ・・・。 https://stedolan.github.io/jq/
Chef実践入門を読んでいる 1
先週買ったChef実践入門のログを残すことにした。 www.amazon.co.jp
Chefは業務で使われているのでレシピを読んだり軽い修正のPRはしたことあるが、1から自分で書いたことはないのでやってみようと思った。サーバサイドに疎いし。
書いたものは下記のリポジトリにpushしていく github.com
所感を事細かに書いていった方が身につきそうだけど、きつくて続かなそうだから印象に残ったとこだけ書いていく
今日の進捗 2.7まで
- centos6.7(本は6.5だが最新)をインストールしたよ
- chef soloをvagrant上に入れてゲストOS上でレシピ書いていったよ
- ホストOSにknife solo入れて手元で構築するようにしたよ
- dstat、mysql、apacheのレシピを書いたよ
- ついでにServerspecも入れて上記の三つがインストールされているかのテストも書いたよ PR
特につまづくことはなかった。
actionで出てきた enable
start
がそれぞれ sbin下の chkconfig
service
の実行に相当すると知ったが、そもそもsbin下のコマンドを全然知らなかった。知見を得た。
Serverspecで今回はdstat、mysql、httpで三つテストファイル区切ったんだけど、どのくらいの粒度が良いのだろうかと気になった。ツールごとに区切っていくとかなり増えそう。
UnityWebRequestについてちょっと調べてみた
この記事はUnity 2 Advent Calendar 2015のエントリです。
UnityWebRequest
UnityWebRequestとはWWWに変わる新しいHTTP通信用のクラスである。
名前空間にExperimental
が含まれている通り、まだ実験的な機能なので今後も仕様が変更されていく可能性がある事をご了承いただきたい。
それでも、WWWと比較して十分使いやすくなってはいるので普通に活用して良さそう。
使い方
例えば、以下のコードはローカルホストにアクセスして、レスポンスをログに吐く
using UnityEngine; using UnityEngine.Experimental.Networking; public class HTTPTest : MonoBehaviour { // Use this for initialization void Start () { StartCoroutine(HttpRequest()); } IEnumerator HttpRequest() { var request = UnityWebRequest.Get("http://localhost:4567"); yield return request.Send(); Debug.Log(request.responseCode.ToString() + ":" + request.downloadHandler.text); } }
コルーチンで、通信終わるまで待つという点は今までと同じ。
WWWクラスの場合コンストラクタ呼び出したタイミングで通信しに行くが、UnityWebRequestの場合はSend
を呼び出したタイミングで通信する。
なので通信する前にSetRequestHeader
で諸々のヘッダ設定ができるようになった。
WWWと比較した時の違いを幾つか挙げるとこんな感じ
- RESTに対応
- データとHTTPのハンドリング部分が分離されている
- DownloadHandlerScriptでロギングや加工が便利
RESTに対応
多分これが一番大きな変更点。
ついにPUT、DELETEメソッドが実装された・・・。
PUTは引数にstringとbyte[]しか渡せない。 POSTはDictionaryが使用できるのでキーバリューペアでサクッといけるがPUTは自分で整形する必要がある。ちなみに文字列をバイト配列に変換する場合下記で行ける。
System.Text.Encoding.UTF8.GetBytes("foo=get")
引数を空文字列にした場合、以下のエラーが出る。
ArgumentException: Cannot create a data handler without payload data
因みにPATCHはないので、必要があればインスタンスのmethod
プロパティに直打ちしよう
request.method = "PATCH";
また、現状POST以外のメソッドはContent-typeが空になっている模様。 なので、そのままパラメータ付きでPUTしてもサーバ側によってはうまく受け取ってくれない可能性が高いので以下の感じでヘッダに組み込むのがいい
request.SetRequestHeader("Content-type", "application/x-www-form-urlencoded");
ここは修正されていくと思う、多分。
データとHTTPのハンドリング部分が分離されている
- 新しいHTTP通信は大まかに三つのクラスで構成されている
- UploadHandler
- DownloadHandler
- UnityWebRequest
UploadHandlerはリクエストを飛ばす際のパラメータデータ、DownloadHandlerはレスポンスのデータを保持する小さなクラスになっている。
その二つをUnityWebRequestが所有している。
UnityWebRequestはURLやヘッダ情報、リダイレクト回数の設定などHTTP通信に関する処理を扱う。
WWWと違い、データそのものと通信がしっかり分離しており扱いやすい。
UploadHandlerとDownloadHandlerは外部から流し込むことができるからだ。
UploadHandler
を外から設定する場合はUploadHandlerRaw
クラスを使う。
var request = UnityWebRequest.Get("http://localhost:4567"); var upload = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes("foo=get")); request.uploadHandler = upload;
コンストラクタの引数がバイト配列なので、変換が必要。 上記で書いたが、PUTはbody部分を空文字列にするとエラーになるので「適当な文字列を入れて初期化」->「uploadHandlerに流し込む」 という流れになった。もっといいやり方ありそう。
DownloadHandler
クラスそのものは流し込むことはできるがあまり意味はない。
むしろ、後述するDownloadHandlerScript
の時に役に立つ。
DownloadHandlerScriptでロギングや加工が便利
DownloadHandlerはダウンロード時の幾つかのタイミングでコールバックされる
ReceiveData
データを読み取った際に呼ばれるコールバックCompleteContent
読み取り完了した時に呼ばれるコールバックReceiveContentLength
ヘッダーからデータの長さを受け取った時に呼ばれるコールバック
データを読み取った各所でメソッドを呼ぶようになっており、Unityではそれをユーザ側でカスタマイズできるようにDownloadHandlerScriptというクラスを提供しています。
サンプルコードから抜粋
using UnityEngine; using System.Collections; using UnityEngine.Experimental.Networking; public class MyDownloadHandler : DownloadHandlerScript { // Standard scripted download handler - will allocate memory on each ReceiveData callback public MyDownloadHandler(): base() { } // Pre-allocated scripted download handler // Will reuse the supplied byte array to deliver data. // Eliminates memory allocation. public MyDownloadHandler(byte[] buffer): base(buffer) { } // Required by DownloadHandler base class. Called when you address the 'bytes' property. protected override byte[] GetData() { return null; } // Called once per frame when data has been received from the network. protected override bool ReceiveData(byte[] data, int dataLength) { if(data == null || data.Length < 1) { Debug.Log("LoggingDownloadHandler :: ReceiveData - received a null/empty buffer"); return false; } Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveData - received {0} bytes", dataLength)); return true; } // Called when all data has been received from the server and delivered via ReceiveData protected override void CompleteContent() { Debug.Log("LoggingDownloadHandler :: CompleteContent - DOWNLOAD COMPLETE!"); } // Called when a Content-Length header is received from the server. protected override void ReceiveContentLength(int contentLength) { Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveContentLength - length {0}", contentLength)); } }
上記のコードは、コールバックの各所でログに吐くような処理をしています。 あとは、これをUnityWebRequestのDownloadHandlerに流し込むだけです。
var request = UnityWebRequest.Get("http://localhost:4567"); var download = new MyDownloadHandler(); request.downloadHandler = download;
これで、データ受信時にログに吐いたり、ゲーム用にレスポンスを加工したりなど痒いところに手が届くようになる。
まとめ
現状、content_typeの問題など、まだまだこちらでカバーしなければならない問題はありますが、WWWクラスと比較するとかなり改善されており、期待が持てるAPIっぽい
明日は @yaegakiさんのmruby on Unityです
Phaserメモ
PhaserというWEB向けのゲームエンジンがあるので最近触っているので忘れないように殴り書き
ブラウザゲーもUnityでなんとかしようと思っていたのだけど、WebPlayerはもう使えないしWebGL出力はそれなりのサイズになってしまうのでまだまだ軽量とは言い難い。 ということで最近結構賑わっているという噂のPhaserで作ってみようかと考えた。
ついでにtypescriptも始めて見た。jsすらあんまり書けないけど。
メモ
日本語の資料はほとんどない。唯一下記サイトがわかりやすいかなという印象
Phaser入門:HTML5/Javascript 2Dゲームエンジン - catch.jp-wiki
ただ、異常なまでにサンプルコードが充実しているのでそれをひたすら読み解くべし。 phaser.io
シーン設計
Unityなどにおけるシーンの役割は、Phaserでは State
というものが担う。
preload
メソッド内でリソース系のロード、 create
でそのstate内のデータの初期設定をしてくれという感じ。
サンプル見た感じ、Stateの設計は下記のパターンが多い
Boot
Preloader
Hoge
Fuga
Hoge,Fugaは実際に遊ぶであろうStateの部分。MainとかGameOverとか。
まずはBootStateを読み込ませて、create
内でゲーム上で使用するstateを全部読み込む係になっている。PreloaderとかHogeとかFugaなど全部読み込む。完了後にPreloderに遷移する
PreloaderStateの preloader
で画像、音声などのアセットを読み込む。
複数のサンプルでBootとPreloaderがいたから、これはPhaserのお作法っぽい。
アニメーション
xmlだとかspritesheetとか幾つかあったけど、jsonにした。
流れは以下
上から順番に、上、右上、右、右下、下、左下、左、左上の8パターンの歩行グラフィックをそれぞれ4枚持ってる。
- 各スプライトの情報を保持するjsonファイルを用意
texturepackerを使うと、画像をまとめるのとPhaser用Jsonファイル出力の両方ができる
使い方はこちら
https://www.codeandweb.com/blog/2014/12/17/creating-spritesheets-for-phaser-with-texturepacker
今回もそれで吐こうとしたが、TexturePackerですでに出来上がってるatlasに対してスプライトの情報を与えるやりかたがわからなかった。バラバラの画像をペタペタ貼っていくときはスプライトの情報が追加されていくけど、既存の1ファイルだと1つのスプライトとみなされてしまい、それの分割方法がわからなかった。
なのでjson生成スクリプト書いた https://gist.github.com/adarapata/c96048cd99f6ef7d9537 自分の持ってる画像はほぼほぼ上記のパターンなのでこれで生産できるようになった。
こんな感じ
this.game.load.atlasJSONHash("iku", "assets/images/chara_iku.png", "assets/atlases/iku.json");
アニメーションは、コード内で実装する必要がある。下記は上方向歩行モーションの設定
iku.animations.add("walk_up", ["up_0","up_1","up_2","up_3"], 10, true, false); iku.animations.play("walk_up");
単純に配列でスプライト名を指定していけばその順番で再生してくれるみたい。 スプライト名のルールを決めておけば同じフォーマットで複数キャラ対応できそう。 UnityでのAnimatorみたいな動きはできるかもしれない。
ちなみにチュートリアルでローカルサーバ立てるためにXAMPP入れようみたいなこと書いてるけど、多分sinatraが一番楽だと思う。
UniRX使ってOnRaycast的な処理を書く
小ネタ
OnTriggerEnterとかそういう感じで、レイにぶつかった瞬間、ぶつかっている間、レイから離れた瞬間を検知したいなという気持ち。
一案としてこのような感じ
using UnityEngine; using System.Collections; using UniRx; using UniRx.Triggers; using System.Linq; public class OnRaycastHit : MonoBehaviour { Subject<Unit> onRaycastStayStream = new Subject<Unit> (); public IObservable<Unit> onRaycastStayAsObservable { get { return onRaycastStayStream.AsObservable (); } } Subject<Unit> onRaycastExitStream = new Subject<Unit> (); public IObservable<Unit> onRaycastExitAsObservable { get { return onRaycastExitStream.AsObservable (); } } Subject<Unit> onRaycastEnterStream = new Subject<Unit> (); public IObservable<Unit> onRaycastEnterAsObservable { get { return onRaycastEnterStream.AsObservable (); } } private bool isOnNext; public void RaycastHit () { isOnNext = true; } void Start () { this.UpdateAsObservable (). Select (_ => isOnNext). Buffer (2, 1). Subscribe (list => { bool before = list.First (); bool current = list.Last (); if (!current && before) onRaycastExitStream.OnNext (default(Unit)); if (current && !before) onRaycastEnterStream.OnNext (default(Unit)); if (current) onRaycastStayStream.OnNext (default(Unit)); isOnNext = false; }); } }
Raycastで引っかかった時に RaycastHit
を呼ぶイメージ。
そのフレームだけisOnNextがtrueになり、Buffer(2,1)で前フレームとの値と比較してOnNextの対象を変える。
isOnNextが結構強引な気がしていて、まだ良い方法あるんじゃないかと考えてる