しばたテックブログ

気分で書いている技術ブログです。

Redmineをアップグレードしてみた

結構前にやった作業記録なんですが、個人的な備忘録としてブログに残しておきます。

blog.shibata.tech

で構築したRedmineですが新しいバージョンがリリースされていたのでアップグレードしてみました。
3.4.2 → 3.4.3へのアップグレードをしています。

1. 公式な手順

Redmineのアップグレードについて、公式な手順はこちらにあります。

アップグレード - Redmine Guide 日本語訳

日本語訳がしっかり用意されているのは私みたいな利用者からすると非常にありがたいです。

環境によって細かい手順は変わりますが、基本的には、

  • 新バージョンのRedmineの展開
  • データベースのバックアップと(必要があれば)移行
  • 添付ファイルのバックアップと移行
  • Redmineのアップグレード
  • データベースのアップグレード
  • クリーンアップ

という手順を踏むことになります。

1. 新バージョンのRedmineの展開

最初に新しいバージョンのRedmineを展開します。

現時点ではC:\redmine-3.4.2にRedmineをインストールしていますので、C:\redmine-3.4.3に新しいバージョンのRedmineを展開してアップグレードすることにします。

手順としてはもう少し後でも構わないのですが、最初に現行のRedmineのサービスを止めておきます。

# サービス停止
$REDMINE_SERVICE_NAME = "Redmine"
$REDMINE_INSTALL_PORT = 3000
Stop-Service $REDMINE_SERVICE_NAME

サービスを止めたら新しいRedmineを展開します。
この手順についてはバージョンが違うだけで前にインストールしたときと同様になります。

# 新しいRedmineの展開
$REDMINE_VER = '3.4.3'
$REDMINE_INSTALL_ROOT = 'C:\'
$REDMINE_INSTALL_PATH = Join-Path $REDMINE_INSTALL_ROOT "redmine-$REDMINE_VER"
# Zipのダウンロード
Invoke-WebRequest -Uri "http://www.redmine.org/releases/redmine-$REDMINE_VER.zip" -OutFile "$(Get-Location -PSProvider Filesystem)\redmine-$REDMINE_VER.zip"
# PowerShell 4.0だとZipを扱えないのでRubyで頑張って解凍する
# ※いったんカレントディレクトリに解凍してから移動している
gem install rubyzip --no-rdoc --no-ri
ruby -e "require 'zip'; Zip::File.open('.\redmine-$REDMINE_VER.zip') do |zip| zip.each do |entry| puts \""entry #{entry.name}\""; zip.extract(entry, entry.name) { true } end; end"
Move-Item ".\redmine-$REDMINE_VER" $REDMINE_INSTALL_ROOT -Force

2. データベースのバックアップ(とコピー)

今回の環境ではデータベースにSQLiteを使用しています。
Redmine 3.4.2のデータベースファイルを、先ほど展開したディレクトリにコピーして移行し、コピー元のファイルをバックアップとすることにします。

これは単純にファイル(config\database.ymldb\redmine.sqlite3")をコピーするだけです。

# データベースのコピー : SQLite
$OLD_REDMINE_PATH = "C:\redmine-3.4.2"
Copy-Item -LiteralPath (Join-Path $OLD_REDMINE_PATH "config\database.yml") -Destination (Join-Path $REDMINE_INSTALL_PATH "config\database.yml")
Copy-Item -LiteralPath (Join-Path $OLD_REDMINE_PATH "db\redmine.sqlite3") -Destination (Join-Path $REDMINE_INSTALL_PATH "db\redmine.sqlite3")

3. 添付ファイルのバックアップ(とコピー)

データベースと同様に添付ファイル(filesフォルダ)もコピーすることで新しいバージョンへの移行とバックアップを行います。

# filesフォルダの移行
Copy-Item -LiteralPath (Join-Path $OLD_REDMINE_PATH "files") -Destination (Join-Path $REDMINE_INSTALL_PATH "files") -Recurse

4. Redmineのアップグレード

ここからRedmineのアップグレードをしていきます。
公式な手順ではconfig/configuration.ymlを移行すると記載されていますが、今回の環境では設定していないため何もしません。
ただし、ThinをインストールするためにGemfile.localファイルを追加しているので、このファイルをコピーして移行しておきます。

# config/configuration.yml は今回の例では設定していないのでスキップ
# ただし、他にカスタマイズしている設定があればコピーしておくこと

# 今回は Gemfile.local(Thin Service用)をコピー
Copy-Item -LiteralPath (Join-Path $OLD_REDMINE_PATH "Gemfile.local") -Destination (Join-Path $REDMINE_INSTALL_PATH "Gemfile.local")

ここからは前にインストールした時と同様にbundle installを行い新しいバージョンのRedmine環境を構築します。

# DevKitへのPATHが通ってない場合は通しておく
$RUBY_DEVKIT_INSTALL_PATH = 'C:\MinGW'
$env:PATH = "$(Join-Path $RUBY_DEVKIT_INSTALL_PATH "bin");$(Join-Path $RUBY_DEVKIT_INSTALL_PATH "mingw\bin");" + $env:PATH

# bundle install
cd $REDMINE_INSTALL_PATH
bundle install --without development test rmagick --path vendor/bundle
# セッション改ざん防止用秘密鍵の作成
bundle exec rake generate_secret_token

5. データベースのアップグレード

# データベースのマイグレーション
bundle exec rake db:migrate RAILS_ENV="production"

6. クリーンアップ

# キャッシュとセッションファイルのクリア
bundle exec rake tmp:cache:clear tmp:sessions:clear RAILS_ENV="production"

7. サービス設定の変更

ここまでの手順で新しいバージョンのRedmine環境の構築が完了しているので、Thinで起動するRedmineを新しいバージョンのものに変更することで環境の切り替えを行います。

# Thinの再登録
thin_service remove -N $REDMINE_SERVICE_NAME
thin_service install -N $REDMINE_SERVICE_NAME -c "$REDMINE_INSTALL_PATH" -p $REDMINE_INSTALL_PORT -e production
# サービス起動
Start-Service Redmine

動作確認

以上でアップグレードは完了です。
ブラウザからRedmineにログインしてバージョンが新しくなっている事、正しくデータ移行できていることが確認できればOKです。

f:id:stknohg:20171209222019p:plain

PowerShellにおける"配列リテラル"について

PowerShell Advent Calendar 2017、9日目です。

qiita.com

久しぶりのPowerShellの基本がわかっていなかったシリーズです。

以前のオープンソースカンファレンス2017 Hokkaidoでの登壇などで、ふつうに

PowerShellには配列リテラルがあります。

と説明していたのですが思いっきり間違っていました。
誤った説明をしてきたことを謝罪するとともに、あらためてPowerShellにおける"配列リテラル"について説明したいと思います。

PowerShellの仕様としての"配列リテラル"

中の人であるBruce Payetteさんが書いたWindows PowerShell in ActionPowerShell Blogの記事によれば、


  • Windows PowerShell in Action : 2.4 Collections: arrays and sequencesより一部引用

Here’s how array literals are defined in PowerShell: They’re not. There’s no array literal notation in PowerShell.


  • PowerShell Blog : Array Literals In PowerShell より一部引用

The first thing to understand is that there are no array literals in PowerShell Arrays are built using operators or casts.


と、PowerShellに"配列リテラル"は存在しないと説明されています。

例えば、

$a = 1,2

$a = (1,2)

といった例における配列は両者ともリテラルではなくカンマ演算子によって生成されるものであるとされています。

また、PowerShellの言語仕様書(本エントリではV3を例示)においても、2.3.5.5 Array literalsにおいて、

2.3.5.5 Array literals

PowerShell allows expressions of array type (§9) to be written using the unary comma operator (§7.2.1), array-expression (§7.1.7), the binary comma operator (§7.3), and the range operator (§7.4).

との説明がなされ、仕様として"配列リテラル"は存在しないことがきちんと説明されていました。

PowerShellの構文から見た"配列リテラル"

私が間違った説明をした原因とも言えるのですが、PowerShellの構文上、ASTにおいては"配列リテラル"に類するものが存在しています。

先述の配列の例をShowPSAstモジュールを使いASTを可視化してみると以下の様になります。

Import-Module ShowPSAst
{ $a = (1,2) } | Show-Ast

f:id:stknohg:20171207181148p:plain

1,2の部分についてはASTとしてはArrayLiteralAstとなっておりあたかも配列リテラルを取り扱うかの様になっています。

そして、言語仕様書ではこれはarray-literal-expressionとして以下の様に定義されています。

f:id:stknohg:20171207181206p:plain

図の上部を見ればわかりますが、これはarray-literal-expressionといいつつカンマ演算子専用の構文です。

この仕様と実装のちぐはぐさが私の誤解の根本的な原因となりました。

ちなみに、仕様の説明では"二項"カンマ演算子と記載されていますが、単項や3項以上の場合でもこのArrayLiteralAstが使われます。

# 単項の場合
{ $a = ,1 } | Show-Ast

f:id:stknohg:20171207181228p:plain

# 3項以上の場合
{ $a = 1,2,3,4 } | Show-Ast

f:id:stknohg:20171207181245p:plain

【補足】配列部分式演算子について

補足としてもう一つややこしい話をします。

PowerShellにおいて配列を生成するにはカンマ演算子のほかに@()による配列部分式演算子を使うことができます。

ここでカンマ演算子と配列部分式演算子の違いについて触れておきます。

配列部分式演算子は構文としてはarray-expressionとして以下の様に定義されています。

f:id:stknohg:20171207181259p:plain

この演算子最大の特徴は()の中がstatement-listと複数の文を受け入れことができる点になります。

この説明だけみればカンマ演算子と配列部分式演算子が全然別物だと認識できる*1かと思いますが、ちょっとややこしい例を挙げてみます。

#
# カンマ演算子による配列生成
#
# 定義可能
$array01 = (
    1,
    2,
    3
)
# エラーになる
$error01 = (
    1
   ,2
   ,3
)
# エラーになる
$error02 = (
    1
    2
    3
)

#
# 配列部分式演算子による配列生成
#
# 定義可能
$array10 = @(
    1,
    2,
    3
)
# 定義可能
$array11 = @(
    1
   ,2
   ,3
)
# 定義可能
$array12 = @(
    1
    2
    3
)

この6つの配列定義についてそれぞれ定義可・不可となる理由がわかるでしょうか?
これがきちんと説明できればPowerShellの配列をマスターしたも同然です。

カンマ演算子による配列生成の解説

カンマ演算子による配列生成で$array01以外がエラーとなるのはarray-literal-expressionの定義にある通り、カンマ演算子を使い複数行にわたる配列定義を行う際のカンマは後置のみ許可されているためです。

こちらは割と直感的に理解できるのではないかと思います。

配列部分式演算子による配列生成の解説

そして、ちょっと厄介なのが$array10$array12で、これらはすべて定義可能であり同じ結果を返します。

まず、$array10

$array01 = (
    1,
    2,
    3
)

$array10 = @($array01)

と同等のイメージになります。これはわかりやすいかと思います。

つぎに$array11$array12については以下の様に;を入れるとわかりやすくなります。
本項の最初に説明した()の中に複数の文が来るケースに該当します。

# 定義可能
$array11 = @(
    1;
   ,2;
   ,3;
)
# 定義可能
$array12 = @(
    1;
    2;
    3;
)

それぞれに注釈を入れると

# 定義可能
$array11 = @(
    1;    # 文1 : 数値リテラル -> パイプライン
   ,2;    # 文2 : 単項カンマ演算子 + 数値リテラル -> パイプライン
   ,3;    # 文3 : 単項カンマ演算子 + 数値リテラル -> パイプライン
)
# 定義可能
$array12 = @(
    1;    # 文1 : 数値リテラル -> パイプライン
    2;    # 文2 : 数値リテラル -> パイプライン
    3;    # 文3 : 数値リテラル -> パイプライン
)

と、$array11は単項カンマ演算子を使った3つの文、$array12は数値リテラルを使った3つの文から構成されており、3つの文を評価した結果が配列化されることになります。

本エントリではこれ以上触れませんがそれぞれのケースに対してASTを見てみるとより分かりやすいでしょう。

最後に

とりあえずこんな感じです。

個人的にPowerShellの配列は自由度の高さとその代償としての厄介さを抱えているのかなと思っています。

追記

ぎたぱそ先生の配列生成のパフォーマンスについての記事で本エントリを取り上げてもらいました。

tech.guitarrapc.com

とても有用な内容ですので是非こちらもご覧ください。

*1:実際別物です

Application Request Routing(ARR)を使ったRedmineの設定について

blog.shibata.tech

以前に構築したWindows Server上のRedmineですが「IISと一緒に80番ポートでアクセスできる様にしたいなぁ。」と思ったのでリバースプロキシとしてApplication Request Routing(以降ARR)を導入してみました。

ARRを使ったRedmineの設定についてはググるといろいろなサイトでその手順が紹介されているのですが、割と古めの情報が多かったので、本エントリでは最新のARR 3.0を使いできるだけGUIに頼らない手順を紹介しようと思います。

参考サイト

ARRとは何ぞやといった話や、基本的な設定手順についてはMVPの田中さんの以下の記事が詳しく参考になります。

www.buildinsider.net

本エントリも基本的にはこの記事の内容に従っており、記事中ではC#で書かれている個所をPowerShellで書き直している感じになります。

0. はじめに

本エントリの前提として、Windows Serverに最小構成でRedmineをインストールするでRedmineをインストールした直後の状態からはじめます。

この環境にIISとARRをインストールし、RedmineにアクセスするためのURLの書き換えを行っていきます。

1. IISとARRのインストール

はじめにIISとARRをインストールします。
IISはWindowsの機能の追加、またはInstall-WindowsFeatureコマンドレットからインストール可能ですが、ARRと一緒にインストールするのであればWebPIからインストールするのが手っ取り早く確実です。

以下の手順でWebPIをサイレントインストールします。

# Web PI
# ダウンロード
Invoke-WebRequest -Uri "https://download.microsoft.com/download/C/F/F/CFF3A0B8-99D4-41A2-AE1A-496C08BEB904/WebPlatformInstaller_amd64_en-US.msi" -OutFile "$(Get-Location -PSProvider Filesystem)\WebPlatformInstaller_amd64_en-US.msi"
# インストール
Start-Process -FilePath "msiexec.exe" -ArgumentList @('/i', "$(Get-Location -PSProvider Filesystem)\WebPlatformInstaller_amd64_en-US.msi", '/passive') -Wait -PassThru
# PATH追加
$env:PATH = "C:\Program Files\Microsoft\Web Platform Installer;" + $env:PATH

WebPIをインストールしたらWebpiCmdコマンドが使える様になりますので、以下の様にWebpiCmd /InstallコマンドでIISとARRをインストールします。

# IIS + ARR 3.0のインストール
#   IIS-WebServer        IIS-WebServer
#   ARRv3_0              Application Request Routing 3.0
#   ManagementService    IIS: Management Service
WebpiCmd.exe /Install /Products:"IIS-WebServer,ARRv3_0,ManagementService" /AcceptEULA

f:id:stknohg:20171105210848p:plain

f:id:stknohg:20171105210903p:plain

補足としてWebpiCmdでインストール可能なプロダクトは以下のコマンドで確認することができます。
環境に応じてインストールするプロダクトを変えてやれば良いでしょう。

WebpiCmd.exe /List /ListOption:All

2. ARRの構成

ここからARRの構成を行います。
はじめにWebAdministrationをインポートしておきます。

Import-Module WebAdministration

リバースプロキシの有効化

Set-WebConfigurationPropertyコマンドでリバースプロキシを有効にします。

# リバースプロキシ有効化
Set-WebConfigurationProperty -Filter system.webServer/proxy -Name Enabled -Value $true

GUIだと以下の設定と等価になります。

f:id:stknohg:20171105211131p:plain


f:id:stknohg:20171105211148p:plain


f:id:stknohg:20171105211204p:plain

URL書き換え規則の設定 - その1

ここからURL書き換え規則を追加していきます。
書き換え規則はDefault Web Siteに対して行うものとし、

  • /http://localhost:3000/

に書き換えるルールを設定してみます。

ざっくり図にするとこんな感じです。

f:id:stknohg:20171105212112p:plain:w400

書き換え設定はGUI、CUIのどちらから行おうとも最終的にはWeb.configの設定に行きつきます。

なのでPowerShellで設定する場合でもAdd-WebConfigurationPropertySet-WebConfigurationProperty等を使ってひたすら該当する設定をしてやるしかありません。

以下の例ではReverseProxyInboundRule1という規則*1を作っています。

# Rewrite Ruleの設定
$REWRITE_SITE_PATH = "IIS:\Sites\Default Web Site"
$REWRITE_RULE_NAME = "ReverseProxyInboundRule1" # GUIで設定した時と同じ名前にしておく
$REVERSE_PROXY_HOST = "localhost:3000"
$rule = @{
    Name = $REWRITE_RULE_NAME; 
    PatternSyntax = 'ECMAScript';
    stopProcessing = 'True'
}
Add-WebConfigurationProperty -PSPath $REWRITE_SITE_PATH -Filter "system.webServer/rewrite/rules" -Name "." -Value $rule
Set-WebConfigurationProperty -PSPath $REWRITE_SITE_PATH -Filter "system.webServer/rewrite/rules/rule[@name='$($REWRITE_RULE_NAME)']/action" -Name "url" -Value "http://$REVERSE_PROXY_HOST/{R:1}"
Set-WebConfigurationProperty -PSPath $REWRITE_SITE_PATH -Filter "system.webServer/rewrite/rules/rule[@name='$($REWRITE_RULE_NAME)']/action" -Name "type" -Value "Rewrite"
Set-WebConfigurationProperty -PSPath $REWRITE_SITE_PATH -Filter "system.webServer/rewrite/rules/rule[@name='$($REWRITE_RULE_NAME)']/match" -Name "url" -Value "(.*)"

GUIだと以下の設定と等価になります。

f:id:stknohg:20171105211319p:plain

f:id:stknohg:20171105211333p:plain

f:id:stknohg:20171105211348p:plain

f:id:stknohg:20171105211404p:plain

URL書き換え規則の設定 - その2

先ほどの設定で基本的な内容は理解できたかと思いますが、これではあまり使い勝手がよくありません。

そこで追加例として、

  • /redminehttp://localhost:3000/redmine

に書き換えるルールを設定してみます。

このルールであれば/redmine/*の場合だけRedmineを、その他URLの場合はIISを利用することができます。
(/redminehttp://localhost:3000/としていないのは、このルールだとRedmine側でCSS等のパスが合わなくなるためです)

f:id:stknohg:20171105212217p:plain:w400

Redmineの設定変更

このルールに合わせるため、URL書き換えの前にRedmine側でURLにプリフィックス(/redmine)を付ける設定変更をしておきます。
Redmineでプリフィックスを付けるにはいくつか方法がある様ですが、今回は/config/environment.rbを書き換える方法を採ります。

以下の手順で/config/environment.rb

Redmine::Utils::relative_url_root = "/redmine"

の1行を追加します。

# CSS等のパスを変えるために ./config/environment.rb にPrefix設定を追加。
# http://www.redmine.org/projects/redmine/wiki/HowTo_Install_Redmine_in_a_sub-URI
$REDMINE_VER = '3.4.2'
$REDMINE_INSTALL_ROOT = 'C:\'
$REDMINE_INSTALL_PATH = Join-Path $REDMINE_INSTALL_ROOT "redmine-$REDMINE_VER"
@"
#
Redmine::Utils::relative_url_root = "/redmine"
"@ -replace "`n","`r`n" | Add-Content (Join-Path $REDMINE_INSTALL_PATH "config\environment.rb") -Encoding Default

/config/environment.rbの設定を変更した後は、Thinの起動引数に--prefixを付ける変更をしてRedmineを起動しなおします。

# サービス設定を変更
$REDMINE_SERVICE_NAME = "Redmine"
$REDMINE_INSTALL_PORT = 3000
$REDMINE_URL_PREFIX = "/redmine"
Stop-Service $REDMINE_SERVICE_NAME
thin_service remove -N $REDMINE_SERVICE_NAME
thin_service install -N $REDMINE_SERVICE_NAME -c "$REDMINE_INSTALL_PATH" -p $REDMINE_INSTALL_PORT -e production --prefix $REDMINE_URL_PREFIX
Start-Service $REDMINE_SERVICE_NAME

これでプリフィックスを付けてRedmineを起動することができ、

でアクセス可能になります。

URL書き換えルールの設定

最後にURL書き換えルールを設定します。
その1で追加したルールを以下のコマンドで書き換えます。

Set-WebConfigurationProperty -PSPath $REWRITE_SITE_PATH -Filter "system.webServer/rewrite/rules/rule[@name='$($REWRITE_RULE_NAME)']/action" -Name "url" -Value "http://$REVERSE_PROXY_HOST/{R:0}"
Set-WebConfigurationProperty -PSPath $REWRITE_SITE_PATH -Filter "system.webServer/rewrite/rules/rule[@name='$($REWRITE_RULE_NAME)']/match" -Name "url" -Value "redmine(.*)"

GUIだとこう書き換えています。

f:id:stknohg:20171105211509p:plain


f:id:stknohg:20171105211530p:plain

結果

最終的に/redmineでアクセスした場合はRedmineに、

f:id:stknohg:20171105212958p:plain

それ以外のURLでアクセスした場合はIIS(ここではデフォルトサイト)にアクセス可能になり

f:id:stknohg:20171105213110p:plain

RedmineとIISのサイトを併用可能にすることができました。

*1:GUIで設定した場合につく名前と同じ