同盟パズル。(アプリ版『ガイアプロジェクト』アンバス人チャレンジ)

久しぶりの『ガイアプロジェクト』の投稿。ダー・シュワームに次いで好きな種族であるアンバス人でのナイスプレイがありました。

まずは結果

184点。高得点ではありますけれど、この難易度なら200も時々あります。にもかかわらず、こうして投稿したのは理由があります。

同盟数

5同盟と惑星改造ボーナスによる追加の同盟タイル。ここまできれいに取れたのは久しぶりです。

しかも、最後の同盟は衛星を繋ぐのに必要なトークンがなくなったため

  1. 研究でQICを入手する
  2. フリーアクションで以下の資源変換を行う
    • QIC→鉱石
    • 鉱石→パワートークン
  3. 同盟接続

を行うことができました。

他にも…

  • 研究トラック「知識」を上げずに研究4ゴール
  • キッチリ取れたラウンドバスごとに同盟×3点の上級タイル
  • 最終ラウンドのブースター(鉱山×1点)

といった細かくもいいプレイを行うことができました。

  • 得られる鉱石が多め
  • 受けも攻めもやりやすく
  • 首府能力でゴリ押しもできる

好みの種族ですアンバス人。

台座と着脱。(マックスファクトリー 1/6 ライザリン・シュタウト フィギュア)

2021年12月に予約し、待つこと1年3ヶ月ほど。

ついに、この商品が届きました。

『ライザのアトリエ』最初のシリーズでの1/6完成品はほぼ間違いなくこちらが最初のリリース。

外箱の大きさはかなりのものです。

早速の撮影

専用の台座はそれだけで背景の一部。また、立像でないため固定されていないという特徴もあります。

また、上着が着脱可能。(取り外しは結構注意が必要です)

そのため、2パターンで楽しめる豪華な作品となっています。

いくつかの試し撮り

角度、光の当て方によって印象がガラリと変わるのが1/6の大きさならでは。

今後、背景を変えてみたり光源の検証などを行っていきます。

mermaid.jsによる『一杯のおいしい紅茶』抽出。

概要

昨日の続きとなります。「キチッとした手順でお茶を入れると更においしくなる」と改めて気づいて以来、しっかりとした手順でお茶を入れたいと早見表を作ってみました。

こういうときにmermaidのシーケンスダイアグラムは頼りになります。

シーケンス図

sequenceDiagram participant m as マグカップ participant p as ティーポット participant k as ケトル note over m,k: 開始 note over m,k: それぞれが清潔な状態であることを確認 note over k: お湯を沸かす note over p,m: 暖めておく note over p: 暖め完了 note over p: 茶葉を入れる note over k: 水沸騰 note over p,k: お湯をティーポットに注ぐ note over p: 抽出 note over m: 暖め完了 opt ミルクファーストの場合 note over m: 牛乳を注ぐ end note over m,p: お茶をマグカップに注ぐ opt ティーファーストの場合 note over m: 牛乳を注ぐ end opt 必要に応じて note over m: 砂糖などを入れる end note over m,k: 完了

どう書いたか

sequenceDiagram
    participant m as マグカップ
    participant p as ティーポット
    participant k as ケトル
note over m,k: 開始
note over m,k: それぞれが清潔な状態であることを確認
note over k: お湯を沸かす
note over p,m: 暖めておく
note over p: 暖め完了
note over p: 茶葉を入れる
note over k: 水沸騰
note over p,k: お湯をティーポットに注ぐ
note over p: 抽出
note over m: 暖め完了
opt ミルクファーストの場合
note over m: 牛乳を注ぐ
end
note over m,p: お茶をマグカップに注ぐ
opt ティーファーストの場合
note over m: 牛乳を注ぐ
end
opt 必要に応じて
note over m: 砂糖などを入れる
end
note over m,k: 完了

こう、流れを書くときに使えるスクリプトは便利です。

抽出『一杯のおいしい紅茶』。

概要

この「割れないティーポット」を用いてからというものの、割と真剣に「いかにしておいしい紅茶を入れることができるか」を探求しています。

そこで、『動物農場』や『1984年』などで知られる英国の作家、ジョージ・オーウェルによるエッセイ『一杯のおいしい紅茶』で紹介されているポイントを挙げたいと思います。

オーウェル卿が指摘する黄金のルール(さらっと抜き出し)

  1. 茶葉はインドかスリランカのものを使う。
  2. 紅茶は少量ずつ入れる。(つまり、ティーポットで入れる)
  3. ティーポットは金属製以外。(陶磁器を推奨している)
  4. ポットは事前に温める。
  5. 濃い紅茶を入れる。
  6. 茶葉は直接ポットに入れるべき。
  7. 茶葉を踊らせる。
  8. 円筒形のカップを用いて暖かい状態を保つ。
  9. ミルクティーの場合は紅茶が先。(これは議論の余地あり)
  10. 砂糖無しで飲むべき。

このうち、実行しているもの

紅茶は少量ずつ入れる。(つまり、ティーポットで入れる)

そのためにこのティーポットを用いているようなものです。

ティーポットは金属製以外。(陶磁器を推奨している)

オーウェル卿が存命の折、このような材質(強化プラスチック)はあったのかは不明です。

ですが、こちらは

  • 茶こし以外の金属臭がなく
  • 保温性に優れる
  • 耐久性は保証付き

となっています。

ポットは事前に温める。

時間があるときに実施。ダージリンやルイボスティーなどの高い水温が求められるお茶ではこの手間を加えるだけで全然味が違います。

円筒形のカップを用いて暖かい状態を保つ。

同じく、陶器製のマグカップを利用。ティーポットとマグカップに水を張ってレンジで温めることでこの状態を実現しています。

状況によって使い分けているもの

茶葉はインドかスリランカのものを使う。

カフェイン摂取を制限しているため、デカフェやルイボス、ハーブティーの割合の方が多いです。ですが、上記2つの茶葉は朝一番に飲んでいます。

濃い紅茶を入れる。

こちらも好みによりけり。渋みが強めに出るような茶葉では敢えて抑えることがあります。

茶葉を踊らせる。

「ステンレス製の茶こしの中で」という条件付き。

沸騰したてのお湯を使う。

デカフェで沸騰したてのお湯を用いると雑味が出るパターンが少しありました。

ミルクティーの場合は紅茶が先。(これは議論の余地あり)

英国での永遠の議論の種。これに関してはコメントを持ちません。(そもそもミルクティーは週に1~2回程度なので)

砂糖無しで飲むべき。

これもよりけりだと思います。以前に述べたキャンディス入りやドライフルーツを足して飲んで糖分も補給しています。

現時点での結論として

  1. ティーポットを用いる
  2. ティーポットとマグカップは温める
  3. 飲んでいる間は暖かい状態を保つ

の3つを守るだけでも、相当、紅茶の質は上がるというのが現時点での感想です。

連携:RedmineのディレクトリとWasabiバケット。

概要

クラウドストレージで作成したバケットは無事にマウントできるようになったので、Redmineの添付ファイルの保存先を切り替えます。

確認環境

  • Ubuntu 20.04
  • s3fsによりWasabiクラウドストレージのバケットがマウントされていること

サックリとした手順

  1. 保存先のディレクトリを作ります。
  2. Remineの添付ファイル一式をバケットにコピーします。
  3. 添付ファイルの保存先をシンボリックリンクに切り替えます。

詳細手順

マウントしたバケットにディレクトリを作成します。

sudo mkdir -p /mnt/wasabi/redmine
# 自分がマウントした環境に合わせます。

sudo chown www-data:www-data /mnt/wasabi/redmine

ls -ld /mnt/wasabi/redmine
# ファイルがあることと所有者がwww-dataであることを確認します。

Remineの添付ファイル一式をコピーします。

sudo -u www-data cp -pir /var/lib/redmine/files /mnt/wasabi/redmine
# Redmineのパスは自分の環境に合わせます。

シンボリックリンクを貼り替えます。

cd /var/lib/redmine
# 自分の環境に合わせます。

sudo mv files files.org
# 一時的に退避します。

sudo ln -s /mnt/wasabi/redmine/files files
# 自分がマウントした環境に合わせます。

sudo chown -h www-data:www-data files

ls -ld /var/lib/redmine/files
# filesの向き先がリンクを張った場所にあることとリンクの所有者がwww-dataであることを確認します

動作を確認します。

  1. Redmineの任意のチケットでファイルを添付します。
  2. 添付後、上記、マウントしたバケットの内容を確認してファイルがあることを確認します。

これで、AWSのRedmineでもファイルを大量に添付できるようになります。

fail2banの再設定。

概要

不正アクセスからサーバを保護するfail2ban。様々なルールが存在するため、チューニングの失敗によっては機能不全に陥ります。

そんなこんなで、ちょっとハマった出来事を記します。

確認実施環境

Ubuntu 20.04

fail2banはアンインストールできない場合があります。

apt-get --purge autoremove fail2ban

をやってもアンインストールできませんでした。

対処: dpkgのinfoファイル削除

sudo su -
# この作業は全て管理者権限で行った方がいいです

cd /var/lib/dpkg/info/

ls -l fail*
rm fail*
# fail2banのみのパッケージがあることを確認して消去します

apt-get --purge autoremove fail2ban
# この段階でようやくアンインストールできました

cd /etc/

rm -rf fail2ban
# fail2banの設定を変更します

と、dpkgのinfoファイルを削除して

ufwとうまく連携できません。

「なぜチューニングに失敗したのか」の理由です。ネットにあるfail2banの記事は大概がiptablesとの連携を前提としているため、Ubuntu系での標準ファイアウォールであるufwとうまく連携できませんでした。

なので、

  • 記事を鵜呑みにして設定するとエラーが発生してfail2banの起動に失敗する。
  • 再設定のためにアンインストールしようとすると上記問題が発生する

という経緯があります。

対処:ufwに即した設定変更

参考記事:
https://blog.fernvenue.com/archives/ufw-with-fail2ban/

前提:

まっさらな状態で(上記手段でアンインストールした上で)

sudo aptitude install fail2ban

を実行した状態とします。

jail.localを編集します。

協議・信仰に沿ったエディタで以下のファイルを編集(作成)します。

  • ファイル名 /etc/fail2ban/jail.local

○内容

[ufw]
enabled=true
filter=ufw.aggressive
action=iptables-allports
logpath=/var/log/ufw.log
maxretry=1
bantime=-1
ignoreip = 127.0.0.0/8 ::1
# ignoreipは任意の(自分のアクセス元)を指定ください

[sshd]
enabled=true
filter=sshd
mode=normal
port=22
protocol=tcp
logpath=/var/log/auth.log
maxretry=3
bantime=-1
ignoreip = 127.0.0.0/8 ::1
# ignoreipは任意の(自分のアクセス元)を指定ください
  • ファイル名 /etc/fail2ban/filter.d/ufw.aggressive.conf

○内容

[Definition]
failregex = [UFW BLOCK].+SRC=<HOST> DST
ignoreregex =

設定反映

systemctl enable fail2ban
systemctl start fail2ban
systemctl statsu fail2ban

これで、不審なアクセスは次回以降は有無を言わせずブロックする設定となります。

検証:AWS LightsailのUbuntuにWasabiクラウドストレージをマウント。

概要

(ほぼ)固定費でそれなりのスペックのサーバを運用できるAWS Lightsail。ストレージを増やすには

  • スペックの増強を図る
  • AWS S3などのクラウドストレージを増強する

といった策が必要です。ですが、もっと低価格で利用できるサービスはないものかと探していたところにみつけました。

クラウドストレージ:Wasabi

https://wasabi.com/ja

なかなか挑戦的な言葉が書かれています。

  1. 1TBでも6$程度
  2. データ転送料無料

は魅力的。(逆に言えば、たとえ1バイトのファイルしか保存しなくても最低1TB分は請求されます)

そして、S3と同じプロトコルが使えるとのこと。

無料トライアルもあるので、Linuxサーバにマウントできるかを検証してみます。

試した手順

環境

AWS上で動かしているUbuntu 20.04で利用しています。

さっくりとした流れ

  1. Wasabiのアカウントを作成します
  2. バケットを作成します
  3. アクセスキーを作成します
  4. Linuxサーバで必要なパッケージをインストールします
  5. アクセスキーを保存します
  6. マウントを確認します
  7. fstabを修正します

詳細の手順

Wasabiアカウント作成

上記URLから自身のアカウントを作成。確認メールからパスワードを設定します。

バケット作成

ログイン後、「バケット」をクリック。

任意のバケット名を入力し、地域を選択します。(ここでは大阪を選択)

バージョン管理などは全て無効の状態で「次」をクリック。

確認画面後に「バケットを作成」で作成できました。

アクセスキーの生成

アクセスキーをクリックし「新しいアクセスキーを作成する」からアカウントキーと秘密鍵を控えます。(この情報は全てのストレージへのアクセスに必要となるため、取り扱いは厳重にしてください)

Linuxサーバ上での動作

スナップショット取得

念のため、作業直前にAWSコンソールからスナップショットを作成します。

必要パッケージインストールします

sudo aptitude update
sudo aptitude install s3fs

パスワードファイルの作成

信仰・協議に従ってエディタを起動します。次のファイルを作成します。

.passwd-s3fs
# アクセスキー:秘密鍵 の順番で貼り付け

chmod 600 .passwd-s3fs

ls - ${HOME}/.passwd-s3fs
# ファイルがあることを確認します

マウントポイントの指定

sudo mkdir /mnt/wasabi
# /mntファイルに任意の名前を作成ください

udo s3fs 【wasabiで作成したバケット名】 /mnt/wasabi -o passwd_file/【上記作成したパスワードファイルのパス】/.passwd-s3fs -o url=https://【バケットのリージョン名】.wasabisys.com -o use_path_request_style -o endpoint=【バケットのリージョン名】 -o allow_other

これでマウントしたことを確認しました。

WasabiのWebインタフェースから任意のファイルをアップロード。

cd /mnt/wasabi 
# 作成したマウントポイントに移動します

ここから、アップロードしたファイルが確認できれば設定完了です。

fstabの設定

システムを再起動してもマウントできるようにfstabの設定を追記します。

sudo cp -pi /etc/fstab /path/to/directory/fstab.date +%Y%m%d
diff -u /etc/fstab /path/to/directory/fstab.date +%Y%m%d
# 差分がないことでバックアップを確認します

バックアップ後、協議・信仰に従ったエディタで末尾に追記します。

s3fs#【wasabiバケット名】 /mnt/wasabi fuse _netdev,allow_other,passwd_file=/【パスワードファイルのパス】/.passwd-s3fs,url=https://s3.バケットのリージョン名wasabisys.com,use_path_request_style,endpoint=バケットのリージョン名 0 0

マウント確認

sudo mount -a
# エラーが出ないことを確認します

df -h
# マウントしたバケットが見えているかを確認します

今後の検証

トライアルの間、

  • マウントしたディレクトリに保存されたファイルをWebに公開できるか
  • 遜色なく利用できるか
  • 転送速度などに問題ないか

を確認後、本格的に使っていこうと思います。

スクリプト:連携。(パスワード生成を呼び出したSQLバックアップ)

概要

ChatGPTに助けられて作成した

  • SQLのバックアップを行うシェルスクリプト
  • より安全なパスワード生成を行えるRubyスクリプト

この2つを連携させてみました。

スクリプトのフロー図

以下のようにして動きます。

sequenceDiagram participant b as バックアップ participant p as パスワード生成 note over b: 処理実行 note over b: 作業ディレクトリ<br>作成 note over b: MySQL dump b->>p: スクリプト呼び出し note over p: 処理実行 note over p: PW発行 note over p: PWファイル作成 p-->>b: スクリプト実行完了 note over b,p: PWファイルを元に暗号化 note over b: 作業ディレクトリ<br>削除 note over b: 古いバックアップ削除 note over b,p: 古いPWファイルを削除 note over b: 処理完了

スクリプト内容

スクリプト1: DBバックアップ

  • スクリプトタイプ:シェルスクリプト
#!/bin/bash

## 変数ここから ##
# SQLをバックアップするディレクトリ(保管先)を指定します。
backup_dir="/home/backup/mysql"
# 保持するバックアップの世代を日数で指定します。
keep_days=7
# ファイルに付与する日付/作業ディレクトリ名/バックアップファイル名を指定します。
current_date=$(date +%Y%m%d)
backup_name="redmine_mysql_${current_date}"
zip_file="redmine_mysql.${current_date}.zip"
# アカウントファイルを指定します。
credentials_file="$HOME/mysql/account.txt"
# パスワードを生成するスクリプトの格納場所を指定します。
password_generate="$HOME/scripts/ruby/password_generate_for_redmine.rb"
# 上記スクリプトによって生成されたパスワードファイルの格納場所を指定します。
password_file="$HOME/restore_password/mysql-restore.${current_date}.txt"
# バックアップ時に指定するオプションを指定します。
options="--defaults-extra-file=$credentials_file --no-tablespaces --single-transaction"
## 変数ここまで ##

## 処理ここから ##

# 1.アカウントファイルのパーミッションが400かどうかチェックします。
# 400以外は処理そのものを終了します。
permissions=$(stat -c "%a" "$credentials_file")
if [ "$permissions" != "400" ]; then
    echo "アカウントファイルのパーミッションは400である必要があります。"
    exit 1
fi

# 2.一時的なバックアップディレクトリを作成します。
mkdir "${backup_dir}/${backup_name}"

# 3. mysqldumpを実行してデータベースのバックアップを取ります。
mysqldump $options -h localhost redmine > "${backup_dir}/${backup_name}/${backup_name}.sql"

# 4. パスワードによる暗号化を実施します。
ruby "$password_generate"
password=$(cat "$password_file")
cd "${backup_dir}/${backup_name}"
zip -r "${backup_dir}/${zip_file}" -P "$password" .
cd -

# 5. 一時的なバックアップディレクトリを削除します。
rm -rf "${backup_dir}/${backup_name}"

# 6.パスワードの読み取り権限を600に変更します。
chmod 600 $password_file

# 7. 保持期間より古いバックアップファイルを削除します。
find "$backup_dir" -name "redmine_mysql.*.zip" ! -type f -newermt "${keep_days} days ago" -delete
find "$password_file" -name "*.txt" -type f -mtime +$keep_days -delete

スクリプト2:パスワード生成

  • スクリプトタイプ: Ruby
#このRubyスクリプトは、SecureRandomモジュールを使用してランダムなパスワードを生成するためのスクリプトです。
#パスワードの生成に関する様々な設定を変数で行うことができます。
#例えば、パスワードの長さ、数字やアルファベット、大文字や記号を使用するかどうかなどを指定することができます。
#スクリプトは、出力先がファイルか標準出力かを選択できます。
#ファイルに出力する場合は出力先のディレクトリやファイル名を指定することができます。

# モジュールを呼び出します 
require 'securerandom'
require 'fileutils'
require 'date'

### 変数はここからです
## 出力するパスワードの数(行数)を数字で指定します
num_passwords = 1
## 出力先を選択します
# ファイルに出力する場合は 1、標準出力に出力する場合は 0 に設定します
output_to_file = 1
# 出力先のディレクトリを指定します
output_directory = '/home/hoge/restore_password' 
# 出力ファイル名を名前+yyyymmdd形式.txtで指定します
# 最初の''部分の名前を任意の名前に入力ください
output_filename =  'mysql-restore.' + Time.now.strftime("%Y%m%d") + '.txt'
## パスワードの強度を指定します
# パスワード桁数を数字で指定します
password_length = 12
# 数字を用いる場合は1を、用いない場合は0を指定します
use_numbers = 1
# アルファベット小文字を用いる場合は1を、用いない場合は0を指定します
use_alphabet = 1
# アルファベット大文字を用いる場合は1を、用いない場合は0を指定します
use_uppercase = 1
# 記号を用いる場合は1を、用いない場合は0を指定します
use_symbols = 1
## パスワード生成用の文字種を定義します
# 必要に応じて使わない文字を削除することが可能です(lと|, 0とOなど)
characters = ''
characters += '0123456789' if use_numbers == 1
characters += 'abcdefghijklmnopqrstuvwxyz' if use_alphabet == 1
characters += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' if use_uppercase == 1
characters += '!#$%&()*+,-./:;<=>?@[]^_`{|}~' if use_symbols == 1
### 変数はここまでです

# パスワード生成関数を定義します
def generate_password(length, characters)
  SecureRandom.random_bytes(length).unpack('C*').map do |byte|
    characters[byte % characters.length]
  end.join
end

## パスワードファイルを出力する場合(変数 output_to_fileを1にしたとき)の処理です
#出力先のパスを作成します
if output_to_file == 1
  output_path = File.join(output_directory, output_filename)
# 出力先のディレクトリが存在しない場合は作成します
  FileUtils.mkdir_p(output_directory)
# パスワードを出力します
  File.open(output_path, 'w') do |file|
    num_passwords.times do
      password = generate_password(password_length, characters)
      file.puts password
    end
  end
else

## 標準出力に出すだけの場合(変数 output_to_fileを0にしたとき)の処理です
# パスワードを標準出力に出力します
  num_passwords.times do
    password = generate_password(password_length, characters)
    puts password
  end
end

上記、Rubyスクリプトを「変数の定義でファイル出力と標準出力」の2つが選べるようにしたのは幸いでした。(パスワード1つのみを使うので行数も1にしています)

Redmineプラグイン導入時に起因するエラーの発生原因と対処方法について

こちらの記事を更に詳細にまとめたものとなります。

概要

様々なプラグインにより機能を追加できるのがRedmineの魅力。
しかしながら、そのプラグイン導入の過程によって予期せぬエラーが起きます。

本記事では、エラーの内容と対処、並びにこれが起きないための運用について筆者の経験を元に書き起こしています。

想定としている読者

  • LinuxでRedmineを動かしている
  • その管理をしている / 管理を任されている
  • プラグインインストール時にエラーが発生している

エラーが起きた環境

種別環境1環境2環境3
OSUbuntu 20.04CentOS 7Ubuntu 22.04
Redmine4.23.35.0
DBMySQL 8.3.xMariaDB 5.5.xMySQL 8.3.x
Ruby2.72.33.1

具体的に何が起こったか?

Case 1. エラー画面が表示され、どこにもアクセスできない。

We're sorry, buty something went wrong.
We've been notified about this issue and we'll take a look at it shortly.

この画面は「やってしまったか」感がとても強いです。

Case 1.の原因

経験上、以下の理由で発生しました。

原因1-1:DBマイグレーションをしていない

プラグインインストール時、DBのマイグレーションを行っていない手順ミスはありがちです。

原因1-1の対処:DBマイグレーションを行う。

こちらはrailsとapacheの手順です。自身の環境に合わせて実施してください。

cd /home/www-data/redmine && pwd
# Redmineのルートディレクトリに移動します。自分の環境に合わせます。

sudo -u www-data bundle exec rake redmine:plugins:migrate RAILS_ENV=production
# RedmineのルートディレクトリでDBマイグレーションを実施します

sudo systemctrl restart apache2.service
# Webサービスを再起動します。

原因1-2: プラグイン名とレポジトリが異なる。(バージョン名が付与されている)

view_customizeのように、プラグイン名とレポジトリ名が異なるパターンはあります。

例:
https://github.com/onozaty/redmine-view-customize
と、レポジトリ名はredmine-view-customizeですが、実際のプラグイン名は
view_customizeです。

また、zipを直接入手した場合は、解凍したディレクトリにバージョン名が付与されます。

原因1-2の対処: ディレクトリをリネーム

以下は一例です。

cd /home/www-data/redmine/plugins && pwd
# Redmineのルートディレクトリに移動します。
sudo mv redmine-view-customize view_customize

sudo -u www-data bundle exec rake redmine:plugins:migrate RAILS_ENV=production
# RedmineのルートディレクトリでDBマイグレーションを実施します

sudo systemctrl restart apache2.service
# Webサービスを再起動します。

原因1-3: プラグインとRedmineのバージョンが合ってない。

例として:
https://www.redmine.org/plugins/redmine_custom_workflows

  • Compatible with Redmine 5.0.x, 4.2.x, 4.1.x.

と書かれているように、古いRedmineのバージョンに合ってないプラグインをインストールしたときに起こりがちです。

また、逆に、プラグインが新しいRedmineに対応していない時にも発生します。

原因1-4: 導入済みのプラグインとコンフリクトを起こしている。

ある種、オープンソースの宿命と言えます。
有志/企業が機能を追加しているので、他のプラグインと同じライブラリを用いていたりDBのテーブルが重複するなどで発生します。

以下のように、メンテナが相性が悪いプラグインを認識している場合はそれに注意すればいいのですが、多数あるプラグイン同士の相性をチェックするのは極めて難しい問題です。

https://github.com/ncoders/redmine_local_avatars

As reported in issue #12, the plugin "mega_calendar" ist not compatible with this plugin due to an issue with the provided users_controller_path.rb file.

原因1-3 / 原因1-4の対処: プラグインのアンインストール

こちらも、rails / apacheでの実施です。自分の環境に合わせて実施してください。

cd /home/www-data/redmine && pwd
# 自分の環境に合わせます。

sudo -u www-data bundle exec rake redmine:plugins:migrate NAME=プラグイン名 VERSION=0 RAILS_ENV=production
# プラグイン名は /plugin/配下にあるディレクトリ名です

cd plugins && pwd
# プラグインが配置されているディレクトリに移動します。

sudo rm -rf プラグイン名

ls -ld /home/www-data/redmine/plugins/プラグイン名
# 削除したディレクトリが存在しないことを確認します

sudo systemctl restart apache2.service

上記、プラグインに起因したエラーの大半はDBの再マイグレーションやアンインストールによって解消しますが、これだけで収まらないのがRedmineプラグイン追加/アップデートの恐怖です。

Case 2. 一部の機能が使えない (Internal Error)

Case1.で発生したエラー画面の対処としてDB再マイグレーションやアンインストールを行った後、この事象が起きました。

  1. ログインはできる
  2. あるプラグインにアクセスできる

けれども、

  1. 管理画面に遷移する
  2. チケット一覧を見ようとする
  3. 他のプラグインの画面を見ようとする

等で、

Internal Error
An error occured on the page you were trying to access.
If you continue to experience problems please contact your Redmine administrator for assistance.
If you are the Redmine administrator, check your log files for details about the error.

の無慈悲なメッセージが出てきます。特にRedmineをファイルサーバ化するdmsfプラグイン周りで発生しました。

こうなると、

  • DBの再マイグレーション
  • プラグインアインインストール

でも、今の筆者の知見では修復できませんでした。その場合の対処方法は以下の通りです。

Case 2の対処方法: バックアップしたDBからの切り戻し

この作業は、「エラーを起こす前のDBバックアップデータを持っていないと元に戻すことはできません」

この前提条件がない場合は他の有識者に頼ってください。(少なくとも筆者は持ち合わせていません)

また、以下の環境で復旧を確認しています。

  • MySQL 8.0.3系
  • Redmine 5.0
  • Redmine 4.2

手順

  • プラグインアンインストール(実施済みの方は不要です)
cd /home/www-data/redmine && pwd
# 自分の環境に合わせます。

sudo -u www-data bundle exec rake redmine:plugins:migrate NAME=プラグイン名 VERSION=0 RAILS_ENV=production
# プラグイン名は /plugin/配下にあるディレクトリ名です

cd plugins && pwd
# プラグインが配置されているディレクトリに移動します。

sudo rm -rf プラグイン名

ls -ld /home/www-data/redmine/plugins/プラグイン名
# 削除したディレクトリが存在しないことを確認します

sudo systemctl restart apache2.service
  • バックアップしたDBのレストア
cd /hoge && pwd
# DBデータをバックアップしたディレクトリに移動します。

mysql -h DBホスト -u RedmineのDBユーザ -p RedmineのDB名 < RedmineのDBバックアップ
# 例 mysql -h localhost -u redmine -p redmine < redmine_backup.$(date +%Y%m%d).sql
# この処理で聞かれるパスワードはredmineインストール時に設定したDBユーザのものです

sudo systemctl restart apache2.service

この後、元に戻っていれば作業は完了です。

こうならないために

日々のバックアップを取る

これは必須です。最低限、データベースの定期的なバックアップを取り、障害に備えましょう。

参照(『こうなってしまったため』書き起こしました:)

また、作業前に

cd /hoge && pwd
# 任意のバックアップディレクトリに移動します

mysqldump -h localhost -u redmine -p --no-tablespaces --single-transaction redmine > redmine_backup.$(date +%Y%m%d).sql
# それぞれ -h ホスト名 -u redmine -p ユーザ オプション db名です。
# パスワードはredmineインストール時に設定したDBユーザのものです

等の、DBバックアップも必要です。

システムごとバックアップを取る

仮想サーバで動かしている、AWSのようなクラウドサービスを利用している場合はスナップショットを取得し、OSごとバックアップするのが後腐れありません。

ChatGPTによるRubyスクリプト。(パスワード生成スクリプト)

ChatGPTを利用するようになってから、「こういう処理ができたら仕事の処理が楽になるのに」が現実的になりました。

概要

割と設定する機会があるパスワード。

  • キチッとランダムに
  • 桁数や出力数が指定可能で
  • ファイルに出力する必要があるか
  • または標準出力に表示させればいいのか

を設定するRubyスクリプトはできないものかとChatGPTにお伺い。幾度かの対話を繰り返し、ようやく想定通りの動きをするスクリプトができました。

openssl rand と異なり、

  • 大文字/小文字の利用
  • 数字や記号の混在

を細かく設定できるのがポイントです。

生成・編集したスクリプト

  • スクリプト名:password_generate.rb

前提

以下の環境で動作を確認しました。

  • Ubuntu 20.04 LTS
  • CentOS 7
  • Ruby 2.4 / 2.7.0

スクリプト内容

  • password_generate.rb
#このRubyスクリプトは、SecureRandomモジュールを使用してランダムなパスワードを生成するためのスクリプトです。
#パスワードの生成に関する様々な設定を変数で行うことができます。
#例えば、パスワードの長さ、数字やアルファベット、大文字や記号を使用するかどうかなどを指定することができます。
#スクリプトは、出力先がファイルか標準出力かを選択できます。
#ファイルに出力する場合は出力先のディレクトリやファイル名を指定することができます。

# モジュールを呼び出します 
require 'securerandom'
require 'fileutils'
require 'date'

### 変数はここからです
## 出力するパスワードの数(行数)を数字で指定します
num_passwords = 12
## 出力先を選択します
# ファイルに出力する場合は 1、標準出力に出力する場合は 0 に設定します
output_to_file = 1
# 出力先のディレクトリを指定します
output_directory = '/home/hoge/restore_password' 
# 出力ファイル名を名前+yyyymmdd形式.txtで指定します
# 最初の''部分の名前を任意の名前に入力ください
output_filename =  'mysql-restore.' + Time.now.strftime("%Y%m%d") + '.txt'
## パスワードの強度を指定します
# パスワード桁数を数字で指定します
password_length = 10
# 数字を用いる場合は1を、用いない場合は0を指定します
use_numbers = 1
# アルファベット小文字を用いる場合は1を、用いない場合は0を指定します
use_alphabet = 1
# アルファベット大文字を用いる場合は1を、用いない場合は0を指定します
use_uppercase = 1
# 記号を用いる場合は1を、用いない場合は0を指定します
use_symbols = 1
## パスワード生成用の文字種を定義します
# 必要に応じて使わない文字を削除することが可能です(lと|, 0とOなど)
characters = ''
characters += '0123456789' if use_numbers == 1
characters += 'abcdefghijklmnopqrstuvwxyz' if use_alphabet == 1
characters += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' if use_uppercase == 1
characters += '!#$%&()*+,-./:;<=>?@[]^_`{|}~' if use_symbols == 1
### 変数はここまでです

# パスワード生成関数を定義します
def generate_password(length, characters)
  SecureRandom.random_bytes(length).unpack('C*').map do |byte|
    characters[byte % characters.length]
  end.join
end

## パスワードファイルを出力する場合(変数 output_to_fileを1にしたとき)の処理です
#出力先のパスを作成します
if output_to_file == 1
  output_path = File.join(output_directory, output_filename)
# 出力先のディレクトリが存在しない場合は作成します
  FileUtils.mkdir_p(output_directory)
# パスワードを出力します
  File.open(output_path, 'w') do |file|
    num_passwords.times do
      password = generate_password(password_length, characters)
      file.puts password
    end
  end
else

## 標準出力に出すだけの場合(変数 output_to_fileを0にしたとき)の処理です
# パスワードを標準出力に出力します
  num_passwords.times do
    password = generate_password(password_length, characters)
    puts password
  end
end

使い方

  1. 変数を環境に合わせて定義します。
  2. ruby password_genarate.rbを実行します。
  3. 定義したとおりパスワードファイルが出力されていたり、画面に表示されれば成功です。

今後の展望

  • 他のスクリプトで呼び出す(以前に紹介したMySQLバックアップ時にパスワードをかけるなど
  • 対話式で実行

など、使い勝手に合わせて修正していきたいです。

Page 85 of 246

Powered by WordPress & Theme by Anders Norén