lightline.vim で Ricty を使う
vim のステータスライン用のプラグインを vim-powerline から lightline.vim に変更してみました。
ついでにフォントも Ricty に powerline 用パッチを当てたものに変更したのでやり方をメモ。
作業環境は Ubuntu 13.04 32bit です。
Ricty をビルドする
Ricty はライセンスの関係で TrueType フォント形式では配布されておらず、生成スクリプトのみが公開されている状態なので、まずはフォントをビルド。
fontforge をインストール。
% sudo apt-get install fontforge
Inconsolata の OpenType file をダウンロード。
% wget http://levien.com/type/myfonts/Inconsolata.otf
Migu 1M をダウンロード。
MigMix ではないので注意。
% wget http://iij.dl.sourceforge.jp/mix-mplus-ipa/59022/migu-1m-20130617.zip
% unzip migu-1m-20130617.zip
% git clone https://github.com/yascentur/Ricty.git
Ricty の生成。
% cd Ricty % ./ricty_generator.sh ~/tmp/Inconsolata.otf ~/tmp/migu-1m-20130617/migu-1m-regular.ttf ~/tmp/migu-1m-20130617/migu-1m-bold.ttf
Ricty をインストール。
% mv Ricty*.ttf ~/.fonts % fc-cache -fv
Ricty にパッチを当てる
lightline.vim では powerline 用か vim-powerline 用のパッチが当たったフォントが使えるので、パッチを当てたフォントを作成しインストール。
- powerline に同梱の fontpatcher.py を使う場合
% git clone https://github.com/Lokaltog/powerline.git % fontforge -script $HOME/tmp/powerline/font/fontpatcher.py $HOME/.fonts/Ricty-Regular.ttf % fontforge -script $HOME/tmp/powerline/font/fontpatcher.py $HOME/.fonts/Ricty-Bold.ttf % mv Ricty\ Regular\ for\ Powerline.ttf ~/.fonts/ % mv Ricty\ Bold\ for\ Powerline.ttf ~/.fonts % fc-cache -fv
- vim-powerline に同梱の Powerline font patcher の方を使う場合
% git clone https://github.com/Lokaltog/vim-powerline.git % fontforge -lang=py -script ./vim-powerline/fontpatcher/fontpatcher $HOME/.fonts/Ricty-Regular.ttf % fontforge -lang=py -script ./vim-powerline/fontpatcher/fontpatcher $HOME/.fonts/Ricty-Bold.ttf % mv Ricty-Regular-Powerline.ttf ~/.fonts % mv Ricty-Bold-Powerline.ttf ~/.fonts % fc-cache -fv
lightline.vim で Ricty を使う
lightline.vim を NeoBundle でインストール。
.vimrc に以下を書いて :NeoBundleInstall 実行。
NeoBundle 'itchyny/lightline.vim
.vimrc に以下の設定が無い場合は追加。
scriptencoding utf-8 set encoding=utf-8
guifont で作成した Ricty を指定。
set guifont=Ricty\ 10
以下の lightline.vim 用の設定を追加。
公式の README.md に載っているものそのままです。
手元の環境では vim-powerline 用のパッチを当てたフォントを使用しているので以下のようにしました。
let g:lightline = { \ 'colorscheme': 'wombat', \ 'component': { \ 'readonly': '%{&readonly?"x":""}', \ }, \ 'separator': { 'left': "\u2b80", 'right': "\u2b82" }, \ 'subseparator': { 'left': "\u2b81", 'right': "\u2b83" } \ }
powerline 用のパッチを当てたフォントを使っている場合は以下のようになるはずです。
let g:lightline = { \ 'colorscheme': 'wombat', \ 'component': { \ 'readonly': '%{&readonly?"x":""}', \ }, \ 'separator': { 'left': "\ue0b0", 'right': "\ue0b2" }, \ 'subseparator': { 'left': "\ue0b1", 'right': "\ue0b3" } \ }
結構いろいろやった気がしますがこれで必要な作業は一通り完了です。
gvim を再起動してみると以下のような見た目になりました。
いい感じ。
lightline.vim は作者の方が丁寧な解説記事を書かれているので、じっくり読みながらいろいろとカスタマイズしていってみたいですね。
参考
lightline.vim作りました - プラグインの直交性について - プログラムモグモグ
http://d.hatena.ne.jp/itchyny/20130824/1377351527
作者が教える! lightline.vimの導入・設定方法! 〜 初級編 - インストールしよう - プログラムモグモグ
http://d.hatena.ne.jp/itchyny/20130828/1377653592
作者が教える! lightline.vimの設定方法! 〜 初級編 - コンポーネントを作ってみよう - プログラムモグモグ
http://d.hatena.ne.jp/itchyny/20130917/1379369171
作者が教える! lightline.vimの設定方法! 〜 中級編 - 展開コンポーネントを理解しよう - プログラムモグモグ
http://d.hatena.ne.jp/itchyny/20130918/1379461406
Ansible で標準のパス以外の場所に入れた Python を使用する
Ansible はデフォルトではリモートのホストに入っている標準の python を使用します。
これを virtualenv 環境など、標準のパス以外の場所の python を使いたい場合には、ansible_python_interpreter 変数で python インタプリタのパスを指定するようです。
List of Behavioral Inventory Parameters
http://docs.ansible.com/ansible/latest/intro_inventory.html#list-of-behavioral-inventory-parameters
vars: ansible_python_interpreter="/root/python-venv/bin/python"
ただ、手元の CentOS 6.4 環境で、この方法で virtualenv 環境の python を指定したところ、yum モジュールを使った箇所で以下のようなエラーが出てしまいました。
TASK: [install mysql-server] ************************************************** failed: [192.0.2.1] => {"failed": true, "parsed": false} invalid output was: Traceback (most recent call last): File "/root/.ansible/tmp/ansible-1378480574.36-133423455605286/yum", line 26, in <module> import yum ImportError: No module named yum FATAL: all hosts have already failed -- aborting
ここ以外は上手く動くようなので、yum モジュールまでは標準の python、virtualenv 環境を使う時だけそちらの python、という感じで指定できれば回避できそう。
何か方法はないかと調べてみたところ、1.2 から追加された set_fact を使う事で回避することができました。
set_fact - Set host facts from a task
http://docs.ansible.com/ansible/latest/set_fact_module.html
以下のような感じで、virtualenv 環境を使いたい task の直前で set_fact を使用して ansible_python_interpreter 変数を指定してやります。
・ ・ ・ - name: install mysql-server yum: name=mysql-server state=installed - name: start mysql action: service name=mysqld state=started enabled=yes # ここで python インタプリタを切り替え - name: set ansible_python_interpreter set_fact: ansible_python_interpreter="/root/python-venv/bin/python" - name: create mysql_python_test database mysql_db: name=mysql_python_test state=present encoding=utf8 ・ ・ ・
これで先ほどのエラーを回避でき、virtualenv 環境に入れた mysql-python を使用して mysql_db モジュールを実行することが出来ました。
以下に実際の playbook を置いておきます。
https://github.com/akishin/ansible-playbooks/blob/master/snippets/virtualenv-mysql-python.yml
それほど使う機会もないかと思いますが、何かの参考になれば幸いです。
GitLab 5.4 から 6.0 へアップデートする
GitLab 6.0 がリリースされました。
グループ機能を強化した「GitLab 6.0」リリース、有償版の提供も開始
http://sourceforge.jp/magazine/13/08/23/140000
Fork したプロジェクトからオリジナルへの MergeRequest が可能になるなど、より GitHub に近付いた感じですね。
というわけで早速前回インストールした 5.4 を 6.0 にアップデートしてみました。
基本的には以下のドキュメントに従って作業をしていきます。
gitlabhq/doc/update/5.4-to-6.0.md
https://github.com/gitlabhq/gitlabhq/blob/master/doc/update/5.4-to-6.0.md
バックアップ
まずは現在のデータのバックアップを行います。
# cd /home/git/gitlab # sudo -u git -H RAILS_ENV=production bundle exec rake gitlab:backup:create
と思ったら「Dumping uploads」で「No such file or directory - /home/git/gitlab/public/uploads」エラー。
どうやら構築手順で漏れていましたが、public/uploads ディレクトリが必要なようです。
なのでここで一旦作成し、再度バックアップを実行します。
# mkdir /home/git/gitlab/public/uploads # chown git:git /home/git/gitlab/public/uploads # sudo -u git -H RAILS_ENV=production bundle exec rake gitlab:backup:create
今度は上手く行きました。
バックアップファイルは以下の場所に作成されるようです。
# ll /home/git/gitlab/tmp/backups 合計 80 -rw-rw-r--. 1 git git 40960 8月 23 21:00 2013 1377259246_gitlab_backup.tar -rw-r--r--. 1 git git 40960 8月 23 21:02 2013 1377259375_gitlab_backup.tar
サーバの停止
次にアプリケーションサーバを停止します。
ここでは Apache + Passenger で動かしているので httpd と、別のサービスとして登録していた sidekiq の二つのサービスを停止しました。
# service httpd stop # service sidekiq stop
最新のコードの取得
gitlab のリポジトリを更新します。
# cd /home/git/gitlab # sudo -u git -H git fetch # sudo -u git -H git checkout 6-0-stable
gitlab-shell の更新
gitlab-shell の方も更新します・・・とありますが、前回の手順で既にドキュメントで指定されているバージョン 1.7.0 を使用していたのでスルーしました。
追加パッケージのインストール
python-docutils パッケージを追加でインストールします。
yum でも同名で提供されていました。
# yum install -y python-docutils
ライブラリのインストールとマイグレーション
まずは bundler で追加されたライブラリをインストールします。
MySQL を使用しているので postgres グループは除外しています。
# cd /home/git/gitlab # sudo -u git -H bundle install --deployment --without development test postgres
以下の rake タスクを実行して各種データのマイグレーションを行います。
# sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production # sudo -u git -H bundle exec rake migrate_groups RAILS_ENV=production # sudo -u git -H bundle exec rake migrate_global_projects RAILS_ENV=production # sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production # sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production
GitLab 6.0 からは global な namespace のプロジェクトが deprecated になったので、 migrate_global_projects 実行時には自動でプロジェクトオーナーの namespace 以下に移動させて良いか訊かれます。
後で手動で移動させる事もできるので、その辺りはチェックアウトしているユーザへの影響など考慮しながら適宜判断する感じでしょうか。
ここでは面倒なのと一人用 GitLab なので yes を選択しました。
その他も db:migrate 以外では実行可否を聞かれますが、特に問題無さそうなので全部 yes を選択しました。
どれも新しいバージョンでの仕様変更に関する内容のようなので、古いバージョンから長いこと使用しているような場合には良く読んで慎重に選択した方が良さそうです。
最後に assets:precompile も忘れずに実行しておきます。
# sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production
設定ファイルの更新
config/gitlab.yml と config/unicorn.rb の差分を確認、とのことですが、ここでは Unicorn は使用していないので gitlab.yml だけ確認しました。
# diff config/gitlab.yml config/gitlab.yml.example 18c18 < host: 192.0.2.1 --- > host: localhost 20a21,22 > > # Uncomment and customize the last line to run in a non-root path 22,23c24,28 < # Uncomment and customize to run in non-root path < # Note that ENV['RAILS_RELATIVE_URL_ROOT'] in config/puma.rb may need to be changed --- > # Note that three settings need to be changed for this to work. > # 1) In your application.rb file: config.relative_url_root = "/gitlab" > # 2) In your gitlab.yml file: relative_url_root: /gitlab > # 3) In your unicorn.rb: ENV['RAILS_RELATIVE_URL_ROOT'] > # 99a105 > allow_username_or_email_login: true
最後の allow_username_or_email_login は LDAP の設定でした。
LDAP は使っていないのと、それ以外特に違いは無さそうなのでこのままで良さそうです。
アプリケーションの起動
いよいよ起動してみます。
# service sidekiq start # service httpd start
ブラウザを起動してアクセスしてみるとログイン画面がこんな感じに。
思い切り 6 って書いてあります。
Help ページを確認してみると、こちらも無事 6.0.0 になっていました。
他にも Global な namespace で作成していたプロジェクトがオーナーの namespace 配下になっていたりと、どうやら今回のバージョンアップは上手く行ったようです。
まとめ
GitLab はバージョンが変わる毎に結構インストール手順が変わっちゃったりして追いかけるのが大変なんですが、リリースバージョン 1 つ差くらいだと案外簡単にバージョンアップできますね。
余り間が空くとどんどん面倒になりそうなので、使っている方は早めに思い切ってバージョンアップしてしまうといいかも知れません。
ついでに以前書いた Ansible の Playbook も 6.0.0 をインストールするように修正してみました。
新機能を気軽に試したい方はこちらを使ってみて下さい。
条件によって実行する task を定義する
when による条件分岐について調べたのでまとめておきます。
host の情報や他のコマンドの実行結果の値により実行する task を定義する事が出来ます。
task を実行するための条件は when 句で指定します。
when 句では変数を指定できるので、例えば --extra-vars を使用して以下のように外部から実行条件を指定する事ができます。
- when.yml
--- - user: root hosts: all tasks: - name: install mlocate yum: name=mlocate state=installed when: install == "y"
when 句での変数の参照には ${} や {{}} は付けない事に注意。
実行時には以下のように変数 install の値を渡します。
「y」以外の値を渡すと task の実行が skip されることが分かります。
$ ansible-playbook when.yml --extra-vars "install=n" -i hosts -k
vars_prompt で入力させるようにすれば、実行時に task 実行可否を決めさせることも可能です。
- when2.yml
--- - user: root hosts: all vars_prompt: - name: "install" prompt: "install mlocate?" private: no default: "y" tasks: - name: install mlocate yum: name=mlocate state=installed when: install == "y"
ansible では対象ホストの情報やインベントリで定義された情報についてアクセスするために自動的に定義されるいくつかの変数があります。
これらの変数の値を when 句で使用する事も可能です。
例えば以下ではインベントリファイルに定義したホスト名を取得する inventory_hostname を使って実行可否を切り替えています。
- when3.yml
- user: root hosts: all tasks: - yum: name=mysql state=latest when: inventory_hostname != 'example01'
また、register を使用して他の task の実行結果を変数に格納しておき、その値を他の task の when 句で使用することも出来ます。
この挙動を試すため、対象サーバで以下のようなファイルを作成します。
# echo "bar" > /tmp/testfile
以下の Playbook では先ほど作成したファイルの有無で処理の実行を切り替えています。
試しにファイルを削除すると task が実行されなくなることが分かります。
- when4.yml
- user: root hosts: all tasks: - command: test -f /tmp/testfile ignore_errors: true register: testfile_exist - lineinfile: dest=/tmp/testfile state=present regexp='^bar$' line=BAR when: testfile_exist.rc == 0
これらの条件付き実行タスクを使いこなす事でより一層柔軟な Playbook を定義することが出来るようになりそうです。
参考
Magic Variables, and How To Access Information About Other Hosts
http://docs.ansible.com/ansible/latest/playbooks_variables.html#magic-variables-and-how-to-access-information-about-other-hosts
Conditionals — Ansible Documentation
http://docs.ansible.com/ansible/latest/playbooks_conditionals.html
Registered Variables
http://docs.ansible.com/ansible/latest/playbooks_variables.html#registered-variables
shkumagai さんが Ansible 1.2.2 のドキュメントを日本語に翻訳して下さいました。
お陰で理解が進みました。
ありがとうございます。
ansible v1.2.2 ドキュメントを翻訳しました ― doing mistakes
http://shkumagai.github.io/blog/2013/08/19/ansible_docs_v1_2_2_translated.html
今回参照したドキュメントと対応する箇所は以下になります。
20分(くらい)で GitLab をインストールする方法
この間構築手順を書きましたが、改めて見ると GitLab の構築って結構手間がかかって面倒臭いですよね。
私の周りでも構築は面倒というような話をよく聞きます。
こんな時こそ自動化だ、という訳で Ansible で GitLab インストール用の Playbook 書いてみました。
https://github.com/akishin/ansible-playbooks/tree/master/gitlab
clone して hosts というファイルの中に対象サーバのホスト名か IP アドレスを記述します。
% git clone git://github.com/akishin/ansible-playbooks.git % cd ansible-playbooks/gitlab % vi hosts # 対象サーバを記述
準備が出来たら ansible-playbook 実行。
% ansible-playbook site.yml -i hosts -k
Ansible さえインストールされていれば基本的にこれだけでしばらく待てば GitLab 環境の出来上がり。
ちなみに手元の仮想環境で time コマンド付きで実行してみた時は以下のような結果でした。
real 18m40.501s user 0m4.991s sys 0m2.327s
やっぱり Ruby 2.0 と Git 1.8 をソースコードからビルドしているのがボトルネックかなー。
RPM 作れるなら RPM からインストールするように変えればもっと早くなるはずです。
GitLab の 細かいカスタマイズなどは roles/gitlab/templates の下にあるテンプレートを弄ればある程度は出来ると思います。
Ansible 自体のインストール方法などはこちらに書いたので参考にしてみて下さい。
自分の環境でしか確認していないので、もし何かおかしい点などあればフィードバック頂けると嬉しいです。
これですぐに GitLab を使い始めることが出来ますね。
Playbook 実行時に任意の値を指定する
Playbook 内に直接値を定義せず、実行時に外部から値を渡したい場合、 --extra-vars 引数を使う方法と vars_prompt を使う方法があります。
--extra-vars
Passing Variables On The Command Line
http://docs.ansible.com/ansible/playbooks_variables.html#passing-variables-on-the-command-line
※ www.ansibleworks.com は使われなくなったようなので URL を修正
予め Playbook 内で変数を使用しておき、 ansible-playbook コマンドの実行時に --extra-vars オプションによって実際の変数の値を渡す事が出来ます。
Playbook は以下のような感じで定義します。
- extra-vars.yml
--- - user: '{{ user }}' hosts: '{{ hosts }}' tasks: - name: install mlocate yum: name=mlocate state=installed
「user」と「hosts」の値をそれぞれ同名の変数を参照するようにしていますが、このファイル内では変数は定義していません。
これらの変数は Playbook 実行時に以下のように --extra-vars 引数の値として指定します。
$ ansible-playbook extra-vars.yml --extra-vars "hosts=all user=root" -i hosts -k
Ansible 1.2 からは以下のように JSON 形式で指定することも出来るようです。
$ ansible-playbook extra-vars2.yml --extra-vars '{ "foo":"FOO", "fruits":["apple", "cherry", "orange"] }' --connection=local
以下のように debug モジュールを使うと簡単に動作確認が出来ます。
- extra-vars2.yml
--- - user: root hosts: all tasks: - debug: msg="{{ foo }}" - debug: msg="${item}" with_items: fruits
vars_prompt
Prompts
http://docs.ansible.com/ansible/playbooks_prompts.html#prompts
※ www.ansibleworks.com は使われなくなったようなので URL を修正
vars_prompt を使う場合、Playbook 内の vars_prompt セクションで外部から入力を受け付けたい変数を定義しておきます。
- vars-prompt.yml
- user: root hosts: all vars_prompt: - name: "name" prompt: "Please enter your name" private: no default: "John Doe" tasks: - debug: msg="Hello, {{ name }}"
実行すると以下のように「prompt」で指定した「Please enter your name」というメッセージが表示され入力待ちになります。
任意の文字列を指定して Enter を押すと debug モジュールが実行されます。
$ ansible-playbook vars-prompt.yml --connection=local Please enter your name:
vars_prompt では以下のようなオプションを使用できます。
オプション | 意味 |
---|---|
name | 入力値を参照する際の変数名 |
prompt | 入力を促すプロンプト文字列 |
default | デフォルト値 |
private | yes にするとエコーバックされない(パスワード等で使う) |
confirm | yes にすると確認のための再入力を求める |
エコーバックしない private オプションや確認のための confirm オプションがあるので、パスワードの変更などに使うと良さそうです。
vars_prompt で入力された文字列でパスワードを変更する Playbook を書いてみると以下のような感じになりました。
- hosts: all user: root vars: username: johnd saltstr: saltstr vars_prompt: - name: "new_password" prompt: "Enter new password" confirm: true private: yes tasks: - name: "create password salt" shell: echo somesalt | /usr/bin/md5sum | awk '{print $1}' register: password_salt - name: "create new password hash" command: python -c 'import crypt; print crypt.crypt("{{ new_password }}", "$1${{ password_salt.stdout }}$")' register: password_hash - name: "change password" user: name={{ username }} password={{ password_hash.stdout }} state=present
どちらかというと環境構築用の Playbook では --extra-vars の方が使えそうですが、運用系の作業を Playbook 化する場合などは vars_prompt の方が適している場合もありそうですね。
Ansible で複数行の文字列置換
ansible で設定ファイル内の文字列を置換したかったので、 lineinfile モジュールを試してみました。
lineinfile
http://www.ansibleworks.com/docs/modules.html#lineinfile
対象サーバに以下のようなファイルを用意。
- /tmp/test.conf
foo bar baz bar bar bar foo
このファイル内の文字列を置換してみます。
以下のような Playbook を作成しました。
- lineinfile.yml
- hosts: all user: root vars: target_file: /tmp/test.conf tasks: - name: lineinfile example task lineinfile: dest=${target_file} state=present regexp='^bar$' line=BAR=99999
ここで lineinfile モジュールに指定しているパラメータは以下のような意味です。
実行してみます。
$ ansible-playbook lineinfile.yml -i hosts -k
確認してみると以下のように、最後の "bar" だけが置換されている事がわかります。
# cat /tmp/test.conf foo bar baz bar bar BAR=99999 foo
複数行まとめて置換したい場合はどうやるんだろう?と思ってドキュメントを確認したところ、以下のように書いてありました。
only the last line found will be replaced.
http://www.ansibleworks.com/docs/modules.html#lineinfile
どうやら lineinfile モジュールでは、複数行マッチした場合は最後にマッチした行のみ置換されるようです。
他にも同じくドキュメントに
This is primarily useful when you want to change a single line in a file only. For other cases, see the copy or template modules.
http://www.ansibleworks.com/docs/modules.html#lineinfile
と書いてあったりするので、どうやら今のところ複数行の置換には対応していない模様(バージョン 1.2.2 で確認)。
とはいえ template を用意するほど変更箇所が多いわけでもないし・・・。
というわけで、結局 command モジュール + sed で以下のようにしました。
- hosts: all user: root vars: target_file: /tmp/test.conf tasks: - name: find and replace using sed command: sed -i "s/^bar$/BAR=99999/g" ${target_file}
変更後に再度実行すると全て置換されている事が分かります。
# cat /tmp/test.conf foo BAR=99999 baz BAR=99999 BAR=99999 BAR=99999 foo
置換系は sed 使えば確かに簡単なので、当面これでいいような気がしました。
マッチしなければ何も起きないので、冪等性が壊れることも多分無さそうだし。
参考:
lineinfile モジュール
http://yteraoka.github.io/ansible-tutorial/ansible-in-detail.html#module-lineinfile
ちょうど今月の Software Design が sed 特集みたいです。