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

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

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 ) )

では。