ソースコードから見るVagrantのネットワーク(2)

今回は前回のnetwork_ip.rbと同じくnetwork.rbから外部モジュールとして呼び出されているscoped_hash_override.rbを見てみましょう。
https://github.com/mitchellh/vagrant/blob/8747d938aa37e02abc20c870bb9b866a5726bc6b/lib/vagrant/util/scoped_hash_override.rb

このなかでは1つだけメソッドが定義されています。

scoped_hash_override(origianl,scope)

このメソッドはハッシュを操作するメソッドで、ソースコードには以下の例が記載されています。 ハッシュoriginalからscopeで指定した文字列に一致した要素を抜き出し新たなハッシュを作り出すようです。

    # This allows for hash options to be overridden by a scope key
    # prefix. An example speaks best here. Imagine the following hash:
    #
    #     original = {
    #       :id => "foo",
    #       :mitchellh__id => "bar",
    #       :mitchellh__other => "foo"
    #     }
    #
    #     scoped = scoped_hash_override(original, "mitchellh")
    #
    #     scoped == {
    #       :id => "bar",
    #       :other => "foo"
    #     }
    #

それではソースコードを見ていきましょう。
まず引数のscopeをto_sメソッドで文字列に変換し、ハッシュorigianlをコピーしてresultに格納します。次以降で説明する処理でハッシュoriginalの要素に行った処理をここでコピーしたハッシュresultに作用させていきます。

scope = scope.to_s
result = original.dup

次に元のハッシュoriginalの各要素に対して繰り返し処理をしていきます。

original.each do |key, value|
  parts = key.to_s.split("__", 2)

  # If we don't have the proper parts, then bail
  next if parts.length != 2

  # If this is our scope, then override
  if parts[0] == scope
    result[parts[1].to_sym] = value
  end
end

まずkeyをto_sメソッドで文字列に変換した上でsplitメソッドで配列にして返します。 splitメソッドsplit(pattern,[limit])とptternとlimitを引数にとり、patternを区切り文字で文字列を分割し、limitで指定した数字に配列の要素数を押さえます。ここではsplit("__",2)なので文字列「__」を区切り文字、要素を2つまでに押さえます。
http://ref.xaio.jp/ruby/classes/string/split

ソースコードのハッシュoriginalの例では以下のように処理されます。

①:id                 ->:id
②:mitchellh__id      ->:mitchellh, :id
③:mitchellh__other   ->:mitchellh, :other

次の制御構造のnextでif以下の条件に合致した場合は繰り返し処理を飛ばします。

  next if parts.length != 2

ここではparts.length != 2という条件なので、keyを分割(split)して作成した配列partsの要素が2以外であれば以降の処理はされずに次のkeyの処理を行います。前述のハッシュ関数の例だと①は要素が1つなので処理が飛ばされ②の処理に移ります。 ②は要素が2つなので次の処理に進みます。
次の処理では配列partsの1つ目の要素がscopeかどうかがifの条件式となっています。

  if parts[0] == scope

例ではmitchellhなので②はこの条件式に合致します。その場合は次の処理がされます。

    result[parts[1].to_sym] = value

配列の2番目の要素をシンボルにしてハッシュresultにハッシュoriginalのvalueを入れます。②ではresult[:id] = "bar"となります。このとき:idは①と同じなので、id => "foo"id => "bar"に上書きされます。
③ではresult[:other] = "foo"なので:otherがハッシュ内で重複しないので単純に追加されます。

最後にscoped_hash_overrideメソッドはハッシュresultを返り値として返します。
ハッシュresultは以下になりソースコードのハッシュの比較結果はfalseになってしまいます。。。scoped == {〜となっていてハッシュを比較しているのか、「=」を1つの間違いかなのかはわからなかったです。

    #     result = {
    #       :id => "bar",
    #       :mitchellh__id => "bar",
    #       :mitchellh__other => "foo",
    #       :other => "foo"
    #     }

testコードをみるとこの動きで正しそうでした。 https://github.com/mitchellh/vagrant/blob/8747d938aa37e02abc20c870bb9b866a5726bc6b/test/unit/vagrant/util/scoped_hash_override_test.rb

ソースコードから見るVagrantのネットワーク(1)

Vagrantrubyで書かれているのでプログラム経験のないど素人の私でも眺めているとなんとなくわかる部分があります。そこでソースコードからVagrantでどのようにゲストOSのネットワーク設定をしているのか見てみたいと思います。

Vagrantのネットワーク設定はnetwork.rbに記述されています。
https://github.com/mitchellh/vagrant/blob/master/plugins/providers/virtualbox/action/network.rb

500行弱の短いコードですが、今回は肩ならしとしてnetwork.rbから外部モジュールとして呼び出されているnetwork_ip.rbを見てみたいと思います。
https://github.com/mitchellh/vagrant/blob/master/lib/vagrant/util/network_ip.rb

network_ip.rbはネットワークアドレスを取得するためのモジュールです。 network_addressメソッドとip_partsメソッドの2つで構成されています。

ip_partsメソッド

ip_partsメソッドはIPアドレスオクテットごとの配列として返すメソッドです。

def ip_parts(ip)
  ip.split(".").map { |i| i.to_i }
end

ip.split(".")の部分でsplitメソッドを使って、IPアドレスの文字列を引数に"."を区切り文字として配列を返している。
http://ref.xaio.jp/ruby/classes/string/split

~irbを使用した出力例~
irb(main):001:0> ip = "192.168.1.1"
=> "192.168.1.1"
irb(main):002:0> p ip.split(".")
["192", "168", "1", "1"]
=> ["192", "168", "1", "1"]

続いてmapメソッドを使い、文字列の配列を数値の配列に変換します。 mapメソッドは配列の各要素(item)を取り出しblockを実行し、blockの戻り値を集めた配列を 作成して返します。
http://ref.xaio.jp/ruby/classes/array/map

array.map{|item|block}
~irbを使用した出力例~
irb(main):003:0> p ip.split(".").map{|i|i.to_i}
[192, 168, 1, 1]
=> [192, 168, 1, 1]

blockで使用しているto_iは文字列を10進数の整数に変換するメソッドです。
http://ref.xaio.jp/ruby/classes/string/to_i

network_addressメソッド

続いてnetwork_addressメソッドです。

def network_address(ip, subnet)
  ip      = ip_parts(ip)
  netmask = ip_parts(subnet)
  
  ip.map { |part| part & netmask.shift }.join(".")
end

ipとsubnetの2つの引数をさきほど定義したip_partsメソッドでIPアドレス(もしくはサブネットマスク) の文字列をオクテットごとの数字の配列に変換しています。 配列ipをip_partsメソッドでも利用したmapメソッドで配列の要素ごとにある処理をしていきます。ここでしている処理とはまず配列netmaskをshiftメソッドで配列の要素をひとつひとつ取り出していきます。
http://ref.xaio.jp/ruby/classes/array/shift

~irbを使用した出力例~
irb(main):002:0> netmask = [255,255,255,0]
=> [255, 255, 255, 0]
irb(main):003:0> netmask.shift
=> 255
irb(main):004:0> netmask
=> [255, 255, 0]
irb(main):005:0> netmask.shift
=> 255
irb(main):006:0> netmask
=> [255, 0]

続いて取り出してきた要素を配列ipとビット演算をします。
http://www9.plala.or.jp/sgwr-t/c/sec14.html

~irbを使用した出力例~
irb(main):001:0> 192 & 255
=> 192
irb(main):002:0> 168 & 255
=> 168
irb(main):003:0> 1 & 255
=> 1
irb(main):004:0> 1 & 0
=> 0

irb(main):001:0> ip = [192,168,1,1]
=> [192, 168, 1, 1]
irb(main):002:0> netmask = [255,255,255,0]
=> [255, 255, 255, 0]
irb(main):003:0> ip.map{|part|part & netmask.shift}
=> [192, 168, 1, 0]

最後に得られた配列をjoinメソッドを用いて結合します。
http://ref.xaio.jp/ruby/classes/array/join

~irbを使用した出力例~
irb(main):008:0> [192,168,1,0].join(".")
=> "192.168.1.0"

これでIPアドレスとネットマスクからネットワークアドレスが取得できました。

サーバ技術者養成講座をChefでやってみた(4)OSインストールからVagrant用BOXファイル作成まで その2

前回はOSインストールからVagrant用BOXファイル作成の流れをまとめました。今回から実際の流れを見てみます。 まずはVirtualBOXの新規マシンを作成します。

注意するポイントを挙げておきます。

  • ディスク:20GB(ファイルタイプはVMDK)で今後十分な領域をアサインできるように「可変サイズ」が推奨されています。
  • メモリ:1GB
  • ネットワーク:NAT ポートフォワードで接続するため必須
  • その他:USBコントローラー、オーディオを無効化

はじめにVirtualBOXの新規ボタンを押して、名前(ここではSETE_originとしました)を入力し、メモリサイズを1024MBと入力して作成ボタンを押します。バージョンはCentOSの32bitをインストールするためRedHat(32bit)を選択します。

f:id:kjkw76:20140506194605p:plain

続いてファイルサイズを20GBと入力し、ファイルタイプがVMDK、ストレージが可変サイズであることを確認して作成ボタンを押します。

f:id:kjkw76:20140506194719p:plain

作成した仮想マシンの設定ボタンからその他の項目を設定します。
USBコントローラを有効化のチェックボックスを外す。

f:id:kjkw76:20140506194745p:plain

さらにオーディオを有効化のチェックボックスを外す。

f:id:kjkw76:20140506194755p:plain

ネットワークの設定は割り当てをNATにしておきます。

f:id:kjkw76:20140506194841p:plain

OKを押して仮想マシンの設定を終え、仮想マシンを起動する。
ディスクの選択画面でダウンロードしておいたCentOS 5.5のisoイメージファイルを選択する。

f:id:kjkw76:20140506195354p:plain

サーバ技術者養成講座をChefでやってみた(3)OSインストールからVagrant用BOXファイル作成まで その1

原著では物理サーバへのインストールとなっていますが、ここではChefで構築していくためVirtual Boxの仮想OSとしてインストールします。また、Immutable Infrastructureっぽくするため作成した仮想OSをVagrantのBase BOX(仮想OSのテンプレート)とします。

大きな流れは以下の通りです。

  1. Virtual Boxの仮想マシンを新規作成する。
  2. 仮想マシンにCentOS5.5をインストールする。
  3. 仮想OSにVagrantのBase BOXとするための設定をする。
  4. 仮想OSをBase BOX化する。

CentOS5.5のインストールはサーバ技術者養成講座の5章にそって行いますが、Base BOXとするため加えて以下の設定やインストールをしていきます。

  • User設定、Permission設定
  • Virtual Box Guest AdditionsのインストールVagrantでのファイル共有、ポートフォワードのため)
  • SSHの設定VagrantからゲストOSへ接続するため)
  • Ruby,RubyGemsのインストール(Chefをインストールするため)
  • Chefのインストール(プロビジョニングのため)

VagrantのBase Box作成は以下の公式ドキュメントを参考にしています。 https://docs.vagrantup.com/v2/boxes/base.html
v1のdocumentの方が詳細にかかれているのでこちらも参考にしながら。
http://docs-v1.vagrantup.com/v1/docs/base_boxes.html

サーバ技術者養成講座をChefでやってみた(2)Chefの準備(後編)

前回に続いてChefの準備です。今回でChefの準備が完了です。

knife-soloをインストールします。

mba:~ user1$ sudo gem install knife-solo
Password:
Fetching: mixlib-config-2.1.0.gem (100%)
Successfully installed mixlib-config-2.1.0
Fetching: mixlib-cli-1.5.0.gem (100%)
Successfully installed mixlib-cli-1.5.0
Fetching: mixlib-log-1.6.0.gem (100%)
Successfully installed mixlib-log-1.6.0
Fetching: mixlib-authentication-1.3.0.gem (100%)
Successfully installed mixlib-authentication-1.3.0
Fetching: mixlib-shellout-1.4.0.gem (100%)
Successfully installed mixlib-shellout-1.4.0
Fetching: mime-types-1.25.1.gem (100%)
Successfully installed mime-types-1.25.1
Fetching: systemu-2.5.2.gem (100%)
Successfully installed systemu-2.5.2
Fetching: yajl-ruby-1.2.0.gem (100%)
Building native extensions.  This could take a while...
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/rubygems/ext/builder.rb:54: warning: Insecure world writable dir /usr/local/bin in PATH, mode 040777
Successfully installed yajl-ruby-1.2.0
Fetching: ipaddress-0.8.0.gem (100%)
Successfully installed ipaddress-0.8.0
Fetching: ohai-7.0.4.gem (100%)
Successfully installed ohai-7.0.4
Fetching: rest-client-1.6.7.gem (100%)
Successfully installed rest-client-1.6.7
Fetching: net-ssh-2.9.0.gem (100%)
Successfully installed net-ssh-2.9.0
Fetching: net-ssh-gateway-1.2.0.gem (100%)
Successfully installed net-ssh-gateway-1.2.0
Fetching: net-ssh-multi-1.2.0.gem (100%)
Successfully installed net-ssh-multi-1.2.0
Fetching: highline-1.6.21.gem (100%)
Successfully installed highline-1.6.21
Fetching: erubis-2.7.0.gem (100%)
Successfully installed erubis-2.7.0
Fetching: diff-lcs-1.2.5.gem (100%)
Successfully installed diff-lcs-1.2.5
Fetching: hashie-2.1.1.gem (100%)
Successfully installed hashie-2.1.1
Fetching: rack-1.5.2.gem (100%)
Successfully installed rack-1.5.2
Fetching: chef-zero-2.0.2.gem (100%)
Successfully installed chef-zero-2.0.2
Fetching: coderay-1.1.0.gem (100%)
Successfully installed coderay-1.1.0
Fetching: slop-3.5.0.gem (100%)
Successfully installed slop-3.5.0
Fetching: method_source-0.8.2.gem (100%)
Successfully installed method_source-0.8.2
Fetching: pry-0.9.12.6.gem (100%)
Successfully installed pry-0.9.12.6
Fetching: chef-11.12.4.gem (100%)
Successfully installed chef-11.12.4
Fetching: knife-solo-0.4.1.gem (100%)
Thanks for installing knife-solo!

If you run into any issues please let us know at:
  https://github.com/matschaffer/knife-solo/issues

If you are upgrading knife-solo please uninstall any old versions by
running `gem clean knife-solo` to avoid any errors.

See http://bit.ly/CHEF-3255 for more information on the knife bug
that causes this.
Successfully installed knife-solo-0.4.1
Parsing documentation for mixlib-config-2.1.0
Installing ri documentation for mixlib-config-2.1.0
Parsing documentation for mixlib-cli-1.5.0
Installing ri documentation for mixlib-cli-1.5.0
Parsing documentation for mixlib-log-1.6.0
Installing ri documentation for mixlib-log-1.6.0
Parsing documentation for mixlib-authentication-1.3.0
Installing ri documentation for mixlib-authentication-1.3.0
Parsing documentation for mixlib-shellout-1.4.0
Installing ri documentation for mixlib-shellout-1.4.0
Parsing documentation for mime-types-1.25.1
Installing ri documentation for mime-types-1.25.1
Parsing documentation for systemu-2.5.2
Installing ri documentation for systemu-2.5.2
Parsing documentation for yajl-ruby-1.2.0
unable to convert "\xCA" from ASCII-8BIT to UTF-8 for lib/yajl/yajl.bundle, skipping
Installing ri documentation for yajl-ruby-1.2.0
Parsing documentation for ipaddress-0.8.0
Installing ri documentation for ipaddress-0.8.0
Parsing documentation for ohai-7.0.4
Installing ri documentation for ohai-7.0.4
Parsing documentation for rest-client-1.6.7
Installing ri documentation for rest-client-1.6.7
Parsing documentation for net-ssh-2.9.0
Installing ri documentation for net-ssh-2.9.0
Parsing documentation for net-ssh-gateway-1.2.0
Installing ri documentation for net-ssh-gateway-1.2.0
Parsing documentation for net-ssh-multi-1.2.0
Installing ri documentation for net-ssh-multi-1.2.0
Parsing documentation for highline-1.6.21
Installing ri documentation for highline-1.6.21
Parsing documentation for erubis-2.7.0
Installing ri documentation for erubis-2.7.0
Parsing documentation for diff-lcs-1.2.5
Installing ri documentation for diff-lcs-1.2.5
Parsing documentation for hashie-2.1.1
Installing ri documentation for hashie-2.1.1
Parsing documentation for rack-1.5.2
Installing ri documentation for rack-1.5.2
Parsing documentation for chef-zero-2.0.2
Installing ri documentation for chef-zero-2.0.2
invalid options: -SNw2
(invalid options are ignored)
Parsing documentation for coderay-1.1.0
Installing ri documentation for coderay-1.1.0
Parsing documentation for slop-3.5.0
Installing ri documentation for slop-3.5.0
Parsing documentation for method_source-0.8.2
Installing ri documentation for method_source-0.8.2
Parsing documentation for pry-0.9.12.6
Installing ri documentation for pry-0.9.12.6
Parsing documentation for chef-11.12.4
Installing ri documentation for chef-11.12.4
Parsing documentation for knife-solo-0.4.1
Installing ri documentation for knife-solo-0.4.1
26 gems installed

gem listで見てみます。

mba:~ user1$ gem list

*** LOCAL GEMS ***

~省略~
chef (11.12.4)
chef-zero (2.0.2)
~省略~
knife-solo (0.4.1)
~省略~
ohai (7.0.4)
~省略~

knifeコマンドの設定をします。いろいろと聞かれますが、デフォルトでよいのでリターンを連打します。

mba:~ user1$ knife configure
WARNING: No knife configuration file found
/Library/Ruby/Gems/2.0.0/gems/chef-11.12.4/lib/chef/mixin/path_sanity.rb:25: warning: Insecure world writable dir /usr/local/bin in PATH, mode 040777
Where should I put the config file? [/Users/user1/.chef/knife.rb] 
Please enter the chef server URL: https://mba.local:443 
Please enter an existing username or clientname for the API: [user1] 
Please enter the validation clientname: [chef-validator] 
Please enter the location of the validation key: [/etc/chef-server/chef-validator.pem] 
Please enter the path to a chef repository (or leave blank): 
*****

You must place your client key in:
  /Users/user1/.chef/user1.pem
Before running commands with Knife!

*****

You must place your validation key in:
  /etc/chef-server/chef-validator.pem
Before generating instance data with Knife!

*****
Configuration file written to /Users/user1/.chef/knife.rb

サーバ技術者養成講座をChefでやってみた(1)Chefの準備(前編)

サーバ技術者養成講座という本があります。この本ではサーバのインストールからさまざまなソフトの構築が学習できるのですが、これをChefで再現してみました。

環境ですが、MacOS X 10.9.2)、Virtual Box(4.3.10 r93012)、Vagrant(1.5.2)です。 まずはMacにChefのインストールするところから。 ここを参考にさせてもらいました。
http://dotinstall.com/lessons/basic_chef/24203

rubyとgemのVersionを確認します。

 mba:~ user1$ruby -v
 ruby 2.0.0p451 (2014-02-24 revision 45167) [universal.x86_64-darwin13]
 mba:~ user1$gem -v
 2.0.14

つづいてChefをインストールします。公式サイトのget startedに記述があります。
https://learnchef.opscode.com/get-started/

f:id:kjkw76:20140504104630p:plain

実際にインストールしたときの出力です。

mba:~ user1$ curl -L https://www.opscode.com/chef/install.sh | sudo bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 15934  100 15934    0     0  14192      0  0:00:01  0:00:01 --:--:-- 14201

Downloading Chef  for mac_os_x...
downloading https://www.opscode.com/chef/metadata?v=&prerelease=false&nightlies=false&p=mac_os_x&pv=10.9&m=x86_64
  to file /tmp/install.sh.22409/metadata.txt
trying curl...
url https://opscode-omnibus-packages.s3.amazonaws.com/mac_os_x/10.7/x86_64/chef-11.12.4-1.dmg
md5 255c9c372780c199851e52d8594ac86a
sha256  eaaf2a684328d8054bbf84080952d312bbbc34f143df142162b005daf191ff03
downloaded metadata file looks valid...
downloading https://opscode-omnibus-packages.s3.amazonaws.com/mac_os_x/10.7/x86_64/chef-11.12.4-1.dmg
  to file /tmp/install.sh.22409/chef-11.12.4-1.dmg
trying curl...
Comparing checksum with shasum...
Installing Chef 
installing dmg file...
Protective Master Boot Record (MBR : 0) のチェックサムを計算中...
Protective Master Boot Record (MBR ::検証済み CRC32 $A63E199D
GPT Header (Primary GPT Header : 1) のチェックサムを計算中...
 GPT Header (Primary GPT Header : 1):検証済み CRC32 $5CEC083F
GPT Partition Data (Primary GPT Table : 2) のチェックサムを計算中...
GPT Partition Data (Primary GPT Tabl:検証済み CRC32 $21A51859
 (Apple_Free : 3) のチェックサムを計算中...
                    (Apple_Free : 3):検証済み CRC32 $00000000
disk image (Apple_HFS : 4) のチェックサムを計算中...
..................................................................................................
          disk image (Apple_HFS : 4):検証済み CRC32 $83B50227
 (Apple_Free : 5) のチェックサムを計算中...
                    (Apple_Free : 5):検証済み CRC32 $00000000
GPT Partition Data (Backup GPT Table : 6) のチェックサムを計算中...
GPT Partition Data (Backup GPT Table:検証済み CRC32 $21A51859
GPT Header (Backup GPT Header : 7) のチェックサムを計算中...
  GPT Header (Backup GPT Header : 7):検証済み CRC32 $C3215791
検証済み CRC32 $7A616D64
/dev/disk2              GUID_partition_scheme           
/dev/disk2s1            Apple_HFS                       /Volumes/chef_software
installer: Package name is Chef Client
installer: Installing at base path /
installer: The install was successful.
"disk2" unmounted.
"disk2" ejected.

つづいてknife-soloのインストールしますが、長くなったので次回へ。