タグ: ChatGPT Page 2 of 3

Linuxサーバでの失敗と切り戻しと心構え。

当サイトに残しているLinuxの設定について。

多くのケースで

sudo cp -pi /etc/apache/sites-available/hoge.example.conf /path/to/backup/hoge.example.conf.$(date +%Y%m%d)
# 任意のバックアップディレクトリを指定します。

diff -u /etc/apache/sites-available/hoge.example.conf /path/to/backup/hoge.example.conf.$(date +%Y%m%d)
# バックアップが保存されたか、差分がないことで確認します。

と、バックアップを取っています。その重要性を書こうとしましたが、ChatGPTの方がうまく説明してくれるのではと思いプロンプトを叩いてみると、物の見事に答えてくれました。

設定変更作業を行う際に設定ファイルをバックアップし、失敗した場合にバックアップファイルから切り戻すことは非常に重要です。以下にその重要性をいくつか説明します:

  1. システムの安全性と信頼性の確保:
    サーバーの設定ファイルに誤った変更を加えると、サーバーの正常な動作に影響を及ぼす可能性があります。バックアップを取らない場合、問題が発生したときに元の状態に戻す手段がなくなり、システムの安全性と信頼性が損なわれる可能性が高まります。
  2. トラブルシューティングの助け:
    設定変更による問題が発生した場合、バックアップファイルを使用して元の設定に戻すことで、問題を解決する手助けとなります。バックアップがない場合、問題の特定や修正が難しく、システムの停止時間が延長される可能性があります。
  3. 変更履歴の記録:
    バックアップファイルを保存することにより、設定変更の履歴を確認できます。特定の変更が問題を引き起こす場合、どの変更が原因かを特定しやすくなります。これにより、同じ問題が将来的に再発するのを防ぐのに役立ちます。
  4. 開発とテストのサポート:
    バックアップファイルは、新しい機能や設定変更をテストする際にも役立ちます。変更前の設定ファイルを使用して、新しい設定が期待どおりに機能するかどうかを確認できます。
  5. バージョン管理とチーム協力:
    プロジェクトが複数の開発者や管理者によって共同管理される場合、バックアップファイルを使用することで、異なるバージョンの設定ファイルを比較し、変更を調整するのに役立ちます。

バックアップを取る際には、タイムスタンプを含む有効なファイル名を使用し、適切な場所に保存することをお勧めします。また、定期的にバックアップを更新し、システムの変更が行われるたびに新しいバックアップを作成することが重要です。バックアップと適切な設定管理は、システムの安全性と信頼性を確保するために欠かせないプラクティスです。

この事態が発生したので、設定ファイルを切り戻す際の心構え的なことを書いていきます。

エラーの事象を確認します。

  1. 本来とは意図しない動きが発生した。
  2. サイトそのものが見られなくなった。

など、設定変更時にはトラブルはつきものです。その際、まず、すぐ修正しようとせず

「今起きている現象は何か」

を記録しておきます。

  • システムログ
  • スクリーンショット
  • 概要

何でも構いません。「今の現象をありのまま記録する」が重要です。

切り戻しを実施します。

ある程度の記録が発生した後、「元の状態に戻す(切り戻し)」を行います。

冒頭の「hoge.example.conf」設定ファイルの変更中に不具合が発生した場合の切り戻し手順を示します。

  • 問題を起こした設定ファイルをコピーする

この作業は原因追及のために必要です。

sudo cp -pi /etc/apache/sites-available/hoge.example.conf /path/to/backup/ERROR_hoge.example.conf.$(date +%Y%m%d)
# バックアップしたファイルとは別の名前にしておきます。
  • 切り戻しを実施する

cp バックアップファイル 元のファイル

の順番を間違えると二次災害を生みます。

sudo cp -pi /path/to/backup/hoge.example.conf.$(date +%Y%m%d) /etc/apache/sites-available/hoge.example.conf 
  • サービスを再起動する

ここではWebサービス(apache)の再起動を行います。

sudo systemctl restart apache2.service

sudo systemctl status apache2.service
# サービス稼働を確認します。

修正前の状態であることを確認します。

証明書の更新作業だったら、「有効期限が延びていないこと」など、明確な指標があると楽です。

失敗を悔やむより

  1. どんな失敗があったかを記録する
  2. 元の状態に戻す
  3. その後で原因を考える
  4. 原因をフィードバックする

の方が、自分にとっても利用者にとっても建設的です。

ChatGPTによるRubyスクリプト。(エラーログ検索)

割とシンプルながら、障害などの特定を効率よくするためのスクリプトを書いてもらいました。

質問

以下の通りです。

以下を満たすスクリプトを書いてください。

1. プロンプトにてエラーログをフルパスで質問
1-1. エラーログが見つからなければ「ファイルがありません」を返して終了
2. プロンプトにて検索したい単語を指定
3. 検索単語にて行数を表示
4. 「○件見つかりました。該当する行を表示しますか?」でy/n確認
4-1. nの場合は処理を終了
4-2. yの場合は該当行を表示して終了

結果

ほぼ一発で想定通りの動きを見せるスクリプトを書いてもらいました。

# 1. プロンプトにてエラーログをフルパスで質問
print "エラーログのフルパスを入力してください: "
error_log_path = gets.chomp

# 1-1. エラーログが見つからなければ「ファイルがありません」を返して終了
unless File.exist?(error_log_path)
  puts "ファイルがありません"
  exit
end

# 2. プロンプトにて検索したい単語を指定
print "検索したい単語を入力してください: "
search_word = gets.chomp

# 3. 検索単語にて行数を表示
line_numbers = []
File.open(error_log_path, "r") do |file|
  file.each_line.with_index(1) do |line, line_number|
    line_numbers << line_number if line.include?(search_word)
  end
end

puts "#{line_numbers.length}件見つかりました。"

# 4. 「○件見つかりました。該当する行を表示しますか?」でy/n確認
unless line_numbers.empty?
  print "該当する行を表示しますか? (y/n): "
  display_lines = gets.chomp.downcase
  if display_lines == "y"
    File.open(error_log_path, "r") do |file|
      file.each_line.with_index(1) do |line, line_number|
        if line_numbers.include?(line_number)
          puts "行 #{line_number}: #{line.chomp}"
        end
      end
    end
  else
    exit
  end
else
  exit
end

エディタに記述、保存後に

ruby search_log.rb

を実行。

これで、

  • 怪しそうな箇所の行数
  • その詳細

などを絞ることが可能になり、ここからの加工も容易になります。

ChatGPTによるシェルスクリプト(パッケージの自動更新)の問題点と修正。

この記事の更に続きとなります。

以前作成したスクリプトに問題点があったので修正します。

問題点詳細

アップデートするパッケージによってはコンフィグを残すか否かをアップデート中に聞いてきます。

このプロンプトが表示されるとスクリプトは停止。処理を手動で中断して実行する羽目になります。

これを回避するため、以下のように修正いたしました。

修正差分

-    aptitude -y full-upgrade | tee $upgraded_packages >/dev/null
+    DEBIAN_FRONTEND=noninteractive aptitude -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" full-upgrade | tee $upgraded_packages >/dev/null

修正した処理の詳細

※chatGPTの回答なので信頼性は各自ご判断ください。

  1. DEBIAN_FRONTEND=noninteractive : DEBIAN_FRONTEND 環境変数に noninteractive を設定し、aptitude コマンドを非対話モードで実行します。これにより、パッケージの更新時に表示される確認メッセージを自動的に承認することができます。
  2. aptitude -y : aptitude コマンドに -y オプションを指定して、すべての質問に対して自動的に yes を返答するようにします。
  3. -o Dpkg::Options::="--force-confdef" : dpkg コマンドに --force-confdef オプションを指定して、パッケージがインストールされる際に必要なデフォルトの設定値を使用するように指定します。
  4. -o Dpkg::Options::="--force-confold" : dpkg コマンドに --force-confold オプションを指定して、既存のコンフィグファイルを保持するように指定します。
  5. full-upgrade : aptitude コマンドの full-upgrade オプションを指定して、すべてのパッケージを最新バージョンに更新します。
  6. | tee $upgraded_packages >/dev/null : 更新されたパッケージのリストを一時ファイルに保存します。パイプライン演算子 | を使用して、aptitude コマンドの出力を tee コマンドに送信し、同時に一時ファイルに書き込むように指定します。>/dev/null を追加することで、標準出力を無効化し、結果を表示しないようにします。

修正後のスクリプト全文

#!/bin/bash

# インストールされているパッケージの一覧を取得して別ファイルに出力します。
now1=$(date +%Y%m%d)
dpkg-query -W > installed_packages_$now1.txt

# aptitude updateを行います。
aptitude update

# updateの結果:
if aptitude search '~U' | grep -q '^i'; then
    # 対象パッケージ,変更前バージョン,変更後のバージョン を記入した日付付きのファイルを作成。
    now1=$(date +%Y%m%d)
    upgraded_packages=$(mktemp)

    # パッケージのキャッシュをクリアした上でパッケージアップグレードを実施。
    aptitude clean
    DEBIAN_FRONTEND=noninteractive aptitude -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" full-upgrade | tee $upgraded_packages >/dev/null

    # パッケージ一覧からの差分を別ファイルで作成。(実行日の日付を付与)
    new_packages=$(mktemp)
    dpkg-query -W > $new_packages
    diff -u installed_packages_$now1.txt $new_packages > package_diff_$now1.txt

   # 新しいパッケージ名を取得
   DIFF_FILE="package_diff_$now1.txt"
   NEW_PACKAGES=$(grep -E "^\+[^+]" $DIFF_FILE | awk '{print $1}' | cut -c 2-)

   # 変更されたパッケージの数と、新しいバージョンのパッケージ名のリストを表示
   UPDATED_PACKAGES=$(echo "$NEW_PACKAGES" | wc -l)
   echo "$UPDATED_PACKAGES 件のパッケージに変更がありました。以下のパッケージが更新されました:"
   echo "$NEW_PACKAGES"

    # checkrestartを実行して結果を取得
    now=$(date +%Y%m%d)
    checkrestart_output=$(checkrestart)

    # サービスを再起動する必要のあるプロセスを抽出してファイルに出力
    restart_services=$(echo "$checkrestart_output" | awk '/^(These are the systemd services|These are the initd scripts)/{flag=1;next}/^$/{flag=0}flag' | awk '{print $NF}' | sort -u)

    if [[ -n "$restart_services" ]]; then
        # ファイル名に日付を追加
        now2=$(date +%Y%m%d)
        filename="restart_services_$now2.txt"

        echo "以下のサービスを再起動してください:" >> "$filename"
        echo "$checkrestart_output" | awk '/^(These are the systemd services|These are the initd scripts)/{flag=1;next}/^$/{flag=0}flag' | grep -v "restart$" >> "$filename"
        echo "$checkrestart_output" | awk '/^(These are the systemd services|These are the initd scripts)/{flag=1;next}/^$/{flag=0}flag' | grep "restart$" >> "$filename"

        echo "以下のサービスを再起動してください:"
        echo "$checkrestart_output" | awk '/^(These are the systemd services|These are the initd scripts)/{flag=1;next}/^$/{flag=0}flag' | grep -v "restart$"
        echo "$checkrestart_output" | awk '/^(These are the systemd services|These are the initd scripts)/{flag=1;next}/^$/{flag=0}flag' | grep "restart$"


    else
        echo "再起動するサービスはありません"
    fi
fi

これでコンフィグを残すか否かのアップデートでも停止することなく動きましたが、肝心の

  • どのパッケージがコンフィグを残すか否か求められたか
  • その差分は何か

などが不明。なので、改善点はまだまだです。

ChatGPTが各シェルスクリプト。(motdに一文をランダムで表示)

「ちょっとしたことを試したいけど方法が分からない」時のChatGPTは本当に頼りになります。

やりたいこと

こちらの発展系。サーバログイン時にランダムに一文を書いてほしいと思い立ちました。

スクリプト

管理者権限で以下のファイルを作成します。

/etc/update-motd.d/20-quote

#!/bin/bash

# 20-quote - MOTDにquote.txtからランダムな引用を表示するスクリプト

# quote.txtファイルのパス
QUOTE_FILE="/hoge/quote.txt"

# quote.txtファイルの行数を取得する
NUM_LINES=$(wc -l < "${QUOTE_FILE}")

# ランダムな行番号を生成する
RANDOM_LINE=$((1 + RANDOM % NUM_LINES))

# ランダムな行番号に該当する引用を表示する
sed "${RANDOM_LINE}q;d" "${QUOTE_FILE}"

作成後、実行権を付与。

sudo chmod +x /etc/update-motd.d/20-quote

引用文も書いてもらいました。

quote.txt

A penny saved is a penny earned / 節約した1ペニーは1ペニー稼いだのと同じ
Actions speak louder than words / 言葉より行動
All good things come to those who wait / 望むことは遠くにあり、我慢して待てば必ず手に入る
An apple a day keeps the doctor away / 1日にリンゴを食べると医者は遠ざかる
Don't count your chickens before they hatch / 卵を孵す前に小鳥を数えるな
Every cloud has a silver lining / 苦しいことの中にも良いことがある
Fortune favors the brave / 運は勇気ある者に付きもの
Honesty is the best policy / 誠実は最高の策略
If at first you don't succeed, try, try again / 失敗してもくじけずに何度でも挑戦せよ
Necessity is the mother of invention / 必要は発明の母
No pain, no gain / 苦労なくして報酬なし
Penny wise, pound foolish / 1を惜しんで100失う (木を見て森を見ず)
Practice makes perfect / 習うより慣れろ
Rome wasn't built in a day / ローマは一日にして成らず
The early bird catches the worm / 早起きは三文の徳
The grass is always greener on the other side of the fence / 隣の芝は青く見える
The squeaky wheel gets the grease / うるさい方が注目を集める
There's no such thing as a free lunch / 無料の昼食は存在しない
Time is money / 時間は金
Where there's smoke, there's fire / 煙のあるところには火がある

ChatGptが提供したイギリスのことわざ

これで、SSHログイン時に上記の文章がランダムで表示されるようになりました。

ChatGPTによるシェルスクリプト。(外為レートの表示と記録)

概要

定額制のLightsailを利用しているとはいえ、ドルベースで請求されるので相場観は気になる数字です。

そこで、ドル円の相場をスクリプトベースで取得することにしました。

参考:

【Linux】ドル円為替情報をwgetコマンドで取得する
https://www.mtioutput.com/entry/fx-info-wget

前提

  • Ubuntu 20.04で動作を確認しています。
  • 参考先にも書いてありますが、不正アクセスと間違われないよう実行頻度などはお気をつけください。
  • また、相場観を知るためだけにこのスクリプトを作成したことを前もって強調いたします。

ChatGPTへのお伺い

以下のように訊いてみました。

以下を満たすシェルスクリプトを書いてください。

1. 以下のコマンドを実行する
wget -O - -U "" http://www.gaitameonline.com/rateaj/getrate 2> /dev/null

2. コマンド実行時の日時を取得する。

3.USDJPYを含む以下を抽出する。(以下は1のコマンド抜粋)
{"high":"132.86","open":"132.86","bid":"132.54","currencyPairCode":"USDJPY","ask":"132.55","low":"132.49"}

4. 以下のように改行して並び替える。この時、:以外の記号を取り除く。
currencyPairCode:USDJPY
open:132.86
high:132.86
bid:132.68
ask:132.69
low:132.50

4. 次のように言葉を変えて表示する。
yyyy/mm/dd hh:mm 現在のドル円相場は以下の通りです。

open:132.86
high:132.86
bid:132.68
ask:132.69
low:132.50

作成結果

そこからいくつかの質疑応答や機能追加、そして手動による修正をを繰り返しました。

最終的にできあがったのがこちらです。

  • fx_info.sh
#!/bin/bash

# fx_info.shは、外国為替相場の情報を取得し、現在のレートを表示するシェルスクリプトです。
# USD/JPYをデフォルトの通貨ペアとして使用しますが、他の通貨ペアにも簡単に変更できます。
# また、同じディレクトリに相場.csvを作成。相場の履歴を追うことも可能です。
# 参照するURLは外為オンラインの情報です。

#### 変数定義ここから #####
# 通貨ペアを変数化する。
# USDJPY=ドル円 
# EURUSD=ユーロドル
# など、以下のURLに沿ったものを指定
currency_pair="USDJPY"
#### 変数定義ここまで ####

# 1. コマンドを実行してデータを取得し、標準エラー出力を/dev/nullにリダイレクトする。
data=$(wget -O - -U "" http://www.gaitameonline.com/rateaj/getrate 2> /dev/null)

# 2. 現在日時を取得する。
date=$(date '+%Y/%m/%d')
time=$(date '+%H:%M')

# 3. 指定された通貨ペアの情報を取得する。
currency_data=$(echo "$data" | grep -o '{"high":"[0-9]*\.[0-9]*","open":"[0-9]*\.[0-9]*","bid":"[0-9]*\.[0-9]*","currencyPairCode":"'$currency_pair'","ask":"[0-9]*\.[0-9]*","low":"[0-9]*\.[0-9]*"}')

# 4. 必要な情報を取り出し、並び替える。
currencyPairCode=$(echo "$currency_data" | grep -o 'currencyPairCode":"'$currency_pair'"' | cut -d ':' -f 2 | tr -d '"')
open=$(echo "$currency_data" | grep -o 'open":"[0-9]*\.[0-9]*"' | cut -d ':' -f 2 | tr -d '"')
high=$(echo "$currency_data" | grep -o 'high":"[0-9]*\.[0-9]*"' | cut -d ':' -f 2 | tr -d '"')
bid=$(echo "$currency_data" | grep -o 'bid":"[0-9]*\.[0-9]*"' | cut -d ':' -f 2 | tr -d '"')
ask=$(echo "$currency_data" | grep -o 'ask":"[0-9]*\.[0-9]*"' | cut -d ':' -f 2 | tr -d '"')
low=$(echo "$currency_data" | grep -o 'low":"[0-9]*\.[0-9]*"' | cut -d ':' -f 2 | tr -d '"')

# 5. 結果を表示する。
echo "$date $time 現在の${currencyPairCode}相場は以下の通りです。"
echo "始値:$open"
echo "高値:$high"
echo "売値:$bid"
echo "買値:$ask"
echo "安値:$low"

## 以下はファイルに書き込むための処理。

# ファイル名を${currencyPairCode}.csvとする。
filename="${currencyPairCode}.csv"

# ファイルが存在しない場合は、ファイルにヘッダーを書き込む。
if [ ! -e "$filename" ]; then
  echo "実行日,実行時刻,相場,始値,高値,売値,買値,安値" >> "$filename"
fi

# ファイルにデータを追記する。
echo "${date},${time},${currencyPairCode},${open},${high},${bid},${ask},${low}" >> "$filename"

スクリプト作成後の処理

chmod +x fx_info.sh

スクリプト実行結果

  • スクリプト実行
./fx_info.sh
  • 実行結果
2023/03/30 13:41 現在のUSDJPY相場は以下の通りです。
始値:132.86
高値:132.86
売値:132.56
買値:132.57
安値:132.45
  • 作成されたファイル閲覧
cat USDJPY.csv
  • ファイル内容
実行日,実行時刻,相場,始値,高値,売値,買値,安値
2023/03/30,13:29,USDJPY,132.86,132.86,132.60,132.61,132.45
2023/03/30,13:31,USDJPY,132.86,132.86,132.60,132.61,132.45
2023/03/30,13:41,USDJPY,132.86,132.86,132.56,132.57,132.45

これで、ブラウザを開くことなく情報を表示することができるようになりました。

ChatGPTによるシェルスクリプト。(続:Ubuntuサーバのパッケージ全体の更新とサービス再起動の有無) 

こちらのスクリプトを修正しました。(正確にはChatGPTに修正してもらいました)

修正版スクリプト

#!/bin/bash

# インストールされているパッケージの一覧を取得して別ファイルに出力します。
now=$(date +%Y%m%d)
dpkg-query -W > installed_packages_$now.txt

# aptitude updateを行います。
aptitude update

# updateの結果:
if aptitude search '~U' | grep -q '^i'; then
    # 対象パッケージ,変更前バージョン,変更後のバージョン を記入した日付付きのファイルを作成。
    now=$(date +%Y%m%d)
    upgraded_packages=$(mktemp)

    # パッケージのキャッシュをクリアした上でパッケージアップグレードを実施。
    aptitude clean
    aptitude -y full-upgrade | tee $upgraded_packages >/dev/null

    # パッケージ一覧からの差分を別ファイルで作成。(実行日の日付を付与)
    new_packages=$(mktemp)
    dpkg-query -W > $new_packages
    diff -u installed_packages_$now.txt $new_packages > package_diff_$now.txt

   # 新しいパッケージ名を取得
   DIFF_FILE="package_diff_$now.txt"
   NEW_PACKAGES=$(grep -E "^\+[^+]" $DIFF_FILE | awk '{print $1}' | cut -c 2-)

   # 変更されたパッケージの数と、新しいバージョンのパッケージ名のリストを表示
   UPDATED_PACKAGES=$(echo "$NEW_PACKAGES" | wc -l)
   echo "$UPDATED_PACKAGES 件のパッケージに変更がありました。以下のパッケージが更新されました:"
   echo "$NEW_PACKAGES"

    # checkrestartを実行して結果を取得
    now=$(date +%Y%m%d)
    checkrestart_output=$(checkrestart)

    # サービスを再起動する必要のあるプロセスを抽出してファイルに出力
    restart_services=$(echo "$checkrestart_output" | awk '/^(These are the systemd services|These are the initd scripts)/{flag=1;next}/^$/{flag=0}flag' | awk '{print $NF}' | sort -u)

    if [[ -n "$restart_services" ]]; then
        # ファイル名に日付を追加
        now=$(date +%Y%m%d)
        filename="restart_services_$now.txt"

        echo "以下のサービスを再起動してください:" >> "$filename"
        echo "$checkrestart_output" | awk '/^(These are the systemd services|These are the initd scripts)/{flag=1;next}/^$/{flag=0}flag' | grep -v "restart$" >> "$filename"
        echo "$checkrestart_output" | awk '/^(These are the systemd services|These are the initd scripts)/{flag=1;next}/^$/{flag=0}flag' | grep "restart$" >> "$filename"

        echo "以下のサービスを再起動してください:"
        echo "$checkrestart_output" | awk '/^(These are the systemd services|These are the initd scripts)/{flag=1;next}/^$/{flag=0}flag' | grep -v "restart$"
        echo "$checkrestart_output" | awk '/^(These are the systemd services|These are the initd scripts)/{flag=1;next}/^$/{flag=0}flag' | grep "restart$"


    else
        echo "再起動するサービスはありません"
    fi
fi

差分

+   # 新しいパッケージ名を取得
+   DIFF_FILE="package_diff_$now.txt"
+   NEW_PACKAGES=$(grep -E "^\+[^+]" $DIFF_FILE | awk '{print $1}' | cut -c 2-)
+
+   # 変更されたパッケージの数と、新しいバージョンのパッケージ名のリストを表示
+   UPDATED_PACKAGES=$(echo "$NEW_PACKAGES" | wc -l)
+   echo "$UPDATED_PACKAGES 件のパッケージに変更がありました。以下のパッケージが更新されました:"
+   echo "$NEW_PACKAGES"

これによって、アップグレードするパッケージを明確化させました。

次の展望

「どこまで自動化できるか」が課題となります。パッケージによっては設定ファイルを残すかどうかのウィザードが表示されるので、それに対する自動実行までいけたらと思います。

ChatGPTによるシェルスクリプト。(Ubuntuサーバのパッケージ全体の更新とサービス再起動の有無)

脆弱性などに対応するため、Linuxサーバのパッケージを最新に保つことは重要です。

ですが、どこかでトラブルが発生した際に「どのパッケージを更新してから異常が発生したか」の履歴を追うことも必要。

そこで、以下のシェルスクリプトをChatGPTに尋ねながら作ってみました。

動作確認環境

  • Ubuntu 20.04で動作を確認しました。
  • 筆者の好みの関係上、パッケージ管理はaptitudeを用いています。
  • また、サービス再起動の有無を確認するため、checkrestartをインストールします。(debian-goodiesをインストール)

要件

ChatGPTに要求した要件は以下の通りです。

  • パッケージ一覧のリストを作成する。
  • パッケージ全体のupdateを行う。
  • そのupdateで差異があった場合はファイルに出力して更新を行う。
  • サービス再起動があったらそれを標準出力とファイルに出力する。

かなりの試行を重ねて以下のスクリプトができあがりました。

スクリプト内容

  • update-packages.sh
#!/bin/bash

# インストールされているパッケージの一覧を取得して別ファイルに出力します。
now=$(date +%Y%m%d)
dpkg-query -W > installed_packages_$now.txt

# aptitude updateを行います。
aptitude update

# updateの結果:
if aptitude search '~U' | grep -q '^i'; then
    # 対象パッケージ,変更前バージョン,変更後のバージョン を記入した日付付きのファイルを作成。
    now=$(date +%Y%m%d)
    upgraded_packages=$(mktemp)

    # パッケージのキャッシュをクリアした上でパッケージアップグレードを実施。
    aptitude clean
    aptitude -y full-upgrade | tee $upgraded_packages >/dev/null

    # パッケージ一覧からの差分を別ファイルで作成。(実行日の日付を付与)
    new_packages=$(mktemp)
    dpkg-query -W > $new_packages
    diff -u installed_packages_$now.txt $new_packages > package_diff_$now.txt

    # checkrestartを実行して結果を取得
    now=$(date +%Y%m%d)
    checkrestart_output=$(checkrestart)

    # サービスを再起動する必要のあるプロセスを抽出してファイルに出力
    restart_services=$(echo "$checkrestart_output" | awk '/^(These are the systemd services|These are the initd scripts)/{flag=1;next}/^$/{flag=0}flag' | awk '{print $NF}' | sort -u)

    if [[ -n "$restart_services" ]]; then
        # ファイル名に日付を追加
        now=$(date +%Y%m%d)
        filename="restart_services_$now.txt"

        echo "以下のサービスを再起動してください:" >> "$filename"
        echo "$checkrestart_output" | awk '/^(These are the systemd services|These are the initd scripts)/{flag=1;next}/^$/{flag=0}flag' | grep -v "restart$" >> "$filename"
        echo "$checkrestart_output" | awk '/^(These are the systemd services|These are the initd scripts)/{flag=1;next}/^$/{flag=0}flag' | grep "restart$" >> "$filename"

        echo "以下のサービスを再起動してください:"
        echo "$checkrestart_output" | awk '/^(These are the systemd services|These are the initd scripts)/{flag=1;next}/^$/{flag=0}flag' | grep -v "restart$"
        echo "$checkrestart_output" | awk '/^(These are the systemd services|These are the initd scripts)/{flag=1;next}/^$/{flag=0}flag' | grep "restart$"


    else
        echo "再起動するサービスはありません"
    fi
fi

記入後、以下を実施します。

sudo chown root:root update-packages.sh
# root権限で実施するため

sudo chmod 744 update-packages.sh

確認結果

sudo bash update-packages.sh

を実行後、

  • 現在インストールされているパッケージのバージョンを別ファイルに出力
  • パッケージのアップデート
  • その際に差分があればアップグレード
  • サービス再起動の有無を判断し、あればそのサービスを表示

という結果が出ました。

今後の展望

  • 可読性を高くする
  • 自動実行を行う
  • ログ化してローテーションを行う

等は実施したいです。

ChatGPTによるシェルスクリプト。(プロセスごとに消費メモリを表示)

検証中のLinuxサーバで

  • 外部公開する際にどのぐらいリソースを消費するのか?
  • 現在のサーバスペックで大丈夫か?
  • けど、Zabbix等の設定はめんどい

という状況は多々発生します。そこで、またもやChatGPTに

Linuxのメモリ使用量を調べるためのシェルスクリプトを書いてください。 要件は以下の通りです。

1. 稼働中のプロセスをpsで調べる
1. 複数のプロセスがあればそのRSSの合計値を足す
1. RSSの合計値を昇順で表示する としてください。

と聞いてみました。幾ばくかの質疑応答を繰り返し、以下、できあがりです。

Script内容

  • スクリプト: rsstotal.sh
#!/bin/bash

# 現在の日時を取得
now=$(date +"%Y/%m/%d %H:%M")

# 全てのプロセスのRSSの合計をKBで取得
processes_rss=$(ps -e -o rss=,comm= | awk '{a[$2]+=$1;} END {for(i in a) if(a[i]>0) printf("%d %s\n",a[i],i);}' | sort -rn)

# 全てのプロセスのRSSの合計をMBに変換して取得
total_rss_kb=$(echo "$processes_rss" | awk '{s+=$1} END {print s}')
total_rss_mb=$(echo "scale=2;$total_rss_kb/1024" | bc -l)

# メモリ使用量と各プロセスのRSSを表示
echo "$now 現在のメモリ使用量は $total_rss_mb MB です"
echo "各プロセスのRSSの使用量は:"
while read -r rss process; do
  rss_mb=$(echo "scale=2;$rss/1024" | bc -l)
  printf "%.2f MB - %s\n" $rss_mb "$process"
done <<< "$processes_rss"

記述後、

chmod +x rsstotal.sh

として実行権を付与します。

実行結果

2023/03/15 20:11 現在のメモリ使用量は 2238.71 MB です
各プロセスのRSSの使用量は:
738.42 MB - java
738.33 MB - node
101.75 MB - mongod
81.71 MB - Xorg
71.31 MB - slick-greeter
43.44 MB - npm
38.82 MB - sshd
38.53 MB - systemd-journal
30.06 MB - systemd
29.48 MB - pulseaudio
23.67 MB - nginx
22.06 MB - lightdm
20.05 MB - networkd-dispat
19.09 MB - NetworkManager
17.30 MB - bash
16.99 MB - dbus-daemon
12.56 MB - udisksd
12.37 MB - cups-browsed
11.76 MB - systemd-resolve
11.31 MB - ModemManager
9.30 MB - upowerd
9.12 MB - polkitd
9.00 MB - thermald
8.21 MB - cupsd
7.98 MB - systemd-logind
7.82 MB - accounts-daemon
7.78 MB - controller
7.60 MB - gvfsd
7.08 MB - systemd-udevd
6.99 MB - (sd-pam)
6.66 MB - at-spi2-registr
6.22 MB - at-spi-bus-laun
5.90 MB - systemd-timesyn
5.44 MB - gvfsd-fuse
5.33 MB - dconf-service
4.81 MB - bluetoothd
4.77 MB - wpa_supplicant
4.76 MB - redis-server
4.46 MB - rsyslogd
3.81 MB - avahi-daemon
3.43 MB - irqbalance
3.15 MB - awk
3.08 MB - ps
2.95 MB - rtkit-daemon
2.94 MB - cron
2.85 MB - sh
2.77 MB - rsync
1.85 MB - agetty

と表示されたのでうまくいっています。

こちらはnginxとgrowiサーバ。やはりというかjava(elasticsearch)がメモリを相当消費していました。

動作確認日

2023/03/15

ChatGPTによるシェルスクリプト。(日時を指定してのシャットダウン)

概要

「要件は定義できるけどそれを実行する術を知らない」とき、ChatGPTは非常に有用です。

そこで、以下のスクリプトを書いてもらいました。

ChatGPTへの要件

  • 指定時刻にはLinuxサーバのシャットダウンを行いたい。
  • 検証機なので、副系への切り替えなどは考慮しない。
  • 後々を考えて、スクリプトとして残し、思い立ったときには実行できるようにしたい。

ということで、以下の質問をしました。

計画停電に備え、指定時刻にLinuxサーバのシャットダウンをしたいと思います。
そこで、以下のシェルスクリプトを書いてください。

  1. 対話式で日付(YYYYMMDD)と時刻(HHMM)の入力プロンプトを出す
  2. 形式が違う場合はエラーを出し、再度の入力を求める
  3. 入力後、指定日時を表示しy/nで確認
  4. 受付後、バックグラウンドで常駐
  5. 指定時刻になったらシャットダウンを行う

ChatGPTからの回答

以下が、示したスクリプトです。

  • スクリプト名:shutdown.sh
#!/bin/bash

# 1. 日付と時刻の入力プロンプトを出す
read -p "シャットダウンする日時を指定してください(YYYYMMDD HHMM): " shutdown_time

# 2. 形式が違う場合はエラーを出し、再度の入力を求める
until [[ $shutdown_time =~ ^[0-9]{8}\ [0-9]{4}$ ]]; do
    echo "日付と時刻の形式が正しくありません。再度入力してください。"
    read -p "シャットダウンする日時を指定してください(YYYYMMDD HHMM): " shutdown_time
done

# 3. 入力後、指定日時を表示しy/nで確認
echo "指定された日時は ${shutdown_time:0:4}/${shutdown_time:4:2}/${shutdown_time:6:2} ${shutdown_time:9:2}:${shutdown_time:11:2} です。"
read -p "この日時でシャットダウンを行いますか? (y/n): " confirm

# 4. 受付後、バックグラウンドで常駐
if [[ $confirm =~ ^[Yy]$ ]]; then
    shutdown_sec=$(date -d "${shutdown_time:0:8} ${shutdown_time:9:4}" +%s)
    current_sec=$(date +%s)
    if [[ $shutdown_sec -lt $current_sec ]]; then
        echo "指定された日時は過去のため、シャットダウンは行われません。"
    else
        wait_sec=$(( shutdown_sec - current_sec ))
        echo "シャットダウンまでの待機時間は $wait_sec 秒です。"
        sudo sleep $wait_sec && sudo shutdown -h now &
        echo "シャットダウンを開始しました。"
    fi
else
    echo "シャットダウンを中止しました。"
fi

動作確認

上記スクリプトを対象サーバに保存後、以下の処理を行いました。

sudo chown root:root shutdown.sh
# shutdownコマンドは管理者ユーザのみ実行権限があるので所有者もrootにします

sudo chmod 744 shutdown.sh
# rootのみに実行権限を与えます
sudo bash shutdown.sh

と入力後、想定通りYYYYMMDD形式とHHMM形式で日付と時間を入力するよう求められました。なので、30分後などの日時を指定して実行します。

バックグラウンドで実行されているか、以下を確認しました。

ps aux |grep shutdown

# 下記の表示を確認。
# root      107296  0.0  0.0  10536   280 pts/0    S    14:27   0:00 bash shutdown.sh

その後、実行時間になってシャットダウンを確認。

動作確認日

2023/03/14

AIによる命名。(別サイト:フォトアルバム公開)

概要

「面白そう」という理由と、「安価なクラウドストレージが見つかった」という理由で開設したWebフォトアルバム。

https://hideout.reisalin.com/

ドメインなどは決まったものの、「いいサイト名が見つからない」という問題がありました。

そんな中、ChatGPTに聞いたところ思わぬ発見がありました。

質問と回答

最初の質問

まず、ChatGPTにこんな感じで聞いてみました。

Webのフォトアルバムを開設しました。 camera obscura と韻を踏む形で いいタイトルを英語でいくつか候補を挙げてください

ChatGPTの回答

以下は、"camera obscura" と韻を踏むいくつかの英語のタイトル候補です。

  1. Obscure Captures: A Camera Obscura Album
  2. Through the Lens of Camera Obscura: A Photographic Journey
  3. Capturing Shadows: An Album by Camera Obscura
  4. Obscura Moments: A Collection of Camera Captures
  5. The Obscure Beauty: A Camera Obscura Photobook
  6. Obscura Reflections: A Photographic Collection by Camera Obscura
  7. The Obscura Experience: A Camera Album of Captivating Moments
  8. Camera Obscura Chronicles: A Photographic Adventure
  9. Obscura Visions: A Camera Album of Surreal Scenes
  10. The Art of Obscura: A Camera Album of Visual Delights

好きなゲームのタイトルにもなっている「Reflection」。カメラとの相性も抜群。これをベースに更に突っ込んで聞いてみます。

和訳と回答

Obscura Reflections 、とても気に入りました。これを和訳するとどうなりますか

AIへの質問

「Obscura Reflections」を和訳すると、「オブスキュラの反射」となりますが、この場合の「reflection」は「写真や鏡に映った姿や景色」という意味ではなく、「熟考、反省、回想」という意味を持っています。つまり、「Obscura Reflections」は「カメラオブスキュラで撮影された写真を通して、過去の出来事や思い出に熟考し、回想する」というような意味を持ちます。

AIからの回答

これをベースに紹介文も書いてもらいます。

ChatGPTの紹介文

"Obscura Reflections" is a photo album inspired by moments of contemplation and introspection. Through the lens of a camera obscura, this collection captures memories and reflects on the past, inviting viewers to join in the journey of reflection and remembrance.

AIが書いた紹介文

結果

これをそのまま採用する形になりました。

なんとなく思いついたアイディアを形にするという点においてChatGPTは有用なツールです。

Page 2 of 3

Powered by WordPress & Theme by Anders Norén