2015年12月30日水曜日

EdgeRouterLiteを触ってみる

このブログはすごい広島#137の成果です。
(なお、この日は同時にとても大事なイベントがあったのですが、あくまで「すごい広島」ということで・・・)

VyattaからフォークしたVyOSをMIPSなCPUで動くように移植したEdigeRouteLiteを購入しましたので、まずはつなげれるように最低限IPの設定をしました。

このルータは17,000円という格安ながらVyOSベースということもありスペック上は中々高性能です。
しかも、Webインターフェースもあるらしい。
RTX1200が定価10万越えだったりします。まぁ中古で2万切っていますけど。

このルータはNICの口がそれぞれeth0~eth2までの3つあります。
実はeth0にIPが割り当てられているのですが、説明書なんて読まずにいきなりシリアルコンソールでつなぎます(笑)
シリアルコンソールは俗に言うシスコ的なケーブルが使用でき、通信速度は115200bpsです。

起動しますと、

ubnt login:
と出ますので、デフォルトではID、PW共に「ubnt」でログインできます。


Linux ubnt 2.6.32.13-UBNT #1 SMP Tue Jun 4 14:54:28 PDT 2013 mips64
Welcome to EdgeOS
ubnt@ubnt:~$
とでたら、以下のコマンドを打って、編集モードに移行します。

ubnt@ubnt:~$ configure
[edit]
と出てきたら、編集モードになっています。

では、まず現在のNICの設定状況を確認します。
以下のコマンドを実行します。なお、コマンドはTAB補完が効きますし、途中まで打ったら候補が出てきます。このあたりVyattaの頃から大変便利です。

ubnt@ubnt# show interfaces ethernet
こんな感じで出てきます。

 ethernet eth0 {
     address 192.168.1.1/24
     duplex auto
     speed auto
 }
 ethernet eth1 {
     duplex auto
     speed auto
 }
 ethernet eth2 {
     duplex auto
     speed auto
 }
現在はeth0に192.168.1.1が割り当てられているようですね。
では、eth2に192.168.0.1/24を割り当ててみます。
ubnt@ubnt# set interfaces ethernet eth2 address 192.168.0.1/24
何となく、eth2のところをeth1とかにしたら変わりそうですし、
addressの後はdhcpにしたらDHCPになりそうですね。
このように、コマンドも分かりやすいです。
VyOSもといEdgeOS(このルータのOS)は、普通のルータと違い、設定しただけでは反映されません。
では、設定を確認します。

ubnt@ubnt# show interfaces ethernet
今度は変更点が+で出ています。

 ethernet eth0 {
     address 192.168.1.1/24
     duplex auto
     speed auto
 }
 ethernet eth1 {
     duplex auto
     speed auto
 }
 ethernet eth2 {
+    address 192.168.0.1/24
     duplex auto
     speed auto
 }
では、変更を確定させます。

ubnt@ubnt# commit
これで、eth2にIPが割り当てられました。
再度設定を確認すると、+がなくなっています。

この状態では、設定は有効ですが、ファイルに保存されていません。
つまり、電源を切ると元に戻ります。

変更内容をファイルに保存するために以下のコマンドを実行します。

ubnt@ubnt# save
これで、電源を切っても内容が保存され、次回以降も設定が有効になります。
電源を切って、再ログインし、設定が保存されているか確認してみましょう。

実際の設定はVyattaのコマンドが参考になると思います。













2015年12月27日日曜日

EdgeRouterLiteがきた!

年末の押し迫った中、来年来るかなーと思っていたEdgeRouterLiteが来ました!
注文してから2日ほどで到着。早っ!

というわけで、通電前に早速バラしてみました(笑)
なお、6ヶ月ほど保障があるようです。分解すると多分保証はなくなると思います。

箱がでかくてビビリましたが、単に2重底になっていて、下にACアダプタが入っていました。

大きさ的には普通のルータより一回り小さいくらいですね。

左が付属のもの。右が代理店が付属しているものになります。
付属のものはPSEマークが無いので、国内使用が出来ないようです。
随分大きさが違いますが、表記上は両方とも12V1Aらしいです。


構造的には以外にシンプル。業務用ルータというより市販の俗に言うブロードバンドルーターぽい感じですね。

 特筆すべきは、流石寿命を決定付ける電解コンデンサが電源部にも一切使用されていません。
ただ、逆刺し保護はダイオードのみで、ヒューズがあるわけでもないので、規格外のACアダプタつなげるとDCDCが死にそうです。


各NICのチップは蟹なんて使っていませんが、Atherosのチップが使用されています。
Atherosは無線LANで有名ですが、有線LANのチップも作っているんですね。

OSが入っていると思われるUSBメモリです。
4GBっぽいです。(一説によると2GBらしい)
CPUアーキテクチャが違うので、OS書き換えの際は注意が必要です。
なお、アクセスランプはついていないので、起動中に光ったりはしません。

こんな感じで普通にUSBが出ています。
が、どうもちゃんとしたUSB規格ではないようで、何でも刺さるわけではなさそうです。
サンディスクの奴はいけるらしい??
なお、通信は俗に言うシスコ的なケーブルでつなげばいけます。
通信速度は115200bpsでした。


AWS-SDK For Ruby V2に対応してみた。

AWS SDK For Rubyのバージョンが2にあがってはや一年がたとうとしています。
AWSなどのクラウドサービスはAPIを叩いて自動化が出来るのがメリットのひとつでして、
自分も簡単なスクリプトを作成して自動化、省力化をしています。

そんな中、AWS SDK For Rubyのバージョンが2に上がり、これまでのバージョン1とは互換性がない為、絶賛稼働中のものや、作りこんだChefのレシピなどは簡単に移行できませんし、
テストも容易ではなかったりします。

しかし、いつまでもバージョン1を使い続けると、いつかは切られてしまうので、練習がてらGitHubにあげているものをバージョン2に対応させてみました。

一応バージョン1とのDIFFはこの辺りにあります。
バージョン2でcoreとリソースに分離したのですが、いまいちリソースの使い方というか使い勝手が分からなかったので、coreのみで作成しています。

バージョン1と2での大きな違いは、バージョン1では大抵戻り値としてインスタンスのオブジェクトが返っていたのですが、バージョン2では単なる構造体が返って来ます。
あと、バージョン1ではステータスの変化を検知するためにウエイトをかけたりループをまわしたりしていましたが、バージョン2ではwait_untilという専用メソッドが追加されています。

今まではいろんなリソースタイプやコレクションをそれぞれ組み合わせて叩いていたので結構大変でしたが、バージョン2では引数として文字列か数値がとシンプルになっていますし、Filterオプションが強力になっているので、全体的に短い行数で書けるようです。
ただ、今まで戻り値がオブジェクトだったので、チェーンメソッドが書けたのですが、そういうわけには行かなくなりました。

ただ、バージョン1と2でのメソッドの対比表みたいなものは無いので、バージョン1でのこのメソッドに該当するメソッドはどれか探すのが地味に大変です。
同じメソッド名のものもあれば、ec2.instance.create->ec2.client.run_instancesのようにまったく違うものもあります。

単純に置き換えは難しそうですが、この記事が少しでも役に立てればと思います。


2015年12月26日土曜日

RubyのOptionParserで地味にはまった

今まで動いていたのに、オプションを増やしたら謎の挙動をして、数時間を無駄にしたのでメモ。

Rubyでコマンドライン引数処理をするのに、optparseを使う人が多いと思います。

こんな感じで使います。

require "optparse"
opts = OptionParser.new
# 引数
opts = OptionParser.new
instance_type = nil
opts.on("-t","--instance_type INSTANCE_TYPE") do |type|
  pp type
  instance_type = type
end
# よく忘れるパーズ実行
opts.parse!(ARGV)
これで、たとえば
ruby hoge.rb -t t2.small
見たいにすると、instance_type変数にt2.smallという値が入ります。
opts.onの第一引数にはショートオプションを、第二引数にはロングオプションとオプションの説明を入れます。
--からはじめるとロングオプションとして認識します。
ロングオプションはどのオプションか一意に決まる長さまで指定すれば良いです。

で、ここでオプションを増やします。
private_ip = nil
opts.on("-ip","--private_ip PRIVATE_IP_ADDRESS") do |ip|
  pp ip
  private_ip = ip
end
さて、これは正しく動作しません(笑)
ruby hoge.rb -ip 192.168.0.1
としても、private_ipには何故か"p"という文字が入ります。
ruby hoge.rb --private_ip 192.168.0.1
だと正しく動き、private_ipには"192.168.0.1"という文字が入ります。
大抵デバック時には引数を埋め込むため気づきませんでしたが、
ショートオプションはアルファベット1文字しか有効ではなく、それ以降の文字列は引数と認識されます。

なので、
private_ip = nil
opts.on("-i","--private_ip PRIVATE_IP_ADDRESS") do |ip|
  pp ip
  private_ip = ip
end
と同じ挙動になり、-ipというオプションは-iオプションに引数pを渡していることになります。

え?常識(汗

よく見たらマニュアルにちゃんと書いてありましたね(汗

ショートオプションの引数指定は使いにくいので、このような場合はロング オプションの方が使う方もわかりやすいです。例えば、上記の場合、-ab を 指定すると -a b と解釈されます。-a が引数を持たない最初の例なら -a -b と 解釈されます。






2015年12月20日日曜日

AnsibleでPostgreSQLのユーザを作成するときに気をつけること。

このところ、暇があればAnsibleを触っています。

前回まではLAMP構成を作ってみましたが、今回はPostgreSQL環境を構築しようとして、
ユーザ作成で地味にはまったのでメモ。

AnsibleでPostgreSQLのユーザを作成するとき、以下のようにします。
*AnsibleのDocumentより抜粋
# Create rails user, grant privilege to create other databases and demote rails from super user status- postgresql_user: name=rails password=secret role_attr_flags=CREATEDB,NOSUPERUSER
なるほど、role_attr_flagsに割り当てる権限を指定するのだな。
というわけで、次のようにしてみました。

 - name: ユーザ作成
   postgresql_user:
     db: "{{ pgsql_dbname }}"
     name: "{{ pgsql_dbuser }}"
     password: "{{ pgsql_dbpass }}"
     priv: ALL
     encrypted: yes
     state: present
     login_user: postgres
     role_attr_flags: "NOSUPERUSER,NOCREATEDB,NOCREATEUSER,NOCREATEROLE"
   sudo_user: postgres
   sudo: yes
 しかし、これはエラーになります。
何故か?と小一時間悩んだのですが、どうやら、NO_SUPERUSER権限は既にNOCREATEDBなどの権限を有しているため、重複するロールを指定するとエラーになるようです。参考

なので、通常はNO_SUPERUSERだけで事が足りそうです。
自分は明示的に指定したかったので、以下のようにNOSUPERUSERを外しました。

 - name: ユーザ作成
   postgresql_user:
     db: "{{ pgsql_dbname }}"
     name: "{{ pgsql_dbuser }}"
     password: "{{ pgsql_dbpass }}"
     priv: ALL
     encrypted: yes
     state: present
     login_user: postgres
     role_attr_flags: "NOCREATEDB,NOCREATEUSER,NOCREATEROLE"
   sudo_user: postgres
   sudo: yes


2015年12月16日水曜日

CentOS6+PHP5.6+MySQL5.6でハマった

久々にかなりはまったのでメモ。

CentOS6に最新のPHP5.6をremiで入れて、MySQL5.6をcommunityリポジトリから入れると、
php-mysql-5.4.45-2.el6.remi.x86_64が依存関係でインストールできません。
lib-mysqlがらみですと、MySQLの公式サイトが配布しているMySQL-shared-compatをインストールすればいいのですが、これはあくまでRedHatのリポジトリにあるlib-mysqlの依存性が解消されるだけで、remiで入れたphp-mysqlが依存している mysql-libs-5.5.47-1.el6.remi.x86_64には無力のようです。

ググってみた感じ、結構詰まっている人が多いようですが、いろいろやった結果、解決法としては

php-mysqlではなく、php-mysqlndをつかう。

というものでした。
php-mysqlndはMySQLのネイティブドライバらしく、MySQLのクライアントが不要らしいです。
(つまり、lib-mysqlにも依存しない)
PHP5.3以降にふくまれており、mysqlndドライバを使用することを強くお勧めするらしいです。



2015年12月11日金曜日

AWSのMicrosoft-ADを試してみた。



2015/12/3に発表されたAWSのクラウド上のマネージド型MicrosoftActiveDirectoryを触ってみました。
といっても、触った感じSimple-ADとの違いが分からない(汗


例によってWiKiにまとめています。

ChefのLWRPについて

いい加減まとめないとなぁと思いつつはや幾年・・・
ChefのLWRPについてのメモ

ここより詳しい解説がこの辺りにありますけど・・


LWRPとは、簡単に言うとレシピ内で使用するリソースを自分で定義したものです。
これの何がうれしいかというと、レシピの中でゴリゴリ書いているとどうしても可読性が落ちたり、
汎用性に乏しかったりするのですが、それを隠蔽し、共通処理をくくりだすことにより再利用しやすくなります。
たとえば、ApacheのインストールはApacheのクックブックで出来ますが、その後ほぼ必ずConfの設定が必要だったり、証明書の設置などが必要になります。
それらはほぼ同じ処理なのにドメイン名が違うなど微妙に異なります。
また、DBをインストールするときも同様にConfの設定やユーザの作成、DBの作成やバックアップなどのレシピが必要になります。

それらを隠蔽し、リソースのように定義できれば可読性も上がり、コピペミスによる動作不良などを防ぐことが出来ます。


LWRP自体はエディタでゴリゴリ書いてもいいのですが、ここではChefdkをインストールし、スケルトンを作成します。

まずは以下のコマンドを実行し、クックブックとLWRPのスケルトン(雛形)を作成します。
chef generate cookbook test
cd test
chef generate lwrp testlwrp

このようなディレクトリ、ファイルが作成されます。

C:.
└─test
    ├─providers
    ├─recipes
    ├─resources
    ├─spec
    │  └─unit
    │      └─recipes
    └─test
        └─integration
            ├─default
            │  └─serverspec
            └─helpers
                └─serverspec
LWRPで使用するのは、このうちprovidersとresourcesです。
この2つのディレクトリには同じファイル名「testlwrp.rb」が生成されています。
この2つのファイルはペアで使用するため、必ず同じファイル名にする必要がありかつ、
LWRPで作成するリソース名にする必要があります。

ここでは、簡単な例として、/tmp/hogehogeというファイルに指定した内容を書き込むものを作成します。

まず、resourceディレクトリ内にあるtestlwrp.rbに以下の内容を記載してください。

# デフォルトのアクションを指定
default_action :install
#このLWRPで定義するアクション
actions :install, :uninstall
#アトリビュートを定義する。
attribute :input_data, :kind_of => String, :required => true

次に、providersディレクトリ内にあるtestlwrp.rbに以下の内容を記載してください。

def whyrun_supported?
  true
end
action :install do
  converge_by("install test #{new_resource.input_data}") do
    file "/tmp/hogehoge" do
      mode "0644"
      content "install test #{new_resource.input_data}"
      action :create
    end
  end
end
action :uninstall do
  converge_by("uninstall test #{new_resource.input_data}") do
    file "/tmp/hogehoge" do
      mode "0644"
      content "uninstall test #{new_resource.input_data}"
      action :create
    end
  end
end


では順に説明していきます。
resourceでは以下の内容を記述しました。
# デフォルトのアクションを指定
default_action :install
chefのリソースを使用する際、アクションと呼ぶ処理の塊を呼び出します。
無指定の場合呼び出すアクションを規定します。
#このLWRPで定義するアクション
actions :install, :uninstall
コメントのままなんですが、このLWRPに定義されているアクションを列挙します。
列挙されているものが外部のレシピから使用することが出来ます。

#アトリビュートを定義する。
attribute :input_data, :kind_of => String, :required => true
このLWRPのに渡す引数です。
input_dataが引数を格納する変数名、kind_ofで引数の型を、requiredで必須入力がそうでないかの指定をします。

次に、実際の処理が記述されているproviderを見ていきます。

頭に以下のような記述があります

def whyrun_supported?
  true
end

これはwhy-runをサポートしているよ。という宣言になります。
why-runって何?なのですが、実際には実行しないテストモードになります。

次にinstallアクションを見ていきます。

action :install do
  converge_by("install test #{new_resource.input_data}") do
    file "/tmp/hogehoge" do
      mode "0644"
      content "install test #{new_resource.input_data}"
      action :create
    end
  end
end
action :install ブロックでinstallアクションを定義しています。
converge_byブロックで囲まれた中身が実際の処理になります。
fileリソースを使用して、/tmp/hogehogeファイルを作成しています。
このように、レシピを書く感じでほかのリソースを呼び出したりして作成することが出来ます。

ここで、new_resource.input_dataという変数を参照しています。
前述のアトリビュートで宣言した変数名の前に、new_resourceをつけることで、その中身を参照することが出来ます。

同様にuninstallアクションも定義してあります。

では、作成したLWRPを動かしてみます。
今回は作成した一式をVagrant上のCentOSで動作させます。
Chefサーバを用意してとかは大変なので、chef-soloでお手軽に実行したいと思います。
まずは、vagrantのディレクトリに作成したディレクトリを一式置きますと、Vagrantないでは/vagrant配下で参照できます。
recipeディレクトリのdefault.rbを以下のように記述します。

test_testlwrp "lwrp_test" do
  input_data  "test"
end
LWRPで作成したリソースを呼び出すには、<クックブック名>_<LWRP名>で呼び出すというルールがあります。
今回作成したのはtestクックブックのtestlwrpという名前なので、test_testlwrpという名前で呼び出します。
このブロックに囲まれたinput_dataというのがアトリビュートですね。
では、chef-soloを動かす準備をします。
/vagrant/testという感じで作成したクックブック一式が見えている前提です。

/vagrant/solo.rbというファイルを作成し、中身に以下の記述をします。

cookbook_path [/vagrant]
では、chef-soloを実行してみましょう。まずはwhy-runモードで変更を加えずに実行してみます。
 chef-solo -c ./solo.rb -o test -w
こんな感じに出ればOKです。

Starting Chef Client, version 11.8.0
[2015-12-11T13:32:13+00:00] WARN: Run List override has been provided.
[2015-12-11T13:32:13+00:00] WARN: Original Run List: []
[2015-12-11T13:32:13+00:00] WARN: Overridden Run List: [recipe[test]]
Compiling Cookbooks...
Converging 1 resources
Recipe: test::default
  * test_testlwrp[lwrp_test] action install
    - Would install test test
Chef Client finished, 1 resources would have been updated
作成したテスト用のレシピ(default.rb)にはアクションを明示的に指定していませんでしたが、デフォルトのアクションであるinstallが呼ばれています。
また、ファイルの中身として、install test testになることが示されています。
また、実際に/tmp/hogehogeファイルは作成されていません。シミュレーションしただけですね。

では、アクションを変えてみます。default.rbを次のように変更して再度chef-soloを実行してみます。

test_testlwrp "lwrp_test" do
  input_data  "test"
  action :uninstall
end
Starting Chef Client, version 11.8.0
[2015-12-11T13:37:11+00:00] WARN: Run List override has been provided.
[2015-12-11T13:37:11+00:00] WARN: Original Run List: []
[2015-12-11T13:37:11+00:00] WARN: Overridden Run List: [recipe[test]]
Compiling Cookbooks...
Converging 1 resources
Recipe: test::default
  * test_testlwrp[lwrp_test] action uninstall
    - Would uninstall test test
Chef Client finished, 1 resources would have been updated

installの箇所がuninstallに変わりましたね。
では、実際に適用してみましょう。

chef-solo -c ./solo.rb -o test
Starting Chef Client, version 11.8.0
[2015-12-11T13:45:18+00:00] WARN: Run List override has been provided.
[2015-12-11T13:45:18+00:00] WARN: Original Run List: []
[2015-12-11T13:45:18+00:00] WARN: Overridden Run List: [recipe[test]]
Compiling Cookbooks...
Converging 1 resources
Recipe: test::default
  * test_testlwrp[lwrp_test] action uninstall
    - uninstall test test
Recipe: <Dynamically Defined Resource>
  * file[/tmp/hogehoge] action create
    - create new file /tmp/hogehoge
    - update content in file /tmp/hogehoge from none to 3c37bb
        --- /tmp/hogehoge       2015-12-11 13:45:18.458044278 +0000
        +++ /tmp/.hogehoge20151211-27701-vdbtpv 2015-12-11 13:45:18.460044278 +0000
        @@ -1 +1,2 @@
        +uninstall test test
    - change mode from '' to '0644'
Chef Client finished, 2 resources updated
uninstallアクションが実行され、/tmp/hogehogeファイルが作成、パーミッションが0644、中身がuninstall test testなファイルが作成されました。
一応中身を確認してみましょう。

[root@localhost vagrant]# more /tmp/hogehoge
uninstall test test
[root@localhost vagrant]# ls -lah /tmp/hogehoge
-rw-r--r-- 1 root root 19 Dec 11 13:45 /tmp/hogehoge
意図したとおりになっていますね。

以上簡単ですけれど、基本的な動作は抑えていると思いますので、これを応用すればオレオレリソースを作成するのも可能だと思います。
さらに複雑、高度なリソースを定義しようとすると、Rubyのモジュールやクラスを作成して呼び出す・・・なんてことも出来ます。
ただ、あまりRubyをゴリゴリ書くと、作った人しか分からない負の遺産が出来るので(経験談)ほどほどが良いです。


Ansibleのグループ変数(?)について調べてみた

AnsibleはInventoryファイルやgroup_vars、プレイブックなどに変数を定義することが出来ます。

しかし、デフォルトでは同名の変数は上書きされてしまいます。
これは、たとえばdbというグループとwebというグループを作り、group_varsでwebとdbそれぞれに変数を定義した場合、それぞれのグループで有効。ではなく、すべてはマージされるということです。

では、どういう優先度でマージされるのでしょう?
っと調べてみたのですが、ハッキリした記述は見つけられませんでした。
また、Ansibleではグループを階層構造にすることが出来ます。
階層化したグループ名に対応するgroup_versもまた有効のようですが、同様に同名の変数が有った場合の優先度が不明です。

というわけで、このようなプレイブックを作成し、実際に動かしてみました。


$ ansible-playbook -i hosts.ini site.yml -c paramiko
PLAY [staging2] ***************************************************************
GATHERING FACTS ***************************************************************
ok: [192.168.0.130]
ok: [127.0.0.1]
TASK: [debug var=hoge] ********************************************************
ok: [127.0.0.1] => {
    "var": {
        "hoge": "web"
    }
}
ok: [192.168.0.130] => {
    "var": {
        "hoge": "db"
    }
}
TASK: [debug var=huga] ********************************************************
ok: [127.0.0.1] => {
    "var": {
        "huga": "www"
    }
}
ok: [192.168.0.130] => {
    "var": {
        "huga": "dbdb"
    }
}
PLAY [staging] ****************************************************************
GATHERING FACTS ***************************************************************
ok: [192.168.0.130]
ok: [127.0.0.1]
TASK: [debug var=hoge] ********************************************************
ok: [127.0.0.1] => {
    "var": {
        "hoge": "vars_hoge"
    }
}
ok: [192.168.0.130] => {
    "var": {
        "hoge": "vars_hoge"
    }
}
TASK: [debug var=huga] ********************************************************
ok: [127.0.0.1] => {
    "var": {
        "huga": "www"
    }
}
ok: [192.168.0.130] => {
    "var": {
        "huga": "dbdb"
    }
}
PLAY [web] ********************************************************************
GATHERING FACTS ***************************************************************
ok: [127.0.0.1]
TASK: [debug var=hoge] ********************************************************
ok: [127.0.0.1] => {
    "var": {
        "hoge": "web"
    }
}
TASK: [debug var=huga] ********************************************************
ok: [127.0.0.1] => {
    "var": {
        "huga": "www"
    }
}
PLAY [db] *********************************************************************
GATHERING FACTS ***************************************************************
ok: [192.168.0.130]
TASK: [debug var=hoge] ********************************************************
ok: [192.168.0.130] => {
    "var": {
        "hoge": "db"
    }
}
TASK: [debug var=huga] ********************************************************
ok: [192.168.0.130] => {
    "var": {
        "huga": "dbdb"
    }
}
PLAY [zaiko] ******************************************************************
GATHERING FACTS ***************************************************************
ok: [192.168.0.130]
ok: [127.0.0.1]
TASK: [debug var=hoge] ********************************************************
ok: [127.0.0.1] => {
    "var": {
        "hoge": "web"
    }
}
ok: [192.168.0.130] => {
    "var": {
        "hoge": "db"
    }
}
TASK: [debug var=huga] ********************************************************
ok: [127.0.0.1] => {
    "var": {
        "huga": "www"
    }
}
ok: [192.168.0.130] => {
    "var": {
        "huga": "dbdb"
    }
}
PLAY RECAP ********************************************************************
127.0.0.1                  : ok=12   changed=0    unreachable=0    failed=0
192.168.0.130              : ok=12   changed=0    unreachable=0    failed=0
グループ名のアルファベット順で上書きされるのかなと思ったのですが、
どうやらそのホストが所属している一番末端のグループが優先ですが、プレイブック内のvarsセクションでの宣言が一番最優先のようです。


2015年12月6日日曜日

LT駆動開発 21に参加してきました。

特にスライドも何も用意していなかったのですが、案の定召集が(ぉ

LT枠が例によって余っていたので現地で急遽こしらえました。
といっても例によってポカーン枠なんですがね(笑)



いやぁ、みんな毎週ネタがあってすごいわ。