部屋を掃除したら漫画が沢山出てきたので書く日記

漫画とか合唱とかUNIXとかLinuxとかについて書く日記です。

tarを利用して特定のディレクトリを移動する

/export/home/bata64/Solaris

というディレクトリを、

/var/tmp/Solaris

としてコピーしたいとします。

このとき、

$ cp -rp /export/home/bata64/Solaris /var/tmp/Solaris

とか実行すると、ディレクトリ以下にシンボリックリンクが存在する場合実ファイルとしてコピーされてしまいます(参考:)。
なので、大量にデータが格納されているディレクトリ、例えば何からのソフトウェアがインストールされているディレクトリ等の場合、cpだとどうなっているのかわからないので危険です(古くからのSolaris使う人からは伝承のように「大事なディレクトリのデータコピーのときはcp使うな」と教わったものです)。
mvだと良さそうですが、コピー元がなくなってしまうので、なんらかのトラブルで処理中断した場合、移動したデータと移動しなかったデータに分かれてしまい復旧が大変になります。どうすればいいのか?


いまどきのLinuxとかだと色々対処方法がありますが、昔はtarを使うしかなかったようです。
すなわち、こうしていました。

$ cd /export/home/bata64/
$ tar cpf - Solaris |(cd /var/tmp/;tar xpfB -)

アーカイブデータを標準出力に渡し、パイプで受けて所定ディレクトリに移動してそれを展開する、というものです。
tarはその名が示すとおりテープにアーカイブするために作られたコマンドですが、アーカイブ時にパーミッションディレクトリ以下のファイル構造を維持できるという特徴を活かし、いつしかアーカイブファイル作成用コマンドとして使われ、様々な技法が編み出されたようです。

これは便利なコマンドがインストールされていない、ネットもつながらないのでyum install出来ない、というような環境下でなんとかする時に非常に便利です。tarとbashの標準出力、標準入力のパイプ渡しはUNIXエンジニアの伝統技術みたいなものだと思いますので、これは覚えておきたいところです。

ではー。

ディレクトリを移動せずにtarアーカイブを作る

こちらのエントリに書いてある内容を調べている際に、定年が近いミスターSolarisおじさん(近年までオフィスでの執務PCがUltra60だった)が何気なくやってらして、「やべー知らんかった」とショックを受けたのでご紹介します。

bata64.hatenablog.jp


何をしたいかというと、

/export/home/bata_dir

を、

/var/tmp

以下に、

bata_dir.tar

というファイル名でtarアーカイブしたい場合、

$ cd /export/home/

してから

$ tar cf /var/tmp/bata_dir.tar bata_dir

を実行していたわけです。

$ tar cf /var/tmp/bata_dir.tar /export/home/bata_dir

とかやると、展開時に絶対パス(/export/home)に展開されてしまいますから・・・。

が、このように-Cオプションをつけて実行すれば、cdでディレクトリ移動しなくて良いのでした。

$ tar cf /var/tmp/bata_dir.tar -C ./export/home bata_dir

一行ですむので大変便利です。

ではー。

特定ディレクトリを除外してtarアーカイブを作る

何をしたいかというと、

[bata64@Server ~]$ find pl
pl
pl/総合順位表.csv
pl/ShinMasuzawa
pl/ShinMasuzawa/config
pl/ShinMasuzawa/config/config.pl
pl/ShinMasuzawa/config/config.BAK
pl/ShinMasuzawa/Build.PL
~中略~
pl/Masuzawa
pl/Masuzawa/EXCEL_TEST
pl/Masuzawa/EXCEL_TEST/新増沢方式審査用紙tmp.csv
pl/Masuzawa/EXCEL_TEST/新増沢方式審査用紙.csv
pl/Masuzawa/EXCEL_TEST/新増沢方式審査用紙.xlsx
pl/Masuzawa/EXCEL_TEST/新増沢方式審査用紙tmp.xlsx
pl/Masuzawa/EXCEL_TEST/Bata
pl/Masuzawa/EXCEL_TEST/Bata/GetData.BAK
pl/Masuzawa/EXCEL_TEST/Bata/GetData.pm
pl/Masuzawa/EXCEL_TEST/Bata/CSV.BAK
~略~

という構造のplディレクトリをtarアーカイブしたい場合、

[bata64@Server ~]$ tar cf /var/tmp/pl.tar pl

とすれば良いですが、当然plディレクトリ以下の全てのディレクトリ、ファイルを含めたアーカイブファイルである「pl.tar」が出来上がります。

このとき、「pl/Masuzawa」以下のディレクトリとファイル以外をtarアーカイブしたい場合は以下のようにします。

除外ディレクトリを書いたテキストファイル(除外ディレクトリ記載ファイル)を用意する

[bata64@Server ~]$ vi ~bata64/xfile

とかで編集し、

pl/Masuzawa

と記入します。複数ある場合は改行区切りで、

pl/Masuzawa
pl/sirakaba/aozora/minamikaze
pl/sen/masao

みたいに書いていけば良いです。

  • 絶対パスではなく該当ディレクトリ以下のみ記述
  • 余計な空白、改行があるとエラー出さずに失敗(除外されない)するようですのでご注意ください。

がポイントです。

除外ディレクトリ記載ファイルを指定してtarアーカイブ作成

plディレクトリの直上ディレクトリに移動します。

plディレクトリの絶対パス

/export/home/bata64/pl

である場合、

/export/home/bata64/

に移動する、という事です。
その上で、-Xオプションをつけて除外ディレクトリ記載ファイルを指定してtarアーカイブを作成します。

[bata64@Server ~]$ tar cfX /var/tmp/pl.tar ~bata64/xfile pl

これでOK。本当に除外されているかどうかを知りたければ-vオプションつけて

[bata64@Server ~]$ tar cfvX /var/tmp/pl.tar ~bata64/xfile pl

として標準出力を目視でがんばるか、出来上がったtarアーカイブを-tオプションで眺めればよいと思います。

[bata64@Server ~]$ tar tfv /var/tmp/pl.tar

注意点

私はSolarisだいすきっ子ですので以下の環境で試しました。

SPARC Solaris10 1/13
SPARC Solaris8 10/01

すると、

  • Solaris10の場合/usr/sfw/bin/gtarでは成功
  • Solaris8に別途インストールしたGNU tar(バージョン1.13)ではエラーが出ず成功したように見えるが除外されていない
  • Solaris8のOSバンドル tarでは成功

という結果になりました。Solarisで試して上手く行かないなー、という方はtarのバージョンとかを疑ってみてはいかがでしょう。

なお、カーネル2.6台のLinuxとかSolaris11にバンドルされているGNU tarの場合は大体成功します(というかいまどきのOSであれば大体大丈夫でしょう)。

余談

この機能、除外ディレクトリ記載ファイルの書き方まで解説してくれてるサイトがなかなか見つからなかったので、会社のベテランSolaris大好きおじさんと一緒に検証してみました。

ではー。

x86版Solaris10物理サーバをVirtualBoxへ移行(P2V)

2009年に買ったマザーボードで組んだPCにてx86 Solaris10を稼働、主にpukiwikiサーバとして活用しています。

bata64.hatenablog.jp

bata64.hatenablog.jp

bata64.hatenablog.jp

ただ、半年に1回程度ハングするため*1に再起動が必要となる運用をしていたので少々煩わしさを感じていました。

そんな中、新たに「C2750D4I」というマザーボードを購入し、x86 Solaris11サーバとして稼働させました。
このマザーボードはメモリ、HDD共にたくさん積むことが出来るので仮想化環境の基盤的な使い方をするとよさそうだ、と考えたので、勉強もかねて物理Solaris10サーバを仮想化環境へ移行(いわゆるP2V)してみる事にしました。
仮想化ソフトウェアはSolaris11でも動くフリーのもの、という事でVirtualBoxを選びました。

*1:HW由来なのかOSなのか不明・・・

続きを読む

ZFSスナップショットを管理するPythonスクリプト

Pythonの勉強がてら作ってみました。

概要

指定された日数経過したZFSスナップショットをzfs destroyコマンドで削除します。

前提条件

該当Solaris11サーバは日次で全ZFSのスナップショットを取得しており、書式は

[ZFS名]@YYYYmmddHHMMSS

とする。
また、Pythonのバージョンは

3.5.1

とする。

使い方

Usage: ./rotate_zfs_snapshot.py [ZFS name] [age_date]

ZFS「bata64/data」の、30日経過したスナップショットを削除したい場合は

 ./rotate_zfs_snapshot.py bata64/data 30

とすればよい。
なお、スーパユーザ権限が必要です。

ソースコード

初めて作ったのでくどいほどコメントを入れてみました。

#!/usr/bin/env python

import sys
import datetime
import subprocess
import re

## プログラム実行時の引数を取得
param = sys.argv

## 引数の数を取得(コマンド名+引数の数値が取得される)
check_params = len(param)

## 引数の数が2でない場合は使用例出して異常終了
if check_params != 3:
    print ("Usage: " + param[0] + " [ZFS name] [age_date]")
    sys.exit(1)

## 第一引数で渡された値を取得(ZFS名)
snapshot_name = param[1]

## 第二引数で渡された値を取得(エージング期間)
age_date = int ( param[2] )

## datetimeモジュールで現時刻を取得
date_now = datetime.datetime.now()

## datetimeモジュールで今から○日前の日付を、しきい値として取得
date_threshold = date_now - datetime.timedelta( days = age_date )

## zfs list -H -t snapshotを実行してスナップショット一覧を取得
cmd_zfs_list = subprocess.Popen([ 'zfs', 'list', '-H', '-t', 'snapshot' ], stdout=subprocess.PIPE)

### 実行結果がbyte型で渡されたので、文字型として扱うためにデコードして変数へ代入
out_zfs_list = cmd_zfs_list.communicate()[0].decode('utf-8')
cmd_zfs_list.stdout.close()

## zfs list実行結果を1行ずつ(改行区切り)でリストに格納
list_zfs_list = out_zfs_list.split('\n')

## zfs list実行結果を解釈するための正規表現を定義。Perlだと /^(ZFS名@([0-9]{14}))\s/ という感じ
text_re = r'^'+ r'(' + snapshot_name + r'@' + r'(' + r'[0-9]{14}' + r')' + r')' + r'\s'

## 正規表現パターンをコンパイル
p = re.compile( text_re )

## zfs list実行結果が入ったリストをfor文で1個ずつ処理
for line in list_zfs_list:
    ## zfs list実行結果を正規表現パターンで判定
    matchOB = p.match( line )
    ## 正規表現パターンにマッチしていたら処理実行
    if matchOB:
        ## 正規表現グループ化によってスナップショット名の@より右側(取得日時)を取得
        date_snapshot = matchOB.group( 2 )
        ## 正規表現グループ化によってスナップショット名(取得日時)を取得
        name_snapshot = matchOB.group( 1 )
        ## スナップショット取得日時をdatetimeモジュールで日時データへ変換
        date_snapshot_datetime = datetime.datetime.strptime(date_snapshot, '%Y%m%d%H%M%S')
        ## スナップショット取得日時がしきい値より古い場合処理実行
        if date_snapshot_datetime <= date_threshold:
            ## zfs destroyコマンド実行
            status_zfs_destroy = subprocess.call([ 'zfs', 'destroy', name_snapshot ], stdout=subprocess.PIPE)
            ## コマンド応答ステータスが0であれば成功した旨出力
            if status_zfs_destroy == 0:
                print ( "destroy " + name_snapshot + " SUCCESS." )
            ## コマンド応答ステータスが0以外であれば失敗した旨と応答ステータスを出力
            else:
                print ( "destroy " + name_snapshot + " FAIL. CODE = " + str ( status_zfs_destroy ) )

では。

Solaris11.1にDBD::mysqlをインストール(追記あり)

Solaris11.1にHRForecastをインストール - 部屋を掃除したら漫画が沢山出てきたので書く日記で行った、DBD::mysqlのインストールについてです。これがかなりハマりました。

※2014年4月2日追記
cpanmを実行する前に

PATH=/opt/solarisstudio12.3/bin

というようにSolarisStudioをインストールした上でPATHに設定してやれば、下記で説明している作業をする事なくインストールに成功するようです。
事情があってSolarisStudio使えない方は以下の手順で頑張ってみてください。

続きを読む

Solaris11.1にHRForecastをインストール

はじめに

kazeburoさん作成のHRForecastというグラフ作成ツールを使おうと思いました。理由としては

  • Perlで書かれている
  • 過去日付のデータも登録できる(同じくkazeburoさん作成のGrowthForecastには無い機能)

だからです。

で、会社のマイSolaris 11.1サーバにインストールしようとしたら苦労したのと、ネットで検索したら私が困った事の解決方法そのものズバリが見つからなかったので書いてみます。

前提条件

OS: Oracle Solaris 11.1 X86 64bit版
Perl: v5.18.1 on plenv 2.1.1
mysql: Ver 14.14 Distrib 5.1.37, for pc-solaris2.11 (i386) using readline 5.1
HRForecast: 2013年11月8日現在の最新版(86a47c399b)
CPANモジュールのインストールにはcpanmを使用する。
その他、gitとかcurlとかcpanmとか、登場するツールは全てインストール済みである事。
続きを読む