StupidDog's blog

IT関連の手近な所で、疑問に思った事を調べた記録

「windwos7にvagrantでUbuntu13.10 server+Puppet+Chefの実験環境を構築する(Ver.2)」|ただいまRubyの修行中

はじめに

「windwos7にvagrantでUbuntu13.10 server+Puppet+Chefの実験環境を構築する」|ただいまRubyの修行中 - StupidDog's blog
のアップ後に、tbpgrさんから有益な情報を貰ったので、Chefのインストールをもっと正確に早くできる方法で再構築します。
また、Chef-soloの実行確認で何処までリポジトリを簡素に作成できるかを試してみました。

書籍として以下のものを薦めて貰いました。
Chef-Soloでの使用方法が機能を絞って書かれているので、これから始めるにはバッチリです。

入門Chef Solo - Infrastructure as Code

入門Chef Solo - Infrastructure as Code

また、以下のサイトも参照しています。
サーバー設定ツール「Chef」の概要と基礎的な使い方 - さくらのナレッジ

…実践Vagrantに載ってたのに、Chefを使う予定がなかったから意識から外れてたノДT)

概要

  1. Vagrant-omnibusプラグインのインストール
  2. Vagrant-omnibusを利用してChefをインストールするVagrantfileファイルの作成
  3. 仮想環境の構築(vagrant up)
  4. Chef-soloの実行確認

VirtualBoxVagrantなどのインストールは前回と同じです。
Vagrant-omnibusプラグインのインストールから、それを利用したVagrantfileの作成と仮想環境の構築を中心にまとめています。

1.Vagrant-omnibusプラグインのインストール

Vagrantプラグインなので、vagrant plugin installコマンドによりインストールできます。

F:\vm\z001>vagrant plugin list
vagrant-login (1.0.1, system)
vagrant-share (1.0.1, system)

F:\vm\z001>vagrant plugin install vagrant-omnibus
Installing the 'vagrant-omnibus' plugin. This can take a few minutes...
Installed the plugin 'vagrant-omnibus (1.3.1)'!

F:\vm\z001>vagrant plugin list
vagrant-login (1.0.1, system)
vagrant-omnibus (1.3.1)
vagrant-share (1.0.1, system)

F:\vm\z001>

2.Vagrant-omnibusを利用してChefをインストールするVagrantfileの作成

前回のVagrantfileの内容に、Chefのインストール指示として「config.omnibus.chef_version = :latest」の一行を追加します。

VAGRANT_API_VERSION = "2"

Vagrant.configure(VAGRANT_API_VERSION) do |config|
  config.vm.box = "ubuntu1310"
  config.vm.box_url = "http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-1310-i386-virtualbox-puppet.box"
  config.omnibus.chef_version = :latest
end

3.仮想環境の構築(vagrant up)

Vagrant upコマンドを実行し環境を構築します。

F:\vm\z001>vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'ubuntu1310'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: z001_default_1396697147599_75843
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 => 2222 (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection timeout. Retrying...
    default: Warning: Connection timeout. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
    default: /vagrant => F:/vm/z001
==> default: Installing Chef 11.10.4 Omnibus package...
==> default: Downloading Chef 11.10.4 for ubuntu...
==> default: downloading https://www.getchef.com/chef/metadata?v=11.10.4&prerelease=false&p=ubuntu&pv=13.10&m=i686
==> default:   to file /tmp/install.sh.1231/metadata.txt
==> default: trying wget...
==> default: url        https://opscode-omnibus-packages.s3.amazonaws.com/ubuntu/13.04/i686/chef_11.10.4-1.ubuntu.13.04_i386.deb
==> default: md5        86dc72fa5b37eee71bf239a4a39df14b
==> default: sha256     144d7d05aadcc0cdd084c9d4b46f08ae30485d6cc267c902ff5d31230a5b86a3
==> default: downloaded metadata file looks valid...
==> default: downloading https://opscode-omnibus-packages.s3.amazonaws.com/ubuntu/13.04/i686/chef_11.10.4-1.ubuntu.13.04_i386.deb
==> default:   to file /tmp/install.sh.1231/chef_11.10.4-1.ubuntu.13.04_i386.deb
==> default: trying wget...
==> default: Comparing checksum with sha256sum...
==> default: Installing Chef 11.10.4
==> default: installing with dpkg...
==> default: Selecting previously unselected package chef.
==> default: (Reading database ...
==> default: 62328 files and directories currently installed.)
==> default: Unpacking chef (from .../chef_11.10.4-1.ubuntu.13.04_i386.deb) ...
==> default: Setting up chef (11.10.4-1.ubuntu.13.04) ...
==> default: Thank you for installing Chef!

末尾の数行でChef 11.10.4のインストールが行われ成功している事が分かります。

4.Chef-soloの実行確認

ここからは仮想環境へssh接続し、実際にChefを実行できるか確認します。

仮想環境へのssh接続

ssh接続には前回と同じく、gitに含まれるsshコマンドを利用しています。

F:\vm\z001>vagrant ssh
Welcome to Ubuntu 13.10 (GNU/Linux 3.11.0-12-generic i686)

 * Documentation:  https://help.ubuntu.com/
Last login: Thu Apr 10 00:28:04 2014 from 10.0.2.2
Chef-Soloのバージョンを確認
vagrant@ubuntu1310-i386:~$ chef-solo -v
Chef: 11.10.4
プロビジョニングのためのファイルを準備

Chefは、Puppetと違いファイルとディレクトリの構成に決まりがあります。
Cookbookなどのリソースを格納するディレクトリを「リポジトリ」と呼びます。
まずはリポジトリ用のディレクトリを作成します。

サーバー設定ツール「Chef」の概要と基礎的な使い方 - さくらのナレッジの「リポジトリとCookbookの作成、Cookbookの構造」を参照して最低限必要なものだけを作成します。

vagrant@ubuntu1310-i386:~$ mkdir -p chef-repo
vagrant@ubuntu1310-i386:~$ tree chef-repo
chef-repo

0 directories, 0 files
vagrant@ubuntu1310-i386:~$ knife cookbook create hello -o ~/chef-repo
WARNING: No knife configuration file found
** Creating cookbook hello
** Creating README for cookbook: hello
** Creating CHANGELOG for cookbook: hello
** Creating metadata for cookbook: hello

vagrant@ubuntu1310-i386:~$ tree ~/chef-repo
/home/vagrant/chef-repo
└── cookbooks
    └── hello
        ├── attributes
        ├── CHANGELOG.md
        ├── definitions
        ├── files
        │   └── default
        ├── libraries
        ├── metadata.rb
        ├── providers
        ├── README.md
        ├── recipes
        │   └── default.rb
        ├── resources
        └── templates
            └── default

12 directories, 4 files
レシピを編集

「~/chef-repo/cookbooks」ディレクトリ以下にknife cookbook createコマンドで作成したcookbookのひな形が作成されています。
各cookbookは「recipes」ディレクトリ以下に複数のレシピをファイルとして持ちます。
cookbookでレシピを指定しなかった場合に実行されるレシピは「default.rb」ファイルに記述します。
コメントだけが記述されたひな形が作成されているので、下記のように一行追加します。

vagrant@ubuntu1310-i386:~$ cat ~/chef-repo/cookbooks/hello/recipes/default.rb
#
# Cookbook Name:: hello
# Recipe:: default
#
# Copyright 2014, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#
log "Welcome to a kitchen!"
設定ファイルの作成

Chef-soloへ渡す設定としてファイルを作成します。
下記の内容でファイル名を「solo.rb」としリポジトリ直下に作成します。

vagrant@ubuntu1310-i386:~$ cat ~/chef-repo/solo.rb
file_cache_path "/tmp/chef-solo"
cookbook_path ["/home/vagrant/chef-repo/cookbooks"]
実行するレシピを決めるファイルの作成

Chef-soloでは実行するレシピのファイルを直接指定しません。
JSON書式のファイルに記述して実行します。
下記の内容でファイル名を「localhost.json」としリポジトリ直下に作成します。

vagrant@ubuntu1310-i386:~$ cat ~/chef-repo/localhost.json
{
  "run_list" : [
    "recipe[hello]"
  ]
}
レシピの適用

chef-soloコマンドは、管理対象のサーバーで、管理者権限を必要とする部分も変更の対象とするので、実行にsudoが必要になります。

vagrant@ubuntu1310-i386:~$ chef-solo -c ~/chef-repo/solo.rb -j ~/chef-repo/localhost.json
[2014-04-10T04:58:01-07:00] ERROR: Permission denied - /tmp/chef-solo/chef-client-running.pid
[2014-04-10T04:58:01-07:00] FATAL: Chef::Exceptions::ChildConvergeError: Chef run process exited unsuccessfully (exit code 1)

vagrant@ubuntu1310-i386:~$ sudo chef-solo -c ~/chef-repo/solo.rb -j ~/chef-repo/localhost.json
Starting Chef Client, version 11.10.4
Compiling Cookbooks...
Converging 1 resources
Recipe: hello::default
  * log[Welcome to a kitchen!] action write


Running handlers:
Running handlers complete

Chef Client finished, 1/1 resources updated in 1.355948408 seconds

ログ出力として、"Welcome to a kitchen!"の出力に成功しました。

まとめ

Chef-soloのインストールにVagrant-omnibusプラグインを使用して仮想環境構築と合わせてChef-solo環境を入手する方法を確認しました。
折角作成したのでChef-soloでは、どこまでリポジトリを省略して作成できるかを試してみました。
結果として動作確認だけなら、リポジトリ直下にcookbooksがあれば動きそうです。

最終的なリポジトリの内容
vagrant@ubuntu1310-i386:~$ tree -F ~/chef-repo
/home/vagrant/chef-repo
├── cookbooks/
│   └── hello/
│       ├── attributes/
│       ├── CHANGELOG.md
│       ├── definitions/
│       ├── files/
│       │   └── default/
│       ├── libraries/
│       ├── metadata.rb
│       ├── providers/
│       ├── README.md
│       ├── recipes/
│       │   └── default.rb
│       ├── resources/
│       └── templates/
│           └── default/
├── localhost.json
└── solo.rb

12 directories, 6 files

また、参照する先々でknife configureコマンドを実行するように説明されていますが、意図的に実行しないで検証を行いました。今回の内容では、knife configureコマンドで作成する「~/.chef/knife.rb」ファイルは不要だったようです。

前回インストールしたknife-soloはgemなのでVagrant-ominibusプラグインではインストールされません。
次は、構築した環境をベースにChefの使用する機能を増やして、どこで何が必要になるか検証していきます。

あらぁ…puppetやrubyから離れていくノД≦)ノ

「windwos7にvagrantでUbuntu13.10 server+Puppet+Chefの実験環境を構築する」|ただいまRubyの修行中

はじめに

普段はUbuntu12.10 DesktopをホストOSとして、Ubuntu13.10 Serverの仮想環境を作成しています。
今回は、Windowsを使用している人をサポートするためにWindows7をホストOSとして同じ環境を作成しました。
VagrantWindowsをホストOSとしても使用できる事は知識として知っていますが、経験しなければ知りえないことがあります。
以下に2014年4月4日時点で各プロダクトの最新のリリース版を使用して構築した方法をまとめます。

2014.4.5 追記
tbpgrさんより、Chef-SoloインストールのVagrant Pluginの情報を貰ったのでChefインストール部分の再構築中です。Vagrant Pluginを使用しなかった場合に何が必要かを残しておくために変更はしないで残します。

「windwos7にvagrantでUbuntu13.10 server+Puppet+Chefの実験環境を構築する(Ver.2)」|ただいまRubyの修行中 - StupidDog's blog

概要

  1. VirtualBoxのインストール
  2. Vagrantのインストール
  3. Gitのインストール(sshコマンドを利用したい為)
  4. 仮想環境の構築(vagrant up)とssh接続テスト(vagrant ssh)
  5. 仮想環境へChefのインストール

1.VirtualBoxのインストール

VirtualBoxインストーラーをDownloads – Oracle VM VirtualBoxからダウンロードします。
(ファイル「VirtualBox-4.3.10-93012-Win.exe」)

インストール自体はインストーラーに従ってクリックしていくだけで終わります。
途中にセキュリティ上の確認メッセージがでますが以下のものなら「インストール」とします。

オプションの設定(初期状態から変更なし)


インストールの確認メッセージ




2.Vagrantのインストール

VagrantインストーラーをDownload Vagrant - Vagrantからダウンロードします。
(ファイル「vagrant_1.5.2.msi」)

これもインストーラーに従ってクリックしていくだけで終わります。
インストール先が初期状態で「C:\HashiCorp\Vagrant」になっています。
変更する場合は管理者権限が必要な場所にならないように注意してください。

3.Gitのインストール

これはソース管理を行うから普段から入れてます。コマンドラインで使用できるssh.exeが入っているので環境構築後にssh接続確認に使用します。
GitのインストーラーをGitからダウンロードします。
(ファイル「Git-1.9.0-preview20140217.exe」※previewだけど良しとします)

サーチパスの追加

インストーラーによりgitコマンドはパスが通った状態になっています。
追加でsshコマンドを使用するためのパスを通します。

[windows]+[R]で「ファイル名を指定して実行」ダイアログを開き「SystemPropertiesAdvanced」と入力し「システムのプロパティ」ダイアログを開きます。
f:id:StupidDog:20140404014557j:plain
f:id:StupidDog:20140404015228j:plain

システム環境変数の変数Pathの末尾が「C:\Program Files (x86)\Git\cmd」になっていると思います。
この後に「;C:\Program Files (x86)\Git\bin」を追加します。(区切りの;を忘れずに)

4.仮想環境の構築とssh接続テスト

始めはUbuntu12.04 Desktopを構築しようしました。しかし、公開されているBoxファイルのイメージと今回使用しているVirtualBoxのバージョンが離れすぎたためか起動に失敗してしまうので断念しました。
用途としてはGUIが不要なので、いつも使っているPuppet Vagrant Boxesで公開されてるBoxファイルを使用します。
f:id:StupidDog:20140404024603p:plain

ここからはコマンドライン操作となります。
[windows]+[R]で「ファイル名を指定して実行」ダイアログを開き「cmd」と入力して「コマンドプロンプト」を開きます。
※以降の\は¥に読み替えてください。

仮想環境用のディレクトリを作成する

管理用ディレクトリを作成して、そこをカレントディレクトリとします。
ここでは「F:」ドライブ上に「F:\vm\z001」として作成しました。

C:\>f:
F:\>mkdir vm\z001
F:\>cd vm\z001
F:\vm\z001>
Vagrantfileを作成する

管理用ディレクトリに以下の内容で「vagrantfile」ファイルを作成します。
ファイル名は大小文字の区別はありませんが、拡張子が付かないように注意してください。
(※Windows上ではvagrantfileもVagrantfileも同じとして扱われます)

VAGRANT_API_VERSION = "2"

Vagrant.configure(VAGRANT_API_VERSION) do |config|
  config.vm.box = "ubuntu1310"
  config.vm.box_url = "http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-1310-i386-virtualbox-puppet.box"
end
仮想環境を構築する
F:\vm\z001>type vagrantfile

VAGRANT_API_VERSION = "2"

Vagrant.configure(VAGRANT_API_VERSION) do |config|
  config.vm.box = "ubuntu1310"
  config.vm.box_url = "http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-1310-i386-virtualbox-puppet.box"
end

F:\vm\z001>vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'ubuntu1310'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: z001_default_1396545723721_56124
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 => 2222 (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection timeout. Retrying...
    default: Warning: Connection timeout. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
    default: /vagrant => F:/vm/z001
構築した環境へsshで接続する

vagrant ssh」コマンドを実行した後は、構築した仮想マシン上での操作となります。
ssh接続に失敗する場合は、sshコマンドへのサーチパスが間違っていないなか確認してください。

F:\vm\z001>vagrant ssh
Welcome to Ubuntu 13.10 (GNU/Linux 3.11.0-12-generic i686)

 * Documentation:  https://help.ubuntu.com/
Last login: Thu Apr  3 10:26:19 2014 from 10.0.2.2

vagrant@ubuntu1310-i386:~$ ruby -v
ruby 1.9.3p194 (2012-04-20 revision 35410) [i686-linux]
vagrant@ubuntu1310-i386:~$ perl -v

This is perl 5, version 14, subversion 2 (v5.14.2) built for i686-linux-gnu-thread-multi-64int
(with 80 registered patches, see perl -V for more detail)

Copyright 1987-2011, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

vagrant@ubuntu1310-i386:~$ python -V
Python 2.7.5+

5.仮想環境へChefのインストール

Puppetが入っている環境ですが、同じ用途で使用されるChefというものがあります。
現場によりどちらかが利用されていると思います。
どちらも実際に動かして試せる環境があると便利なので、Chefも入れてみます。
インストール自体は簡単で以下のコマンドを実行するだけです。

Install Chef 11.x on a Workstation — Chef Single-page Topics
Run the omnibus installerを参照しました。

vagrant@ubuntu1310-i386:~$ 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 14401  100 14401    0     0   2152      0  0:00:06  0:00:06 --:--:--  3547
Downloading Chef  for ubuntu...
downloading https://www.opscode.com/chef/metadata?v=&prerelease=false&p=ubuntu&pv=13.10&m=i686
  to file /tmp/install.sh.1286/metadata.txt
trying wget...
url     https://opscode-omnibus-packages.s3.amazonaws.com/ubuntu/13.04/i686/chef_11.10.4-1.ubuntu.13.04_i386.deb
md5     86dc72fa5b37eee71bf239a4a39df14b
sha256  144d7d05aadcc0cdd084c9d4b46f08ae30485d6cc267c902ff5d31230a5b86a3
downloaded metadata file looks valid...
downloading https://opscode-omnibus-packages.s3.amazonaws.com/ubuntu/13.04/i686/chef_11.10.4-1.ubuntu.13.04_i386.deb
  to file /tmp/install.sh.1286/chef_11.10.4-1.ubuntu.13.04_i386.deb
trying wget...
Comparing checksum with sha256sum...
Installing Chef
installing with dpkg...
Selecting previously unselected package chef.
(Reading database ... 62328 files and directories currently installed.)
Unpacking chef (from .../chef_11.10.4-1.ubuntu.13.04_i386.deb) ...
Setting up chef (11.10.4-1.ubuntu.13.04) ...
Thank you for installing Chef!

vagrant@ubuntu1310-i386:~$ chef-solo -v
Chef: 11.10.4

chef-soloのインストールが出来ました。
しかし、これだけでは足りませんので機能の追加をします。

knife-soloのインストール

このインストールにより、knifeにサブコマンドとしてsoloが追加されます。
Chefではディレクトリの構成が決められています。
その雛形の生成などの手助けをしてくれるコマンドです。
(※ホントはもっと色々だけど習得が進むまでこの認識で良しとします)

インストール方法として以下の説明が多いのですが、サラの環境からだとエラーとなる人が多いと思います。

$ gem install knife-solo --no-ri --no-rdoc

パッケージが足らないのと、ログ出力先に管理者権限が必要となります。
そのため以下のような順序でコマンドを実行することになります。

$ sudo apt-get install git
$ sudo apt-get install ruby1.9.1-dev
$ sudo apt-get install make
$ sudo gem install knife-solo --no-ri --no-rdoc

以上で、「knife solo ~」が使用できるようになりました。
暫く使用してから、実際にchefを使用した環境設定の足がかりをまとめたい…
(figletインストールするまでに迷走した物語などを)

まとめ

Ubuntu12.10とWindows7の二種類のホストOS上に、Vagrantを使い「同じVagrantfile」から「同じBoxファイル」をベースとして同じ仮想環境を構築できることが確認できました。
当然、この環境に変更を加えてからBoxファイルにまとめUbuntu12.10をホストOSとする環境へ復元できます。
VirtualBoxのバージョンが上がっても、有志で公開されているBoxファイルのバージョンは更新されるとは限らないのでVagrantで何でも解決!とは行きませんが、現場でBoxを作成して管理すれば、増員時に開発環境の構築ミスで手戻りなんてことは減らせるかと思います。
PuppetとChefの実験環境も揃ったのでプロビジョニングへ・・・

あれRubyどこ行ったノД≦)ノ

「Ubuntu13.10 ServerへPuppet(puppet-rbenv)で、rbenvとRubyをインストールする」|ただいまPuppetも修行中です

はじめに

「rbenvを、Ubuntu13.10 ServerへPuppetでインストールする」|ただいまPuppetも修行中です - StupidDog's blog

先日見つけたpuppetでrbenvを扱うモジュールを使ってRubyをインストールします。
知ってしまえば導入も利用簡単ですが、私自身がpuppetを始めたばかりで、いくつか躓いた事がありました。
Rubyのインストールの他に、躓いた事と解決した結果をまとめます。

実行環境

vagrantで、puppetlabsで公開されているboxファイルから構築した仮想端末を使用します。

ubuntu 12.10 desktop(ホストOS)
vagrant 1.4.3
virtualbox 4.3.6 r91406
ubuntu 13.10 server(ゲストOS)
puppet v3.4.2
仮想環境を構築する為に使用したVagrantfileファイルの内容
VAGRANT_API_VERSION = "2"

Vagrant.configure(VAGRANT_API_VERSION) do |config|
  config.vm.box = "ubuntu1310"
  config.vm.box_url = "http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-1310-i386-virtualbox-puppet.box"
  config.vm.hostname = "z003.local"
end

alup-rbenvをインストールする

Puppet forgeのインストール方法に従って、moduleをインストールします。
alup/rbenv/1.2.0 · Puppet Forge

vagrant@z003:/vagrant/manifests$ puppet module install alup-rbenv --version 1.2.0
Notice: Preparing to install into /home/vagrant/.puppet/modules ...
Notice: Downloading from https://forge.puppetlabs.com ...
Notice: Installing -- do not interrupt ...
/home/vagrant/.puppet/modules
└── alup-rbenv (v1.2.0)

マニフェストの作成

マニフェストファイルの保存場所は、ゲストOS/ホストOS間で共有しているディレクトリを使います。
vagrantで構築後にに変更していなければ、ゲストOS上で「/vagrant」ディレクトリになります。
そこへ、「manifests」ディレクトリを作成し、マニフェストファイルを配置します。

Ruby 2.1.1をインストールするmanifestファイルの内容

ファイル名は、dev.ppとして保存します。

$username = 'vagrant'

# rbenvのインストール
rbenv::install { "${username}":
  home => "/home/${username}",
}

# rbenv管理でのRuby 2.1.1のインストール(使用するRubyのバージョンも切換える)
rbenv::compile { "2.1.1":
  user   => "${username}",
  home   => "/home/${username}",
  global => true,
}

マニフェストの適用

vagrant@z003:/vagrant/manifests$ sudo puppet apply -v --modulepath=/home/vagrant/.puppet/modules dev.pp
Notice: Compiled catalog for z003.local in environment production in 0.37 seconds
Info: Applying configuration version '1395567847'
Notice: /Stage[main]/Rbenv::Dependencies::Ubuntu/Package[libxslt1-dev]/ensure: ensure changed 'purged' to 'present'
Notice: /Stage[main]/Rbenv::Dependencies::Ubuntu/Package[git]/ensure: ensure changed 'purged' to 'present'
Notice: /Stage[main]/Rbenv::Dependencies::Ubuntu/Package[libssl-dev]/ensure: ensure changed 'purged' to 'present'
Notice: /Stage[main]/Rbenv::Dependencies::Ubuntu/Package[libyaml-dev]/ensure: ensure changed 'purged' to 'present'
Notice: /Stage[main]/Rbenv::Dependencies::Ubuntu/Package[autoconf]/ensure: ensure changed 'purged' to 'present'
Notice: /Stage[main]/Rbenv::Dependencies::Ubuntu/Package[bison]/ensure: ensure changed 'purged' to 'present'
Notice: /Stage[main]/Rbenv::Dependencies::Ubuntu/Package[libreadline6-dev]/ensure: ensure changed 'purged' to 'present'
Notice: /Stage[main]/Main/Rbenv::Install[vagrant]/Exec[rbenv::checkout vagrant]/returns: executed successfully
Notice: /Stage[main]/Main/Rbenv::Install[vagrant]/File[rbenv::cache-dir vagrant]/ensure: created
Notice: /Stage[main]/Main/Rbenv::Install[vagrant]/File[rbenv::rbenvrc vagrant]/ensure: defined content as '{md5}16cc327d1ce70219d2cd5dfad28ce2e7'
Notice: /Stage[main]/Main/Rbenv::Compile[2.1.1]/Rbenv::Plugin::Rubybuild[rbenv::rubybuild::vagrant]/Rbenv::Plugin[rbenv::plugin::rubybuild::vagrant]/File[rbenv::plugins vagrant]/ensure: created
Notice: /Stage[main]/Main/Rbenv::Compile[2.1.1]/Rbenv::Plugin::Rubybuild[rbenv::rubybuild::vagrant]/Rbenv::Plugin[rbenv::plugin::rubybuild::vagrant]/Exec[rbenv::plugin::checkout vagrant ruby-build]/returns: executed successfully
Notice: /Stage[main]/Main/Rbenv::Compile[2.1.1]/Exec[rbenv::compile vagrant 2.1.1]/returns: executed successfully
Notice: /Stage[main]/Main/Rbenv::Compile[2.1.1]/Rbenv::Gem[rbenv::bundler vagrant 2.1.1]/Rbenvgem[vagrant/2.1.1/bundler/present]/ensure: created
Notice: /Stage[main]/Main/Rbenv::Compile[2.1.1]/Exec[rbenv::rehash vagrant 2.1.1]/returns: executed successfully
Notice: /Stage[main]/Main/Rbenv::Install[vagrant]/Exec[rbenv::shrc vagrant]/returns: executed successfully
Info: Creating state file /var/lib/puppet/state/state.yaml
Notice: Finished catalog run in 804.09 seconds

rbenvでRubyをインストールする部分が少し時間が掛かります。
これで、Rubyだけでなく、git、rbenv、ruby-build(が必要とするpackageも含め)など、関連する必要なファイルがインストールされます。何がインストールされたかは、出力されているメッセージで分かります。

躓いた事

(1) インストールしたはずの「alup-rbenv」モジュールが使用できない

「puppet apply」だけでマニフェストを適用しようとするとエラーとなります。
これは、resource typeの一つであるexecを使用しており、execはroot権限が必要だからです。

vagrant@z003:~$ puppet apply -v /vagrant/manifests/dev.pp 
Notice: Compiled catalog for z003.local in environment production in 0.37 seconds
Error: Parameter user failed on Exec[rbenv::checkout vagrant]: Only root can execute commands as other users at /home/vagrant/.puppet/modules/rbenv/manifests/install.pp:29
Wrapped exception:
Only root can execute commands as other users

エラーメッセージにしたがってroot権限で実行するために、sudoを付けて実行しましたが今度は「rbenv::install」が使用できなくなりました。

vagrant@z003:~$ sudo puppet apply -v /vagrant/manifests/dev.pp
Error: Puppet::Parser::AST::Resource failed with error ArgumentError: Invalid resource type rbenv::install at /vagrant/manifests/dev.pp:7 on node z003.local
Wrapped exception:
Invalid resource type rbenv::install
Error: Puppet::Parser::AST::Resource failed with error ArgumentError: Invalid resource type rbenv::install at /vagrant/manifests/dev.pp:7 on node z003.local

ググってみようにも、まだpuppetに疎すぎて、なかなか検索に使えそうな単語が出てきません。見つけた内容も「includeが足りないんでしょう」ばかりで試してみても変化なしです。
puppetのmoduleを理解すべく「入門puppet」でmoduleについて書かれている章を読み、classだからincludeが必要なのは分かりました。しかし、githubにあるalup-rbenvのコードを見ていたら定義がclassではなくdefineです。

defineについては書かれていないので本家サイトのドキュメントを調べました。
Language: Defined Resource Types — Documentation — Puppet Labs

「defineは、classより簡単にマクロのような処理を書くことができ、それはresource typeのように使用できる」みたいな感じです。
classと違いincludeは不要です。では、何がいけないのでしょう?

defineを調べるために、puppetlabsサイトのドキュメントを読んでいたら、モジュールの配置場所を実行時に与えるオプションの説明がありました。
Module Fundamentals — Documentation — Puppet Labs

そこで、alup-rbenvをインストールした時のログから、インストール先がユーザのホームディレクトリ以下になっていることに気がつきました。

/home/vagrant/.puppet/modules
└── alup-rbenv (v1.2.0)

root権限のための、sudoを付ける前と後でpuppetがモジュールを探しに行く場所が異なってるのではないかと考え、ドキュメンにあった設定値を表示するコマンドで確認したところ、やはり異なっていました。
Module Fundamentals — Documentation — Puppet Labs

vagrant@z003:/vagrant/manifests$ puppet config print modulepath
/home/vagrant/.puppet/modules:/usr/share/puppet/modules

vagrant@z003:/vagrant/manifests$ sudo puppet config print modulepath
/etc/puppet/modules:/usr/share/puppet/modules

これに対応するために、マニフェストの適用時にmodulepathを指定するオプションを付けています。
「sudo puppet apply」のオプションで「--modulepath=/home/vagrant/.puppet/modules」の部分です。

(2) マニフェストの適用は成功しているのにrbenvコマンドが無いと言われる
vagrant@z003:~$ rbenv -v
The program 'rbenv' is currently not installed. You can install it by typing:
sudo apt-get install rbenv

rbenvをgithubからgit cloneでインストールした場合、コマンドのサーチパスに追加が必要になります。
rbenvのドキュメントでは.bashrcに以下の2行を追加するように説明があります。

export PATH="$HOME/bin:$PATH"
eval "$(rbenv init -)"

そして、.bashrcを更新しただけでは、この追加の2行は実行されないので、ターミナルを開き直すか、「source .bashrc」で現在のシェルに反映させる必要があります。alup-rbenvを使ったマニフェストの適用後は、この状態と同じです。
追加のされ方が異なりますが、端末を開き直すか、「source .rbenvrc」でrbenvコマンドが実行できるようになります。
alup-rbenvが上記の2行をどのように追加しているかは、考察にまとめます。

考察

(1) alup-rdenvが、どのようにrbenvのサーチパスを追加しているか

先日、resource typeのexecを使用して、rbenvをgithubから取得する方法を考えていた時に、どう解決するか考えた部分です。
一つの例として、alup-rbenvが行っている解決方法を調べます。
以下は、Ubuntu上での結果なので他の環境とは異なると思いますが、考え方は流用できるはずです。

追加する内容は別ファイルとして作成されます

「.bashrc」ファイルに追加したかった内容は、「.rbenvrc」ファイルとして作成されます。
ファイルの内容は以下の通りで、既にサーチパスに"rbenv"が含まれる場合は追加しません。

#
# This is a shell fragment that initializes rbenv, if it
# has not been inited yet. Managed by puppet - DO NOT EDIT
#
if ! echo $PATH | grep -q rbenv; then
  export PATH="/home/vagrant/.rbenv/bin:$PATH"
  eval "$(rbenv init -)"
fi
「.bashrc」ファイルへの変更は行っていません。

Ubuntuでの話になりますが、「.profile」が実行され、そこから「.bashrc」を呼び出すようにシェルスクリプトが組まれています。
alup-rbenvでは、「.bashrc」には追加せず「.profile」の末尾に以下のコードを追加します。

source /home/vagrant/.rbenvrc

rbenv::installの属性で「.profile」から「.bashrc」へ変更する事もできます。

まとめ

始めに書いたマニフェストから、モジュールを導入して躓いた事で、classとmoduleについて調べ、カスタムresource typeの作成はclass以外に、defineも使える事が分かりました。
そして、alup-rbenvのコードがdefineを使った例として丁度良く、行いたいことが分かっているので理解しやすかったです。

そう、こんな感じに・・・

f:id:StupidDog:20140324235308j:plain
「読める!!読めるぞ!!」

「rbenvを、Ubuntu13.10 ServerへPuppetでインストールする」|ただいまPuppetも修行中です

はじめに

「gitを、Ubuntu13.10 Serverにpuppetでインストールする」|ただいまpuppetも修行中です - StupidDog's blog

gitのインストールが分かったので、今回はgithubからsstephenson/rbenv · GitHubをインストール(clone)します。
puppetlabsで公開されているmoduleの中にgitやsubversionなどに対応したものが有ったのですが
(puppetlabs/puppetlabs-vcsrepo · GitHub)、gitへのアクセスがsshでの接続となってしまい別の設定を必要とするので断念しました。
素の状態のPuppetでは、resource typeとしてgitは扱っていないため、任意のコマンドを実行するresource typeであるexecを使用してgitコマンドを実行します。

環境

puppetlabs提供のvagrant向けboxファイルから作成した仮想環境を使用します(gitインストール時の環境と同じ)。

  • Ubuntu13.10 Server
  • puppet v3.4.2

マニフェストの作成

下記の内容でマニフェストを作成する。ファイル名は任意、ここではrbenv.ppとします。

package { 'git':
  ensure => installed,
}

$username = 'vagrant'
exec { 'rbenv':
  user       => "${username}",
  cwd        => "/home/${username}",
  path       => ['/usr/bin'],
  command    => "git clone https://github.com/sstephenson/rbenv.git /home/${username}/.rbenv",
  creates    => "/home/${username}/.rbenv",
  require    => Package['git'],
}
execの属性について
  • コマンドは、userで指定したユーザ・groupで指定したグループの何れかの権限で実行されます。user・groupとも省略するとroot権限で実行されます。
  • コマンドは、cwdで指定したディレクトリをカレントディレクトリとして実行されます。
  • execでは、環境変数やコマンドのサーチパス(PATH)が空の状態でコマンドを実行します。そのためコマンドのパスを指定する必要があります。
  • commandは、実行したいコマンドそのままです。
  • createsは、指定したファイルかディレクトリが存在している場合は、コマンドを実行しないという条件です。
  • requireは、コマンドを実行するのに依存している条件で、例ではgitのパッケージがインストールされている事が条件となります。

マニフェストの適用

gitが未インストールの場合、apt-getコマンドによりインストールされます。
ubuntu以外なら別のコマンドになります。CentOSyumなど。
apt-getコマンドを実行する権限が必要なるので、sudo付きでpuppetコマンドを実行します。
2014.03.24 追記
ここで使用しているexec自体がroot権限を必要とします。

$ sudo puppet apply -v rbenv.pp
Notice: Compiled catalog for z003.local in environment production in 0.19 seconds
Info: Applying configuration version '1395423805'
Notice: /Stage[main]/Main/Exec[rbenv]/returns: executed successfully
Notice: Finished catalog run in 16.43 seconds

$ tree ~/.rbenv
/home/vagrant/.rbenv
├── bin
│   ├── rbenv -> ../libexec/rbenv
│   └── ruby-local-exec
├── completions
│   ├── rbenv.bash
│   ├── rbenv.fish
│   └── rbenv.zsh
├── libexec
│   ├── rbenv
│   ├── rbenv-commands
│   ├── rbenv-completions
│   ├── rbenv-exec
│   ├── rbenv-global
│   ├── rbenv-help
│   ├── rbenv-hooks
│   ├── rbenv-init
│   ├── rbenv-local
│   ├── rbenv-prefix
│   ├── rbenv-rehash
│   ├── rbenv-root
│   ├── rbenv-shims
│   ├── rbenv-sh-rehash
│   ├── rbenv-sh-shell
│   ├── rbenv-version
│   ├── rbenv---version
│   ├── rbenv-version-file
│   ├── rbenv-version-file-read
│   ├── rbenv-version-file-write
│   ├── rbenv-version-name
│   ├── rbenv-version-origin
│   ├── rbenv-versions
│   ├── rbenv-whence
│   └── rbenv-which
├── LICENSE
├── README.md
└── test
    ├── commands.bats
    ├── completions.bats
    ├── exec.bats
    ├── global.bats
    ├── help.bats
    ├── hooks.bats
    ├── init.bats
    ├── libexec
    │   └── rbenv-echo
    ├── local.bats
    ├── prefix.bats
    ├── rbenv.bats
    ├── rehash.bats
    ├── shell.bats
    ├── shims.bats
    ├── test_helper.bash
    ├── --version.bats
    ├── version.bats
    ├── version-file.bats
    ├── version-file-read.bats
    ├── version-file-write.bats
    ├── version-name.bats
    ├── version-origin.bats
    ├── versions.bats
    ├── whence.bats
    └── which.bats

これで、githubからrbenvをインストールすることが出来ました。
この後、rbenvへのサーチパス追加と環境変数の設定を.bashrcに追加しなければなりません。

追加するのは次の2行です。

export PATH="$HOME/bin:$PATH"
eval "$(rbenv init -)"

新規ファイルを配置するのは楽だけど、既存のファイルへ追記する場合のベストプラクティス的な方法は無いだろうか。

まとめ

既存のファイルへ追記する方法を探していたらPuppetでrbenvを扱うmoduleを見つけてしまいました。
サーチパスの設定どころか指定バージョンのRubyをインストールする所までマニフェストで書けてしまいます。
puppetのmoduleとして提供されているので導入も楽です。
次は、このalup/rbenv/1.2.0 · Puppet Forgeを調べることにします。

今回は、resource typeにexecを使用する場合にPATHと環境変数が空の状態で実行される事が分かったので良しとします。

「gitを、Ubuntu13.10 Serverへpuppetでインストールする」|ただいまpuppetも修行中です

はじめに

Ruby on Railsを、始めるつもりが環境構築に凝りすぎ随分と横道に進んでいますが続けます。
手動により導入するものが決まり手順をpuppet化する所まで来ました。
全てを一度に解決せず、各手順を順番に解決していこうと思います。
なので、対象環境上でマニフェストファイルを作成して手動で適用と確認です。

以下が参考にしているサイトと書籍です。

本家サイト:Learning Puppet — Manifests — Documentation — Puppet Labs
書籍:「入門puppet」

環境

puppetlabs提供のvagrant向けboxファイルから作成した仮想環境を使用します。

  • Ubuntu13.10 Server
  • puppet v3.4.2

参考としてVagrantfileの中身は次の通りです。

# encoding:utf-8
# vi: ft=ruby

VAGRANT_API_VERSION = "2"

Vagrant.configure(VAGRANT_API_VERSION) do |config|
  config.vm.box = "ubuntu1310"
  config.vm.box_url = "http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-1310-i386-virtualbox-puppet.box"
  config.vm.hostname = "z003.local"

  # host 192.168.100.1/24 <-> guest 192.168.100.103/24
  config.vm.network "private_network", ip: "192.168.100.103"
end

作業ディレクトリの作成

仮想環境へSSHでログインした直後は、/home/vagrantがカレントディレクトリになっています。
puppetの練習の為に作業ディレクトリを作成します。
作成したマニフェストファイルをまとめたいだけなので、puppetを使う上で必要なわけではありません。

$ pwd
/home/vagrant
$ mkdir pp
$ cd pp

以後、ここがカレントディレクトリになります。

マニフェストファイルの作成

gitをインストールする為のマニフェストファイルを作業ディレクトリにsample.ppとして作成し、次の一行を追加します。

package { 'git': }

マニフェストファイルを適用する

gitがインストールされていない状態から、puppetによりgitのインストールを行う。

$ git
 The program 'git' is currently not installed. You can install it by typing:
sudo apt-get install git

gitが無いことを確認して、マニフェストファイルを適用(apply)する。

$ puppet apply -v sample.pp
Notice: Compiled catalog for z003.local in environment production in 0.19 seconds
Info: Applying configuration version '1395330812'
Error: Execution of '/usr/bin/apt-get -q -y -o DPkg::Options::=--force-confold install git' returned 100: E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)
E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?

Error: /Stage[main]/Main/Package[git]/ensure: change from absent to present failed: Execution of '/usr/bin/apt-get -q -y -o DPkg::Options::=--force-confold install git' returned 100: E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)
E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?

Notice: Finished catalog run in 0.30 seconds

Ubuntu上で実行しているのでapt-getを使用する所まで自動で判定されています。
しかし、apt-getの実行にroot権限を必要とするのでエラーとなりました。

sudoを付けて実行します。

$ sudo puppet apply -v sample.pp
Notice: Compiled catalog for z003.local in environment production in 0.18 seconds
Info: Applying configuration version '1395331185'
Notice: /Stage[main]/Main/Package[git]/ensure: created
Notice: Finished catalog run in 3.11 seconds

$ git --version
git version 1.8.3.2

gitがインストールされました。ここで、マニフェストを、再度適用してみます。

$ sudo puppet apply -v sample.pp
Notice: Compiled catalog for z003.local in environment production in 0.18 seconds
Info: Applying configuration version '1395331530'
Notice: Finished catalog run in 0.11 seconds

「Notice: /Stage[main]/Main/Package[git]/ensure: created」の行が消えてます。
gitがインストール済みなので何もされません。

まとめ

rbenvをgithubからインストールしようと考えていたところ、「入門puppet」の第11章に、execの例としてxbuildをgithubからインストールするマニフェストの作成がありました。
xbuildを、rbenvに読み替えてマニフェストを作成している時、このpackageの一行は何をしているのか気になり調べたところ、Attributesのensureを省略した状態であることが分かりました。

packageのensureを省略すると、installedを指定した状態になります。

本家ドキュメントより、package - attributes - ensureの説明
package-attribute-ensure

What state the package should be in. On packaging systems that can retrieve new packages on their own, you can choose which package to retrieve by specifying a version number or latest as the ensure value. On packaging systems that manage configuration files separately from “normal” system files, you can uninstall config files by specifying purged as the ensure value. This defaults to installed.

取り敢えず最後の部分。

なので、省略しない場合は以下のようになります。

package { 'git':
  ensure => installed,
}

「Kindle Fire HDX 7タブレットで他人のハイライト表示(ポピュラー・ハイライト)を消す方法」

はじめに

増え続ける本により本棚が足りなくなってきたので、とうとうKindleに手を出しました。
何冊か読んでると「3人がハイライト.....」などの下線表示がされている事に気がつきました。
どうやら、同じ本を読んだ人が付けたハイライトを共有する機能で名前は「ポピュラー・ハイライト」だそうです。
しかし、この機能が凄く邪魔です。

  • 大して重要でない部分にハイライトが引かれている
  • 読んだ人が多い本ほどハイライトが多く強調の意味がない
  • 「n人がハイライト」の小文字が文と文の間に表示され邪魔
  • 何でもかんでもハイライトする人がいて嫌がらせか!ノД≦)ノ

自分のハイライトだけで十分なので、自分の本から他人様は出て行ってもらいましょう。

ポピュラー・ハイライトをオフにする方法

上の方からペロッとメニューを出して、以下の通りに階層を潜ってオフにする。

[設定]タッチ
 > [アプリケーション]タッチ
  > [本]タッチ
   "ポピュラー・ハイライト"をオフにする


これで、自分のハイライトだけ表示されるようになります。

「正規表現の"*"と"?"の動作の違いを確認する」|ただいまRubyの修行中

はじめに

正規表現の"*"と"?"の動作の違いを確認する。
ある本で*1タグ付きの文字列を、タグで分割するコードを見かけました。
章の内容とは全然関係無いのですが、そこで使用されていた処理から再確認したことです。

内容

開始タグ"<b>"と終了タグ"</b>"のように/を含めたものが終了タグのような場合に、正規表現が"<\/*b>"や"<\/?b>"でも同じ結果になるような気になります。
すぐ思いつくテストケースでは、タグの位置やタグの有無だと結果は同じです。

そこで、タグ自体が崩れたテストケースとして、終了タグの打ち間違いとして"<//b>"のような文字列を混ぜると違いが出てきます。

確認のためのコード
# encoding:utf-8
require "strscan"

def display_match(text, pattern)
  sc = StringScanner.new(text)

  puts %(*** text="#{text}", regular=#{pattern.to_s} ***)
  n = 0
  while sc.scan_until(pattern)
    n += 1
    puts "loop.#{n}, pos=#{sc.pos}, matchd=#{sc.matched}"
  end
end

text = "<p>This is a <b>pen<//b>. This is a <b>box</b></p>" 

display_match text, %r{</*b>}
display_match text, %r{</?b>}
実行結果
*** text="<p>This is a <b>pen<//b>. This is a <b>box</b></p>", regular=(?-mix:<\/*b>) ***
loop.1, pos=16, matchd=<b>
loop.2, pos=24, matchd=<//b>
loop.3, pos=39, matchd=<b>
loop.4, pos=46, matchd=</b>
*** text="<p>This is a <b>pen<//b>. This is a <b>box</b></p>", regular=(?-mix:<\/?b>) ***
loop.1, pos=16, matchd=<b>
loop.2, pos=39, matchd=<b>
loop.3, pos=46, matchd=</b>

"*"を使用した場合は、"<//b>"にもマッチしている。

正規表現の"*"と"?"の違い。
  • "*"は「直前の正規表現と0回以上の一致」
  • "?"は「直前の正規表現と0回または、1回の一致」

まとめ

"*"では、"/"が2回一致した結果となった。
知ってしまうと当然だけども実際にそうなるコードを考えると何かの時に気付きになるかな。
あまり頻繁に正規表現を使用していなかったので"?"の動作をよく考えていなかったけど、「0回または1回」は「有るか無いか」となるので使える場所は多そうです。

おまけ

今回のきっかけになったコードです(一部)。
# encoding:utf-8

def parse_inline_styles(text)
  segments = text.split( %r{(</?.*?>)} ).delete_if {|x| x.empty?}
  segments.size == 1 ? segments.first : segments
end

parse_inline_styles "<p>This is a <b>pen<//b>. This is a <b>box</b></p>"
実行結果
["<p>", "This is a ", "<b>", "pen", "<//b>", ". This is a ", "<b>", "box", "</b>", "</p>"]

text#splitで、区切りとして指定した正規表現で一致した文字列を、結果とすることができるのは新しい発見です。
が、崩れた終了タグに一致しるノД≦)

こんな感じで終了。

# encoding:utf-8

def parse_inline_styles(text)
  segments = text.split( %r{(</?[A-Za-z]+>)} ).delete_if {|x| x.empty?}
  segments.size == 1 ? segments.first : segments
end

p parse_inline_styles "<p>This is a <b>pen<//b>. This is a <b>box</b></p>"
実行結果
["<p>", "This is a ", "<b>", "pen<//b>. This is a ", "<b>", "box", "</b>", "</p>"]

*1:Rubyベストプラクティス