Vagrantのboxを共有する

インターネットでの共有

Vagrantの開発元でもあるHashiCorpがAtlasというサービスを提供しています。

これを使うと、Vagrantのboxをアップロードし、共有することができます。コストもかからないし、バージョン管理もできちゃいます。

Atlasに登録したものは、そのまま名前を指定すると仮想マシンを立ち上げられます。

vagrant init onozaty/redmine-3.2
vagrant up

とても便利ですね!

インターネットに公開できない場合

インターネット上に公開できないようなものの場合だと、Atlas使えないのでちょっと面倒です。

ファイルサーバなどでboxを共有する

みんなが参照可能な場所にboxを配置し、vagrant init時にURLを指定します。

vagrant init testapp file:////server/vagrant/testapp.box
vagrant up

ちなみに、上記は下記と同じです。

vagrant box add testapp file:////server/vagrant/testapp.box
vagrant init testapp
vagrant up

場所を周知するだけなので、そこまで面倒ではありませんが、あんまりパスを入力したくないですよね、、

boxの場所が書かれたVagrantfileを配布する

ということで、パスを入力するのが嫌なので、別の方法としてVagrantfileを配布する方法があります。

Vagrantfileには、boxのURLが書けて、boxとして登録されていない場合には、そのURLからboxを取得して登録してくれます。 (vagrant init <box名> <URL>でVagrantfile作った時にも同様のVagrntfileが作られています)

  • Vagrantfile
Vagrant.configure(2) do |config|
  config.vm.box = "testapp"
  config.vm.box_url = "file:////server/vagrant/testapp.box"
end

これならば、配布されたVagrantfileを置いたディレクトリで

vagrant up

で終了です。

バージョン管理をする

Vagrantには、boxに対してバージョンを付与し、boxをアップデートする仕組みが用意されています。(Atlasでは、アップロード時にバージョンも記入するので、その情報を元に最新があるかどうかを返してくれています)

jsonファイルにて記載します。バージョンの情報として、バージョン毎のbox取得先URLが記載されています。

  • testapp.json
{
  "description": "Test",
  "short_description": "Test",
  "name": "testapp",
  "versions": [{
    "version": "1.0.0",
    "status": "active",
    "description_html": "<p>Test App</p>",
    "description_markdown": "Test App",
    "providers": [{
      "name": "virtualbox",
      "url": "file:////server/vagrant/testapp-1.0.0.box"
    }]
  },
  {
    "version": "1.1.0",
    "status": "active",
    "description_html": "<p>Test App</p>",
    "description_markdown": "Test App",
    "providers": [{
      "name": "virtualbox",
      "url": "file:////server/vagrant/testapp-1.1.0.box"
    }]
  }]
}

boxのURLとして、上記のjsonファイルを指定します。

vagrant box add file:////server/vagrant/testapp.json
vagrant init testapp
vagrant up

こうすると、jsonに書かれた最新のバージョンを使って立ち上がります。

boxがアップデートされた時には、jsonのファイルを修正すると、vagrant upの時に、新しいものがあることを伝えるメッセージが出ます。

>vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Checking if box 'testapp' is up to date...
==> default: A newer version of the box 'testapp' is available! You currently
==> default: have version '1.1.0'. The latest is version '1.2.0'. Run
==> default: `vagrant box update` to update.

vagrant box updateでboxが更新できます。

vagrant box update --box testapp

jsonファイルもconfig.vm.box_urlに指定できるので、Vagrantfileを配布するような方法も取ることができます。

5 Seconds Of Summer - "Sounds Live Feels Live" JAPAN TOUR 2016 (2016年2月23日@日本武道館)

5 Seconds Of Summer(ファイヴ・セカンズ・オブ・サマー)のライブに嫁さんと2人で行ってきました!
昨年の日本初ライブには残念ながら行けなかったので、待ちに待ったライブです。

若い人ばっかり、しかも女性ばっかりで、ちょっと自分は場違いでは、、といった不安がありましたが、とっても楽しめました。

5sosのメンバも、ほんと楽しそうに演奏しているので、こっちも楽しくなります。(こんな息子たちがいたらいいなぁと思いました(笑))

アシュトンがすごい真剣(というか表情豊か)に演奏していて、モニタで抜かれるたびに、気になってしょうがありません。

「Hey Everybody!」から始まって、最後は「She Looks So Perfect」で、あっという間の時間でした。
ほんと楽しかったです。さらにさらに5sosのことが好きになりました。

セットリスト
  • Hey Everybody!
  • Money
  • Disconnected
  • Don’t Stop
  • Waste the Night
  • Outer Space
  • Castaway
  • Jet Black Heart
  • Vaper
  • Amenisia
  • Beside You
  • End up Here
  • Good Girls
  • Voodoo Doll
  • Permanent Vacation
  • What I like About You
  • She’s Kinda Hot (アンコール)
  • She Looks So Perfect (アンコール)

Ansibleで複数行を追加する(blockinfile)

lineinfile

Ansibleでファイルに行を追記したり置換したりした場合、lineinfileを使うことが多いと思いますが、複数行追加したい場合だと、ちょっとやりずらいところがあります。

下記のように書くと、テキスト内に指定した行の内容がなければ末尾に追加されるので、それを繰り返すことによって末尾に複数行入れられます。

  tasks:
    - name: 末尾に複数行追加
      lineinfile:
        dest=./test.txt
        line={{ item }}
      with_items:
        - '1行目'
        - '2行目'

これが特定の箇所に入れようとすると面倒になります。
たとえば、insertafterを使って指定した行の後に入れようとして、下記のように書くと、、

  tasks:
    - name: 特定の場所に追加
      lineinfile:
        dest=./test.txt
        insertafter='^# xxxx'
        line={{ item }}
      with_items:
        - '1行目'
        - '2行目'

順番が逆に並ぶことになります。

# xxxxx
2行目
1行目

これは、insertafterにマッチした箇所の後に追加するといったことを単に2回繰り返しているためなので、

# xxxxx
1行目
# xxxxx
2行目
1行目

といった形で入っていくためです。

blockinfile

そもそもlineinfileは複数行を扱うのに向いていないので、複数行を扱えるモジュールのblockinfileを使うと良さそうです。

blockinfileは、extraモジュールに現在はあるように見える(GitHubのリポジトリには存在する)のですが、Ansibleのバージョンが古いとextraにいないので、その場合には ansible-galaxy でインストールします。(1.9.4 では入ってませんでした)

ansible-galaxy install yaegashi.blockinfile

blockinfileを使うと、contentに指定した内容をそのまま入れることができます。(rolesにansible-galaxyでインストールしたblockinfileのロールを指定する必要があります)

- hosts: all
  roles:
    - yaegashi.blockinfile
  tasks:
    - name: 特定の場所に追加
      blockinfile:
        dest: ./test.txt
        insertafter: '^# xxxx'
        content: |
          1行目
          2行目

内容の前後にmarkerで指定した内容が入ります。デフォルトだと下記のような感じです。

# xxxxx
# BEGIN ANSIBLE MANAGED BLOCK
1行目
2行目
# END ANSIBLE MANAGED BLOCK

markerの範囲を一つの内容として扱うので、中身を書き換えるのも結構楽です。 たとえば、先ほどのテキスト内容から、下記を実行すると、

tasks:
  - name: 特定の場所に追加
    blockinfile:
      dest: ./test.txt
      insertafter: '^# xxxx'
      content: |
        #1行目
        2行目

markerの範囲のものを置き換えてくれます。

# xxxxx
# BEGIN ANSIBLE MANAGED BLOCK
#1行目
2行目
# END ANSIBLE MANAGED BLOCK

後から追加した行の内容が変わる可能性があるならば、1行だったとしても、blockinfileを使った方がメンテナンスしやすいだろうなぁと思いました。

Easy Ganttを試してみた

以前見かけて試せてなかった Easy Gantt を試してみました。

Easy Ganntは、Easy Software Ltd. が提供するガントチャートのPluginで、有償版と無償版があります。

Easy Software Ltd. は、Easy Redmine として、いろいろ有用なPluginを有償で提供していて、Redmineのホスティングサービスも行っているようです。

インストール

Easy Ganttの動作環境は、Redmine3以上となっています。

Easy Ganttのサイト(Redmine Gantt Plugin - Easy Redmine)から、「Get Gantt Plugin for free」のリンクを押下して、メールアドレスなどの情報を入力します。

指定したアドレスに、ダウンロード先のリンクが記載したメールが届くので、そこからダウンロードしたプラグインをRedmineのpluginディレクトリに配置します。

unzip EasyGanttFree.zip
mv easy_gantt {RAILS_ROOT}/plugins

あとはRedmineを再起動すればインストール完了です。

設定

ログインしてみると、ヘッダに「Projects Gantt」というリンクが見えるので、クリックしてみると、REST API有効にして!といったメッセージが表示されるので、

f:id:onozaty:20160214170506p:plain

REST APIを有効にします。

f:id:onozaty:20160214170627p:plain

この状態でヘッダのリンクをクリックすると、画面が開きましたが、どうやらFree版だと、全プロジェクトをまたいだガントチャートは使えないようです。

f:id:onozaty:20160214170912p:plain

じゃあ、プロジェクト毎のページのガントチャートを見ようということで、プロジェクトの設定で、使用するモジュールとしてEasy ganttにチェックします。

f:id:onozaty:20160214171444p:plain

これでEasy Ganttが開けました。最初はサンプルが表示されていて、「Close this window and load real project data」ってリンクを押すと、実際のデータが表示されます。

f:id:onozaty:20160214223026p:plain

画面に見えている「新しく作成」(チケット/バージョン作成)、「Resource management」、「Critical path」、「Baselines」といった機能は、無償版では使えません。

無償版で行えることは、表示項目の選択、マウス操作による期間、進捗率の変更と、チケットの前後関係設定くらいですが、それでも十分役に立つプラグインだと思いました。

Redmine未読ニュース通知プラグインを試してみた

Redmineのニュースを使って、手軽に周知事項を流せないかなぁと思ったのですが、既読管理ができないため、自分が未読の情報があるのか判断しずらいです。

そこで、既読管理ができるプラグインを探したところ、ちょうど良さそうなものが見つかりました。

インストール

手元の環境(Redmine 3.2)に入れてみましたが、そのままだと入りませんでした。

[root@localhost plugins]# git clone https://github.com/georz/redmine_news_notification.git
[root@localhost plugins]# rake redmine:plugins:migrate RAILS_ENV=production
(in /var/lib/redmine)
/var/lib/redmine/vendor/bundle/ruby/2.2.0/gems/htmlentities-4.3.1/lib/htmlentities/mappings/expanded.rb:465: warning: duplicated key at line 466 ignored: "inodot"
An error occurred while loading the routes definition of redmine_news_notification plugin (/var/lib/redmine/plugins/redmine_news_notification/config/routes.rb): You should not use the `match` method in your router without specifying an HTTP method.
If you want to expose your action to both GET and POST, add `via: [:get, :post]` option.
If you want to expose your action to GET, use `get` in the router:
  Instead of: match "controller#action"
  Do: get "controller#action".

routes.rb でエラーが起きました。
Rails4だとoptionなしのmatchが使えないようですので、明示的にgetを指定するように変えました。

[root@localhost redmine_news_notification]# git diff
diff --git a/config/routes.rb b/config/routes.rb
index efa9320..07ccb56 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,5 +1,5 @@
 # Plugin's routes
 # See: http://guides.rubyonrails.org/routing.html
 Rails.application.routes.draw do
-  match 'news_notifications/:action', :to => 'news_notifications'
+  get 'news_notifications/:action', :to => 'news_notifications'
 end

これで無事インストールができました。

動作

動作としてはシンプルで、未読のニュースがあった場合に、ヘッダ部分に表示されます。

f:id:onozaty:20160207012156p:plain

クリックすると、ニュースの概要が表示されます。

f:id:onozaty:20160207012245p:plain

とてもいい感じです。

なんでメール通知使わないの?

新規ニュースはRedmineのメール通知でも飛ばせます。ただ、Redmineを頻繁に見ながら作業している状況で、メールに通知されるのって、ちょっと遠回りをしている気がしてなりません。
また、メールはそれ以外の情報も大量に流れ込んできて、Redmineの通知が埋もれやすいので、なるべくRedmineの情報はRedmine上で通知が出来ればよいなぁと個人的には思っています。(今回のような仕組みはニュース以外にもあっても良いなぁと思っています)

ちなみにメール通知がベストなのかどうかは、通知が飛ぶ量だったり、メールでどんな情報が流れているのかといったところによっても変わってくるものですので、プロジェクトによって全然異なるかと思います。

CentOS7にIRCサーバ(ngIRCd) をインストールする

CentOS 7 で IRCサーバ立てようとして、今まで使ったことのあった ircd-hybrid を入れようとしたところ、yumのリポジトリから無くなってました。(たしか6の時はあったかと)

ソースから入れるのも面倒なので、他にないのかなぁとさがしていたら、 ngIRCd がありました。

ということで、CentOS7での ngIRCd のインストールメモです。

インストール方法

ngIRCdはEPELリポジトリにて公開されていますので、yumのリポジトリとしてEPELを追加し、ngIRCdをインストールします。

[root@localhost ~]# yum install -y epel-release
[root@localhost ~]# yum install -y ngircd

ngIRCdの設定ファイル(/etc/ngircd.conf)のListenの行をコメントアウトします。(コメントアウトすることで、デフォルトの0.0.0.0となり、すべてのIPアドレスに対してlistenします)

;Listen = 127.0.0.1

あとは、ngIRCdをサービスに登録し、起動するだけです。

[root@localhost ~]# systemctl enable ngircd.service
[root@localhost ~]# systemctl start ngircd.service

適当なチャットクライアント(LimeChatなど)から、該当サーバに対して接続できることが確認できればOKです。(ポートは6667)

パスワードなどを設定したい場合には、/etc/ngircd.conf を触ることになります。 ircd-hybridの設定ファイルより簡単そうです。

Redmineのチケット一覧を右クリックで表示されるコンテキストメニューを調整する(View customize plugin)

確かにカスタムフィールドが多かったりすると、サブメニューが画面に収まらなくて、とても選択しづらくなります。

なぜこういったことがおこるかというと、コンテキストメニューを表示する際に、選択位置を起点として、

  • 下方向に表示して、画面上で収まれば下方向に表示
  • おさまらなければ、上方向に表示

としているようで、ここで決定した方式をサブメニューにも適用しているため、サブメニューが画面からはみ出す可能性が高くなってしまっています。上へ上へ/下へ下へと伸びててしまうイメージです。

サブメニュー表示の際に、画面から切れない位置に都度調整すればよいのですが、それはそれで実装が面倒なので、CSSで調整することによって切れる可能性を減らせないかと考えてみました。

調整方法

上へ上へと延びてしまうのが切れてしまう要因なので、上方向にコンテキストメニューを表示した際には、サブメニューは下方向にしてみます。

結構良い感じになった気がします。

あと、サブメニューで出す項目数が多いと、どうしても切れてしまいかねないので、サブメニューで表示する項目の高さの上限を設定し、それ以上の場合はスクロールバーを出すようにします。

全てのシチュエーションで切れずに選択可能とはならないかもしれませんが、かなり操作しやすくなったのではと思います。

設定内容

今回の調整を、View customize plugin使って実現してみます。

Path pattern

対象のパスはチケット一覧となります。

/issues$

Code

Type:StyleSheetとして下記を設定します。

/* 上方向に表示している時でも、サブメニューは下方向へ */
#context-menu.reverse-y > ul > li.folder > ul {
    top: 0;
    bottom: auto;
}

/* サブメニューの高さを固定にして、スクロールを出すように */
#context-menu > ul > li.folder > ul {
    max-height: 200px;
    overflow-y: auto;
}