PostgreSQL Client
Mac で PostgreSQL のクライアントは何がよいかなぁ。
勉強用なので、有料はちょっとね。
pgAdmin で良いかと思ったけど、ちょっと無理だった。
β版を使ったから、クエリウィンドウのサイズ変更が出来ないのと、日本語が満足にいれられない。
日本語使わなければいける。
環境は Vagrant の PostgreSQL に接続。
ポートフォワーディングの設定しとく。
さてどうしようかな。
これからはじめるTDD
C# で写経してみた。
Testプロジェクトは、頭に Test をつけたけど、後ろにつけるべきだったのかな。
注意点は、プロダクトの方にテストプロジェクトがアクセスするためには、プロダクト側の AssemblyInfo.cs に以下を記述すること。
[assembly: InternalsVisibleTo("TestKorekaraTdd")]
BowlingGame.cs
using System.Collections.Generic; using System.Linq; namespace KorekaraTdd { class BowlingGame { private Frame spareFrame; private List<Frame> strikes = new List<Frame> { }; private IList<Frame> frames = new List<Frame> { new Frame() }; public int FrameScore(int frameNo) { return frames[frameNo - 1].Score; } public void RecordShot(int pins) { frames.Last().RecordShot(pins); CalcSpareBonus(pins); CalcStrikeBonus(pins); if (frames.Last().IsFinished()) { frames.Add(new Frame()); } } public int Score() { int total = 0; foreach(var frame in frames) { total += frame.Score; } return total; } private void AddStrikeBonus(int pins) { foreach(var strike in strikes) { if (strike.IsNeedBonus()) { strike.AddBonus(pins); } } } private void CalcSpareBonus(int pins) { if (spareFrame != null && spareFrame.IsNeedBonus()) { spareFrame.AddBonus(pins); } if (frames.Last().IsSpare()) { spareFrame = frames.Last(); } } private void CalcStrikeBonus(int pins) { AddStrikeBonus(pins); if (frames.Last().IsStrike()) { RecognizeStrikeBonus(); } } private void RecognizeStrikeBonus() { strikes.Add(frames.Last()); } } }
Frame.cs
using System; namespace KorekaraTdd { class Frame { private int score = 0; private int bonusCount = 0; public int Score { get { return score + Bonus; } private set { score = value; } } public int Bonus { get; private set; } private int shotCount = 0; public Frame() { Score = 0; Bonus = 0; } public void AddBonus(int bonus) { Bonus += bonus; bonusCount++; } public bool IsFinished() { return Score >= 10 || shotCount > 1; } public bool IsSpare() { return Score >= 10 && shotCount > 1; } public bool IsStrike() { return Score >= 10 && shotCount == 1; } public bool IsNeedBonus() { if (IsSpare()) { return bonusCount < 1; } if (IsStrike()) { return bonusCount < 2; } return false; } public void RecordShot(int pins) { CheckPinsCount(pins); Score += pins; shotCount++; } private void CheckPinsCount(int pins) { if ((pins < 0 || 10 < pins) && Score + pins <= 10) { throw new ArgumentException(); } } } }
BowlingGameTest.cs
using System; using KorekaraTdd; namespace TestKorekaraTdd { using NUnit.Framework; [TestFixture] public class BowlingGameTest { BowlingGame game; [SetUp] public void SetUp() { game = new BowlingGame(); } [Test] public void 全ての投球がガター() { RecordManyShot(20, 0); Assert.That(game.Score, Is.EqualTo(0)); } [Test] public void 全ての投球で1ピンだけ倒した() { RecordManyShot(20, 1); Assert.That(game.Score, Is.EqualTo(20)); } [Test] public void スペアをとると次の投球のピン数を加算() { RecordSpare(); game.RecordShot(4); RecordManyShot(17, 0); Assert.That(game.Score, Is.EqualTo(18)); Assert.That(game.FrameScore(1), Is.EqualTo(14)); } [Test] public void 直前の投球との合計が10品でもフレーム違いはスペアではない() { foreach (var i in new int[] { 2, 5, 5, 1 }) { game.RecordShot(i); } RecordManyShot(16, 0); Assert.That(game.Score, Is.EqualTo(13)); } [Test] public void ストライクをとると次の2投分のピン数を加算() { RecordStrike(); foreach (var i in new int[] { 3, 3, 1 }) { game.RecordShot(i); } RecordManyShot(15, 0); Assert.That(game.Score, Is.EqualTo(23)); Assert.That(game.FrameScore(1), Is.EqualTo(16)); } [Test] public void 連続ストライクすなわちダブル() { RecordStrike(); RecordStrike(); foreach (var i in new int[] { 3, 1 }) { game.RecordShot(i); } RecordManyShot(14, 0); Assert.That(game.Score, Is.EqualTo(41)); Assert.That(game.FrameScore(1), Is.EqualTo(23)); Assert.That(game.FrameScore(2), Is.EqualTo(14)); } [Test] public void 連続3回ストライクすなわちターキー() { for (var i = 0; i < 3; i++) { RecordStrike(); } foreach (var i in new int[] { 3, 1 }) { game.RecordShot(i); } RecordManyShot(12, 0); Assert.That(game.Score, Is.EqualTo(71)); } [Test] public void ストライクの後のスペア() { RecordStrike(); RecordSpare(); game.RecordShot(3); RecordManyShot(15, 0); Assert.That(game.Score, Is.EqualTo(36)); } [Test] public void ダブル後のスペア() { RecordStrike(); RecordStrike(); RecordSpare(); game.RecordShot(3); RecordManyShot(13, 0); Assert.That(game.Score, Is.EqualTo(61)); } [Test] public void 全ての投球がガターの場合の第1フレームの得点() { RecordManyShot(20, 0); Assert.That(game.FrameScore(1), Is.EqualTo(0)); } [Test] public void 全ての投球が1ピンだと全フレーム2点() { RecordManyShot(20, 1); Assert.That(game.FrameScore(1), Is.EqualTo(2)); } private void RecordManyShot(int count, int pins) { for (var i = 0; i < count; i++) { game.RecordShot(pins); } } private void RecordStrike() { game.RecordShot(10); } private void RecordSpare() { RecordManyShot(2, 5); } } }
FrameTest.cs
using System; using KorekaraTdd; namespace TestKorekaraTdd { using NUnit.Framework; [TestFixture] class FrameTest { Frame frame; [SetUp] public void SetUp() { frame = new Frame(); } [Test] public void 全ての投球がガター() { frame.RecordShot(0); frame.RecordShot(0); Assert.That(frame.Score, Is.EqualTo(0)); } [Test] public void 全ての投球で1ピンだけ倒した() { frame.RecordShot(1); frame.RecordShot(1); Assert.That(frame.Score, Is.EqualTo(2)); } [Test] public void 二投するとフレームは完了する() { frame.RecordShot(1); Assert.That(frame.IsFinished(), Is.False); frame.RecordShot(1); Assert.That(frame.IsFinished(), Is.True); } [Test] public void 十ピン倒した時点でフレームは完了する() { frame.RecordShot(10); Assert.That(frame.IsFinished, Is.True); } [Test] public void 二投目で10ピン倒すとスペア() { frame.RecordShot(5); Assert.That(frame.IsSpare(), Is.False); frame.RecordShot(5); Assert.That(frame.IsSpare(), Is.True); } [Test] public void 一投目で10ピン倒すとストライク() { Assert.That(frame.IsStrike(), Is.False); frame.RecordShot(10); Assert.That(frame.IsStrike(), Is.True); } [Test] public void ボーナス点を加算する() { frame.RecordShot(5); frame.RecordShot(5); frame.AddBonus(5); Assert.That(frame.Score, Is.EqualTo(15)); } [Test] public void オープンフレームにはボーナス不要() { frame.RecordShot(3); frame.RecordShot(3); Assert.That(frame.IsNeedBonus(), Is.False); } [Test] public void スペアのボーナスは1投分で完了() { frame.RecordShot(5); frame.RecordShot(5); Assert.That(frame.IsNeedBonus(), Is.True); frame.AddBonus(5); Assert.That(frame.IsNeedBonus(), Is.False); } [Test] public void ストライクのボーナスは2投分で完了() { frame.RecordShot(10); frame.AddBonus(5); Assert.That(frame.IsNeedBonus(), Is.True); frame.AddBonus(5); Assert.That(frame.IsNeedBonus(), Is.False); } [Test] public void ピン数は0本以上() { Assert.Throws<ArgumentException>( delegate { frame.RecordShot(-1); }); } } }
これからはじめるTDD
C# で書いてる。
C# はたまに勉強はするけど、使ったりはしないのですぐ忘れちゃう。
今回は書籍通りに進めていく。
今は第5章まで進めた。
NUnit でテストを書いている。
NUnit - Home
NUnit は 3 の RC が出ているようだ。
3 からは 2 までについていた GUI の実行ツールがなくなっている?
Visual Studio に Test Adapter を入れる。
NUnit3 用を入れないといけないので注意!無印を入れるとテストが実行されない。
ふと思ったのだが、ボーリングはほぼしたことなくてルールをあまり知らないが、
最後に3回投げれたりしなかったかな?
この書籍だと何も言われてないが。
ボウリング - Wikipedia
特定条件でのみ投げれるようだ。
話を簡単にするために触れてないのだろう。
これからはじめるTDD
第2章を終えたところから、これは正解を見ずに書いた方が勉強になるかも、と感じ、
テストの方だけを見て、実装の方はあまり見ずにやってみた。
また、minitest は使ったことなかったので、RSpec + Guard でテストを回していた。
第3章の時点で、これはFrameクラス有った方が良いなと思って追加したので、
最終結果の変数名とか違う部分が出てきた。
最終結果で参考にして直した部分は 3点。
- Frame を 最初に MAX フレーム数配列として 10 作っていたが、current を追加していく方式に変更
- destribute_bonus のほうは、select を使う発想がなく、ストライクでも MAX 2つ前までなので、2つ前まで見る、としていたのを修正
- (0..10).cover?(pins) という書き方
他に苦労した点とは、ボーリングのルールを知らない、という点だった。
コードを見て貰う機会がないので、jnchito さんに添削してもらいたいところ。
bowling_game.rb
require_relative "frame.rb" class BowlingGame def initialize @frame_status = [ Frame.new ] end def frame_score(frame_no) @frame_status[frame_no - 1].score end def record_shot(pins) @frame_status.last.add(pins) add_bonus(pins) return change_frame if @frame_status.last.finished? end def score @frame_status.inject(0) { |sum, frame| sum += frame.score } end private def add_bonus(pins) @frame_status[0..-2].select(&:need_bonus?).each do |frame| frame.add_bonus(pins) end end def change_frame @frame_status << Frame.new end end
bowling_game_spec.rb
describe BowlingGame do describe "#record_short" do before do @game = BowlingGame.new end subject do throw_count.times.each { @game.record_shot(pins) } @game.score end context "全ての投球がガターの場合" do let(:throw_count) { 20 } let(:pins) { 0 } it { expect(subject).to eq 0 } end context "全ての投球で1ピンだけ倒した" do let(:throw_count) { 20 } let(:pins) { 1 } it { expect(subject).to eq 20 } end context "スペアをとると次の投球のピン数を加算" do before do [3, 7, 4].each { |n| @game.record_shot(n) } end let(:throw_count) { 17 } let(:pins) { 0 } it { expect(subject).to eq 18 } it "一フレームの得点が加算されていること" do subject expect(@game.frame_score(1)).to eq 14 end end context "直前の投球と合計が10ピンでもフレーム違いはspareではない" do before do [2, 5, 5, 1].each { |n| @game.record_shot(n) } end let(:throw_count) { 16 } let(:pins) { 0 } it { expect(subject).to eq 13 } end context "ストライクをとると次の2投分のピン数を加算" do before do [10, 3, 3, 1].each { |n| @game.record_shot(n) } end let(:throw_count) { 15 } let(:pins) { 0 } it { expect(subject).to eq 23 } it "一フレームの得点が加算されていること" do subject expect(@game.frame_score(1)).to eq 16 end end context "連続ストライクすなわちダブル" do before do [10, 10, 3, 1].each { |n| @game.record_shot(n) } end let(:throw_count) { 14 } let(:pins) { 0 } it { expect(subject).to eq 41 } it "一フレームの得点が加算されていること" do subject expect(@game.frame_score(1)).to eq 23 end it "二フレームの得点が加算されていること" do subject expect(@game.frame_score(2)).to eq 14 end end context "3連続ストライクすなわちターキー" do before do [10, 10, 10, 3, 1].each { |n| @game.record_shot(n) } end let(:throw_count) { 12 } let(:pins) { 0 } it { expect(subject).to eq 71 } end context "ストライク後のスペア" do before do [10, 5, 5, 3].each { |n| @game.record_shot(n) } end let(:throw_count) { 15 } let(:pins) { 0 } it { expect(subject).to eq 36 } end context "ダブル後のスペア" do before do [10, 10, 5, 5, 3].each { |n| @game.record_shot(n) } end let(:throw_count) { 13 } let(:pins) { 0 } it { expect(subject).to eq 61 } end context "全ての投球が1ピンの場合" do let(:throw_count) { 20 } let(:pins) { 1 } it "全フレーム2点であること" do subject 10.times.with_index(1) do |_, i| expect(@game.frame_score(i)).to eq 2 end end end end end
frame.rb
class Frame PITCH_MAX = 2 SPARE_POWER = 1 STRIKE_POWER = 2 MAX_PINS = 10 def initialize @pitches = [] @bonus_count = 0 @bonus = 0 end def add(pins) check_pins(pins) @pitches << pins return @bonus_count = STRIKE_POWER if strike? @bonus_count = SPARE_POWER if spare? end def add_bonus(pins) return unless need_bonus? @bonus += pins @bonus_count -= 1 end def finished? pitch_score == Frame::MAX_PINS || @pitches.count == PITCH_MAX end def need_bonus? @bonus_count > 0 end def pitch_score @pitches.count == 0 ? 0 : @pitches.inject(&:+) end def score pitch_score + @bonus end def spare? @pitches.count == PITCH_MAX && @pitches.inject(&:+) == MAX_PINS end def strike? @pitches.count == 1 && @pitches.first == MAX_PINS end private def check_pins(pins) unless (0..10).cover?(pins) && pitch_score + pins <= MAX_PINS raise ArgumentError.new("bad num of pins: #{pins}") end end end
frame_spec.rb
describe Frame do before do @frame = Frame.new end describe "#add" do context "一投分を追加した場合" do it "一投分が保存されていること" do pins = 6 @frame.add(pins) expect(@frame.instance_variable_get("@pitches")).to match_array([pins]) end end context "二投分を追加した場合" do it "二投分が保存されていること" do pins_arr = [7, 2] pins_arr.each { |pins| @frame.add(pins) } expect( @frame.instance_variable_get("@pitches") ).to match_array(pins_arr) end end context "10ピン倒した状態になった場合" do it "スペアポイントが設定されていること" do pins_arr = [4, 6] pins_arr.each { |pins| @frame.add(pins) } expect( @frame.instance_variable_get("@bonus_count") ).to eq Frame::SPARE_POWER end end shared_examples "Raise ArgumentError" do it "ArgumentError 例外が発生すること" do expect { @frame.add(pins) }.to raise_error(ArgumentError) end end context "ピン数が0未満の場合" do let(:pins) { -1 } include_examples "Raise ArgumentError" end context "ピン数が11以上の場合" do let(:pins) { 11 } include_examples "Raise ArgumentError" end context "フレームの合計ピン数が11以上の場合" do before do @frame.add(5) end let(:pins) { 6 } include_examples "Raise ArgumentError" end end describe "#add_bonus" do subject { @frame.add_bonus(pins) } let(:pins) { 7 } context "ボーナスカウントがない場合" do it "ボーナスポイントは 0 のままであること" do subject expect(@frame.instance_variable_get("@bonus")).to eq 0 end end context "スペア分のカウントがある場合" do before do @frame.instance_variable_set("@bonus_count", Frame::SPARE_POWER) end it "ボーナスポイントがつくこと" do subject expect(@frame.instance_variable_get("@bonus")).to eq pins end it "ボーナスカウントが減ること" do subject expect(@frame.instance_variable_get("@bonus_count")).to eq 0 end end end describe "#finished?" do subject { @frame.finished? } context "一投終えた場合" do before do @frame.instance_variable_set("@pitches", [2]) end it { expect(subject).to be_falsey } end context "二投終えた場合" do before do @frame.instance_variable_set("@pitches", [1, 2]) end it { expect(subject).to be_truthy } end context "一投で10ピン倒した場合" do before do @frame.instance_variable_set("@pitches", [10]) end it { expect(subject).to be_truthy } end end describe "#need_bonus?" do subject { @frame.need_bonus? } context "オープンフレームの場合" do before do [5, 3].each { |pins| @frame.add(pins) } end it "ボーナスは不要" do expect(subject).to be_falsey end end context "スペアのボーナスは1投分で完了" do before do [5, 5].each { |pins| @frame.add(pins) } end it "ボーナス付与前はボーナスが必要" do expect(subject).to be_truthy end end end describe "#score" do subject { @frame.score } context "投球が一回もない場合" do it { expect(subject).to eq 0 } end context "投球が二回あった場合" do before do @frame.instance_variable_set("@pitches", [2, 3]) end it "投球の合計が返ること" do expect(subject).to eq 5 end end context "ボーナスポイントがある場合" do before do @frame.instance_variable_set("@pitches", [3, 4]) @frame.instance_variable_set("@bonus", 9) end it "投球の合計 + ボーナスポイントが返ること" do expect(subject).to eq 16 end end end describe "#spare?" do subject { @frame.spare? } context "投球してない場合" do it { expect(subject).to be_falsey } end context "一投の場合" do before do @frame.instance_variable_set("@pitches", [5]) end it { expect(subject).to be_falsey } end context "一投ので10ピン倒した場合" do before do @frame.instance_variable_set("@pitches", [10]) end it { expect(subject).to be_falsey } end context "二投の場合" do before do @frame.instance_variable_set("@pitches", [7, 2]) end it { expect(subject).to be_falsey } end context "二投で10ピン倒した場合" do before do @frame.instance_variable_set("@pitches", [7, 3]) end it { expect(subject).to be_truthy } end end describe "#strike?" do subject { @frame.strike? } context "投球してない場合" do it { expect(subject).to be_falsey } end context "一投の場合" do before do @frame.instance_variable_set("@pitches", [5]) end it { expect(subject).to be_falsey } end context "一投ので10ピン倒した場合" do before do @frame.instance_variable_set("@pitches", [10]) end it { expect(subject).to be_truthy } end context "二投の場合" do before do @frame.instance_variable_set("@pitches", [7, 2]) end it { expect(subject).to be_falsey } end context "二投で10ピン倒した場合" do before do @frame.instance_variable_set("@pitches", [7, 3]) end it { expect(subject).to be_falsey } end end end
Eclispe で クラス図を描く
この書籍をちょっとやってみよう(目的は C# でやりたい、なんだけど)としたが、
何かやろうとすると別のことが気になってすすまない現象に。
クラス図、以前は Astah Community を使わせて頂いていたが、7.0 になってライセンスが厳しくなってしまったので、ちょっとやめとこうと。
結論としては、AmaterasUML を使わせて頂きました。
AmaterasUML - Project Amateras
GEF をインストールしないといけないらしい。www.eclipse.org
以下を追加した。
http://download.eclipse.org/tools/gef/gef4/updates/releases
「GEF」ってそのものはないので、Commonだけ入れてみた。
AmaterasUML のファイルをダウンロードしてきて、Mac 上の Eclipse ファイルを右クリックコンテキストメニューからパッケージの内容を表示で、dropins に配置。
動いたよ!
Itamae で Redmine 環境
とりあえずできた。
参考にしたものをつなぎ合わせただけだけど。
また、itamae の便利な plugin は基本使わないことにして、コードをコピっただけにした。
後で見てわけわかんなくなりそうだったので。
追記: postgesql の起動タイミングを間違っていたので修正。
再追記: さらに間違えてたので修正。また、Postfix も ipv6 無効対応をした。他にもあるかもしれないし、そもそも無効にしなくてもいいのでは・・・と思ってきた。
参考
rbenv
qiita.com
ほぼ丸パクリさせていただいた
SELINUX 無効
github.com
disabled のところ丸パクリさせていただいた
IPv6 無効
FAQ/CentOS7 - CentOS Wiki
IPv6 は使わないが、敢えて無効にする必要ないと思っていたが、
Redmine から PostgreSQL に接続するさい、IPv6 で接続しにいってしまったので
PostgreSQL
yuumi3.hatenablog.com
PostgreSQL のインストール部分をパクらせていただいた
Vagrant の設定
Box自体は前に作ったものを使う。また、Vagrantfile の以下部分のコメント外しておいた。
- Vagrantfile
config.vm.network "private_network", ip: "192.168.33.10"
Itamae ファイル
今回関係ないパッケージも別件で使うので入れてしまってる
IPv6 を無効にしているのは、Redmine が PostgreSQLに対して IPv6 で接続しに移行としてた。
pg_hba.conf で IPv6 はコメントアウトしてたので。
- recipes/base.rb
# SELinux disabled execute 'setenforce 0' do not_if 'getenforce | grep Disabled' end file '/etc/selinux/config' do action :edit block do |content| next if content =~ /^SELINUX=disabled/ content.gsub!(/^SELINUX=.*/, "SELINUX=disabled") end end # update execute "update yum repo" do command "yum -y update" end # EPEL package "epel-release" # Base Library package "asciidoc" package "compat-libcap1" package "compat-libstdc++-33" package "gcc" package "gcc-c++" package "git" package "java-1.8.0-openjdk" package "java-1.8.0-openjdk-devel" package "libaio-devel" package "libcurl-devel" package "libstdc++" package "libstdc++-devel" package "libxml2-devel" package "libxslt-devel" package "libyaml-devel" package "openssl-devel" package "readline-devel" package "tmux" package "vim" package "zlib-devel" package "ipa-gothic-fonts" package "ipa-pgothic-fonts" package "ipa-mincho-fonts" package "ipa-pmincho-fonts" # IPv6 Disable file "/etc/sysctl.conf" do user "root" action :edit block do |content| unless content =~ /ipv6/ content.concat <<-CONF net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1 CONF end end end execute "IPv6 Disable" do command <<-CMD sysctl -w net.ipv6.conf.all.disable_ipv6=1 sysctl -w net.ipv6.conf.default.disable_ipv6=1 CMD end # Postfix file "/etc/sysctl.conf" do user "root" action :edit block do |content| unless content =~ /inet_protocols = all/ content.gsub!("all", "ipv4") end end end
- recipes/rbenv.rb
RBENV_DIR = "/usr/local/rbenv" RBENV_SCRIPT = "/etc/profile.d/rbenv.sh" remote_file RBENV_SCRIPT do owner "root" group "root" source "remote_files/rbenv.sh" end execute "rbenv install" do user "root" command <<-CMD git clone git://github.com/sstephenson/rbenv.git #{RBENV_DIR} git clone git://github.com/sstephenson/ruby-build.git #{RBENV_DIR}/plugins/ruby-build CMD not_if "test -e #{RBENV_DIR}" end node["rbenv"]["versions"].each do |version| execute "install ruby #{version}" do user "root" command "source #{RBENV_SCRIPT}; rbenv install #{version}" not_if "source #{RBENV_SCRIPT}; rbenv versions | grep #{version}" end end execute "set global ruby #{node["rbenv"]["global"]}" do command "source #{RBENV_SCRIPT}; rbenv global #{node["rbenv"]["global"]}; rbenv rehash" not_if "source #{RBENV_SCRIPT}; rbenv global | grep #{node["rbenv"]["global"]}" end node["rbenv"]["gems"].each do |gem| execute "gem install #{gem}" do user "root" command "source #{RBENV_SCRIPT}; gem install #{gem}; rbenv rehash" not_if "source #{RBENV_SCRIPT}; gem list | grep #{gem}" end end execute "update gem" do command "source #{RBENV_SCRIPT}; gem update -- --system; rbenv rehash" end
- recipes/postgresql.rb
# PostgreSQL Install ver = node[:postgresql][:ver] short_ver = node[:postgresql][:short_ver] package node[:postgresql][:pgdg] do not_if "rpm -q #{File.basename(node[:postgresql][:pgdg], ".rpm")}" end package "postgresql#{short_ver}" package "postgresql#{short_ver}-server" package "postgresql#{short_ver}-contrib" package "postgresql#{short_ver}-devel" package "postgresql#{short_ver}-libs" execute "initdb" do command "PGSETUP_INITDB_OPTIONS='--encoding UTF8 --no-locale' /usr/pgsql-#{ver}/bin/postgresql#{short_ver}-setup initdb" not_if "test -e /var/lib/pgsql/#{ver}/data/postgresql.conf" end %w(pg_hba.conf postgresql.conf).each do |file| remote_file "/var/lib/pgsql/#{ver}/data/#{file}" do source "remote_files/#{file}" owner "postgres" group "postgres" mode "0600" end end [:enable, :restart].each do |act| service "postgresql-#{ver}" do action act end end # Firewall execute "firewall port open" do command "firewall-cmd --add-port=5432/tcp --zone=public --permanent" not_if "grep -c 5432 /etc/firewalld/zones/public.xml" end execute "Firewall reload" do command "firewall-cmd --reload" end
- recipes/redmine.rb
package "httpd" package "httpd-devel" package "httpd-tools" package "ImageMagick" package "ImageMagick-devel" package "subversion" package "mercurial" include_recipe "postgresql.rb" RBENV_SCRIPT = "/etc/profile.d/rbenv.sh" PSQL = "/usr/bin/psql" BASE_DIR = node[:redmine][:base_dir] remote_file RBENV_SCRIPT do source "remote_files/rbenv.sh" end execute "passenger install" do user "root" command "source #{RBENV_SCRIPT}; gem i passenger -v #{node[:passenger][:ver]}; rbenv rehash" not_if "source #{RBENV_SCRIPT}; gem list | grep -c passenger" end execute "passenger-install-apache2-module" do user "root" command "source #{RBENV_SCRIPT}; passenger-install-apache2-module --auto" not_if "test -e #{node[:passenger][:so]}" end remote_file "/etc/httpd/conf.d/redmine.conf" do owner "apache" group "apache" source "remote_files/redmine.conf" end execute "install redmine" do command "svn co #{node[:redmine][:svn]} #{BASE_DIR}" not_if "test -e #{BASE_DIR}" end execute "chown redmine directory" do command "chown -R apache:apache #{BASE_DIR}" end execute "create redmine role" do user "postgres" command <<-CMD #{PSQL} -c "CREATE ROLE redmine LOGIN ENCRYPTED PASSWORD 'pass' NOINHERIT VALID UNTIL 'infinity'" CMD not_if <<-CMD #{PSQL} -c "SELECT rolname FROM pg_roles WHERE rolname = 'redmine'" | grep -c redmine CMD end execute "create redmine database" do user "postgres" command <<-CMD #{PSQL} -c "CREATE DATABASE redmine WITH ENCODING='UTF8' OWNER=redmine" CMD not_if <<-CMD #{PSQL} -l | grep -c redmine CMD end remote_file "#{BASE_DIR}/config/database.yml" do owner "apache" group "apache" source "remote_files/database.yml" end # Issue Template execute "Issue Template" do cwd "#{BASE_DIR}/plugins" command "hg clone https://bitbucket.org/akiko_pusu/redmine_issue_templates" not_if "test -e redmine_issue_templates" end # Farend Fancy Theme git "#{BASE_DIR}/public/themes/farend_fancy" do repository "git://github.com/farend/redmine_theme_farend_fancy.git" end execute "bundle install" do cwd BASE_DIR command <<-CMD source #{RBENV_SCRIPT} PATH=/usr/pgsql-#{node[:postgresql][:ver]}/bin:$PATH gem i pg bundle install --without development test bundle exec rake generate_secret_token bundle exec rake db:migrate RAILS_ENV=production bundle exec rake redmine:plugins:migrate RAILS_ENV=production CMD end # httpd file "/etc/httpd/conf/httpd.conf" do action :edit block do |content| next if content =~ /redmine/ content.gsub!(/^DocumentRoot "\/var\/www\/html"/, %Q(DocumentRoot "#{BASE_DIR}/public")) end end [:enable, :restart].each do |act| service "httpd" do action act end end # Firewall execute "firewall port open" do command "firewall-cmd --add-service=http --zone=public --permanent" not_if "grep -c http /etc/firewalld/zones/public.xml" end execute "Firewall reload" do command "firewall-cmd --reload" end
- node.yml
rbenv: global: 2.2.3 versions: - 2.2.3 gems: [bundler] rbenv_root: /usr/local/rbenv passenger: ver: 5.0.21 so: /usr/local/rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/passenger-5.0.21/buildout/apache2/mod_passenger.so postgresql: pgdg: http://yum.postgresql.org/9.5/redhat/rhel-7-x86_64/pgdg-centos95-9.5-2.noarch.rpm ver: 9.5 short_ver: 95 redmine: base_dir: /var/lib/redmine svn: http://svn.redmine.org/redmine/branches/3.1-stable
- run.rb
上記を実行するスクリプト
include_recipe "recipes/base.rb" include_recipe "recipes/rbenv.rb" include_recipe "recipes/redmine.rb"
- 実行
% itamae ssh --host localhost -p 2222 -u vagrant ./run.rb -y node.yml
http://192.168.33.10/ にアクセスするとRedmineが動作してるはず
Itamae で Redmine環境
Itamae で Redmine 環境を構築したい。してみたい。
以下の記事で Ruby は設定。
gem で設定するものもあるけど、動きが分からなくなるので使わない。
Redmine の設定自体は RedmineJP様の記事で。
Redmine 3.1をCentOS 7.1にインストールする手順 | Redmine.JP Blog
ここで、PostgreSQL の設定で躓いてしまった。
pg_hba_conf の設定。
作った redmine ユーザで接続できないので、明日はPostgreSQL を調査する。