ラベル メモ の投稿を表示しています。 すべての投稿を表示
ラベル メモ の投稿を表示しています。 すべての投稿を表示

2014年8月27日水曜日

angularでng-annotateを利用してminify対策を自動化する


ng-annotate is 何

ng-annotateとは前回書いたangularJSのminify問題に対応するアプリケーションです。 ソースコードを解析して自動的にdependency annotationを付けてくれます。
ng-annotate適用前
angular
  .module('ngAnnotationTestApp', ['ngRoute'])
  .service('HogeService', function($scope){
    //...
    console.log($scope);
  });
ng-annotate適用後
angular
  .module('ngAnnotationTestApp', ['ngRoute'])
  .service('HogeService', ["$scope", function($scope){
    //...
    console.log($scope);
  }]);
もともと同様のアプリケーションにngminというのがあったのですが 今は、「ng-annotateを使ってくれ」となっています。 ※プロジェクト自体が非推奨になっている
angularを使っている人なら大体使ったことが有るであろうyeomanのgenerator-angularも 現行の最新リリースバージョンではngminを利用していますが、 レポジトリにある最新バージョンはng-annotateを利用するように修正されています。

使い方

ng-annotateはnpmでそれ単体でも利用することができますが、 大抵のタスクランナー(gruntやgulp,browserify)用pluginも出ているようです。
今回はお試しなのでstandaloneで動くバージョンを利用してみようと思います。

インストール

npmでグローバルインストールします。
$ npm install -g ng-anntate
インストールするとng-annotateコマンドが利用できるようになります。

実行

以下の様なsyntaxです。
$ ng-annotate OPTION 
$ ng-annotate -ar -o app/scripts/app.annotated.js app/scripts/app.js
ng-annotateではDependency Annotateの追加/削除を指定することができます。 追加は-a、削除は-rオプションです。両方指定(-ar)すると作り直しになります。
またデフォルトではファイルは作成せず、標準出力への出力になるので、 ファイルに吐き出す場合は-oオプションを使って下さい。
その他のオプションはいい感じで調べて下さい。

対応しているメソッド

ng-annotateは特定のメソッドやコメントを探してコード変換を行います。 対応しているのは以下らへんです。
.controller, .config, .factory, .directive, .filter, .run, .controller, .provider, .service, .animation and .invoke.
またdirective内のcontrollerプロパティ、$routeProvider.when内部、 ui-router等の一部サードパーティ製ツールにも対応が行われているようです。
また明示的に@ngInjectコメントを付与することでも明示的注釈が追加されます。
var x = /* @ngInject */ function($scope) {};

まとめ

ngAnnotateはもともとパフォーマンスが良いように設計されているらしく、 比較的gruntなどで動かしてもそこまで処理に時間がかかりません
angularのminify問題は結構後に気がつくこともあるので、 こういったもので対策を行っておくのも良いかなと思います。
あと今回は触れませんでしたが、ngAnnotateはpluginも作れるので、 コードをパースして何かの処理を挟み込みたい人は使ってみるのが良いと思います。

2014年8月25日月曜日

angular1.3から追加されるng-strict-diを使ってminifyに強くする。

angular1.3から追加される(そう)strict-diモードについて覚書

ng-strict-diとは?

ng-strict-diとはng-app directive と一緒に付加することで、 injectorをstrict-diモードにすることができるng-appのオプションです。

何を解決するか

strict-diモードを利用することで、Dependency Annotationのつけ忘れを防ぎます。

strict-diモードとangularのminify問題

angularのDependency Annotation

AngularJSのDIには大きく分けて3つの注釈が存在します。 AngularJSではこの注釈(annotation)を利用して名前解決をし、Service等のDIを行っています。
  • functionのパラメータ名による暗黙的な注釈
  • $injectプロパティを利用した注釈
  • inline arrayを利用した注釈

functionのパラメータ名による暗黙的な注釈

パラメータ名による暗黙的な注釈は以下のようにパラメータ名を利用してDIを行います。
function MyController($scope) {

} //angularは$scopeという変数名を利用しscopeオブジェクトを代入する

$injectプロパティを利用した注釈

$injectプロパティは注入対象に対してstring arrayとともに付加することで、 名前解決をし、代入を行います。
var MyController = function(renamed$scope, renamedGreeter) {
  ...
}
MyController['$inject'] = ['$scope', 'greeter']; //renamed$scopeにはscopeオブジェクトが代入される

inline arrayを利用した注釈

inline arrayは注入対象をangularに登録する際に一緒に指定する方法です。
someModule.factory('greeter', ['$window', function(renamed$window) {
  // ...
}]);

暗黙的な注釈の問題点

一見暗黙的な代入は記述量も少なく便利なのですが一つ大きな問題があります。 それはminify時に変数名が変わる可能性がある(と言うよりだいたい変わる)点です。
minify前
function MyController($scope) {

} //angularは$scopeという変数名を利用しscopeオブジェクトを代入する
minify後
function A(a) {

} //minifyにより変数名が変わってしまう
このため、minifyをする予定がある場合は後半二つの明示的に注釈する方法が一般的に取られます。 ただ確実にこの注釈を行っているかチェックを行う方法はありません。 というかよく忘れます。

strict-diモード

これらの問題を解決するのがstrict-diモードっぽいです。 strct-diモードはng-appが付いているタグにng-strict-di属性を付けることでstrict-diモードになります。
  <body ng-app="ngStrictTestApp" ng-strict-di>
この状態で暗黙的な注釈を利用している箇所があると以下の様なJSエラーが発生します。
Uncaught Error: [$injector:modulerr] Failed to instantiate module ngStrictTestApp due to:
Error: [$injector:strictdi] function($routeProvider) is not using explicit annotation and cannot be invoked in strict mode
http://errors.angularjs.org/1.3......2) 
これで付け忘れることはなくなりますね。

まとめ

ng-strict-diはngAnnotationのことを調べている時に気が付きました。 よく明示的な指定を忘れて、minifyしてエラーになることが多いので指定しておいて損はない気がしますね。
ただし、最初にも書きましたがAngularJS 1.3からの機能っぽいです。

AnsibleでGCE(Google Compute Engine)を触る

今日はAnsibleでGCEを触りました。
先に参考リンクを貼っていますが、色々見ている通り結構ハマリました。

参考にしたの

環境

  • OS X 10.9.4
  • ansible 1.7
  • apache-libcloud 0.15.1

やってく

やったのは
  • GCEのサーバ2台作って
  • apache入れる
です。
多分上記の参考にした記事を見えればできると思うのですがいくつかハマったのでだらだら書いていきます。

0. ディレクトリ構成

1. apache-libcloud をインストール
pipでインストールします。
$ sudo pip install apache-libcloud

2. CA cert chainの取得

http://curl.haxx.se/docs/caextract.html から
「HTTP from curl.haxx.se: cacert.pem」をダウンロードしておきます。

3. 認証情報の作成

3.1. Compute Engine用の証明書ファイルを作成する

Developer Consoleにて
Compute Engineを使う対象のProjectの「APIと認証」> 「認証情報」から「新しいクライアント IDを作成」を押して、
サービスアカウントとして、新しいクライアントIDを作成
作成後「新しいP12キーを作成」から認証ファイルをダウンロード
ダウンロードしたらpem形式に変換
$ openssl pkcs12 -in {ダウンロードしたp12ファイルパス} -passin pass:notasecret -nodes -nocerts | openssl rsa -out /path/to/pkey.pem
credentialsディレクトリに突っ込んでおく。

3.2. secrets.py (認証情報の設定)

secrets.pyは最初にインストールしたlibcloudが利用する認証情報の設定ファイルで以下の様なフォーマットです。
これをcredentialsディレクトリに入れておきます。
ただAnsibleの公式ドキュメントや、Qiitaの方にはsecrets.pyが書いてあるのだけど、本当に作る必要があるのか疑問があります。
というのもAnsibleのドキュメント上ではこのファイルを作ると、playbook内でmoduleに認証情報を渡す必要がないと書いてあるのですが、
どうもうまくいかない。。。
そもそもこのsecrets.pyは2つの観点で利用されているようです。
  1. gce* moduleがgce apiを叩くための認証情報として利用
  2. Dynamic Inventoryで利用
前者が上記に書いてあるplaybook内でmoduleに認証情報を書かなくて良くなる部分なのですが、
実際に叩いてみると、たとえPTYHONPATHsecrets.pyが置かれているディレクトリが存在したとしても
import secretsが失敗しているようです。
※ansibleのgce moduleでimport secretsしているのは ここ
この編Pythonの知識不足ですね...
もう少し色々やってみますが、、、、
後者は後述します。

4. Inventoryの設定

4.1. ローカルホスト用(hosts)

GCE自体の設定(instanceの設定や、networkの設定)はローカルPCからGCEに対して行うので、
localhostの設定をinventoryに行います。
inventoryディレクトリにhostsファイルを作成し以下のように記述しておきます。



4.2. GCE用のDynamic Inventory
Dynamic Inventoryは動的にInventoryを作成する方法で、任意のスクリプトで、
Inventoryを作成することができます。
例えばGCEの場合instanceを立てるごとにipなどが変わってしまう為、
接続先情報を取得するのに必要です。
GCE用のDynamic Inventoryで利用されるスクリプトは公式レポジトリに置いてあるのでそれを使います。
Ansibleのレポジトリから以下の2つのファイルを持ってきて、
inventoryディレクトリに置いておきます。
  • plugins/inventory/gce.ini
  • plugins/inventory/gce.py
※普通にコピペして持ってくるでOKです。
そして、gce.iniを設定します。
4.2.1. gce.iniの設定
gce.iniでは 3.2. secrets.py で作成したsecrets.pyのパスを指定するか、
secrets.pyに記述したような情報を直接記載するかが選べます。
気になり毎
GCE Dynamic Inventoryを利用するとGCEインスタンスをタグごとにInventoryにまとめてくれたりします。
例えば、4インスタンス(www1,www2,db1,db2)作成してあり、それぞれ2台ずつwebserver(www1,www2)とdbserver(db1,db2)というタグがついていた場合、
GCE Dynamic Inventoryを利用すると tag_webserverというinventoryとtag_dbserverというinventoryを自動的に作ってくれます。
またzoneやrigionごとのinventoryも作成してくれるため、非常にplaybookが書きやすくなります。
ただ、このDynamic Invetoryはansible-playbookが起動する際に読み込まれるようで、
少し問題が有ります。
例えば以下の様なplaybookがあるとします。
  1. 4台のgceインスタンスを作成(tags: webserver, dbserver)
  2. 2台(webserver)にhttpdをインストール
  3. 2台(dbserver)にredisをインストール
この時dynamic inventoryは1.の手前で読み込まれるようです。
つまりまだGCEインスタンスが作成されていない場合は、webserverもdbserverも存在しないため、
2.,3.でtag_webserver inventoryを利用することができないようです。
※playbookが起動する前に、既にGCEインスタンスが作成されている場合は2.,3.で利用することができます。
この辺りはちょろっと微妙だな~と思っています。
実際には2.の手前でDynamic Inventoryを利用してInventoryをリロードして、
2.,3.の工程で利用したいところですが、なんとなーくその辺を探してもなさそうです。
※あったらだれかおしえてくだしぃ
そうなるとインスタンスを立てて、その後ミドルの設定のようなplaybookは2回起動するか、
分ける必要があります。
自前でリロードするmoduleを書けばいいのかもですが...

5. playbookを作成

上記を踏まえて以下の感じになります。
ポイントはDynamic Inventoryを利用してtag_webserverというinventoryを使ってるラ変です。
ただ前述したとおりインスタンスがまだ存在しない場合は、
2回起動しないと思っている状態になりません。
なお
  • "vars/instance.yml"
  • "vars/gce_auth.yml"
は以下の感じです。

6. 起動を作成

あとは普通に起動します。

$ ansible-playbook -i inventory/ master.yml

まとめ

まだまだサンプルが少ないのと、実際に利用されている感じが無いのが厳しいところですね。。。
そもそもGoogle Compute Engine自体がコレ系のセットアップツール(Deployment Manager)をもっているようで(limited previewですが)
この手のサードパーティ製のツールはどこまで対応されるんだっけ?という雰囲気もあるので
仕方ないといえば仕方ないのですが...

2014年8月20日水曜日

AnsibleからVPC立てる

前置き

最近awsやgcpを触っていて、せっかく作った構成を他の人とかにも共有したいなーと思ってました。
Chefも触ったのですがなんとなーく肌に合わず、最近はAnsibleを使っています。
awsだけだとCloudFormationも有るのですがある程度のサイズになってくると、JSONは微妙ですね... CloudFormationをCoffeeScriptやRubyで書く色々なものも有るのですが、 だったら他のモノのクラウドも一貫して触れる物が良かったのでansibleにしています。

今回やること

以下の様なAWS VCP環境をAnsibleで作ります。

Playbookとかとか

構成

ベストプラクティスっぽい環境 VPCとか「ネットワーク構成」ってRoleに入れるのかな?? 区切りはよくわかないですね
.
├── ec2-servers #hosts
├── envs/ #環境設定 varsとか同じ感じ
│   └── dev.yaml 
├── group_vars/
│   └── all.yaml #awsのクレデンシャルとかリージョンを定義してます。
├── network.yml 
├── roles/
│   └── vpc/ #vpcの設定を行うRole
│       ├── tasks/
│       │   └── main.yaml
│       └── vars/
└── sites.yaml

コード

全般的に↓においてあります。
また以下を参考にしています。

envs/dev.yaml

環境設定を行います。
roles/vpc/tasks/main.yaml内でincludesしていてコマンド引数 environとかで、環境名(production.yamlとか)で設定を変えられます。

group_vars/all.yaml

AWSのクレデンシャルとか全般の設定を行っています。

roles/vpc/tasks/main.yaml

実処理です。 ほとんどdev.yaml内に書いてしまっているので外枠のみですが、ネットワーク周りをyamlで掛けるのはいいですねぇ ただ、route tablesの設定でprivate subnet的なものを作りたいのですが、どうしても空のroute tablesが作れなくてうまく行っていません。 ダミーで適当なroutingを作って後から消すとかがいいんですかね