paloma blog

NWエンジニアやってます。主に自宅環境のお遊びを書きます。Pythonもちょっと。タイトルは好きなカクテルから。

録画サーバのディスク容量をmonitで監視して通知する

あけましておめでとうございます。

今年のおみくじは大吉だったのですが、年明け早々メインマシンのOSが上がらなくなってしまいました。
(ハング中に電源落として上がらなくなったのですが、多分セクタ不良)

なので一発目はタブレットからの投稿です。

昨年やっと録画サーバを構築したのですが、ディスクが少ないのですぐ一杯になってしまいます。
構築優先で全然ディスク設計を考慮しませんでした。

幸い今のところディスク満タンで取れてなかったという状況は無かったのですが、
そろそろ監視でもしようと思いツールを導入しました。

やりたいこと

  • 録画サーバの監視
  • 小規模なので簡易なツールでOK
  • スマホとかで確認できるもの

ということで監視ツールはmonitにしようと思います。

通知方法

slack通知など流行ってますが、とりあえず私はSlack使ったことないのでメール通知設定をします。
とりあえず出先で確認できるようになれば良いです。

インストール

これだけ

$ sudo aptitude install monit

監視設定

ディクス容量と通知ができればよいので最低限の設定にします。

ディスク監視だけなので間隔は5分でいいかな。

set daemon 300

メール設定

# MTA作るのめんどくさいのでGmailを利用
set mailserver smtp.gmail.com port 587 username "xxxxxx@gmail.com" password "xxxxxx" using tlsv1 with timeout 30 seconds

# メールフォーマットはデフォルトのまま
set mail-format {
  from:    monit@$HOST
  subject: monit alert --  $EVENT $SERVICE
  message: $EVENT Service $SERVICE
                Date:        $DATE
                Action:      $ACTION
                Host:        $HOST
                Description: $DESCRIPTION

           Your faithful employee,
           Monit
}

# 送信先
set alert xxxxxx@gmail.com

あとディスク容量だけ監視したいので、この設定を行います。
conf.d以下に別ファイルを作ります。

# ディスク使用率が90%を超えたらアラート
check device disk with path /dev/mapper/ubuntu--vg-root
 if inode usage > 90% then alert

テスト

テスト用にmonitプロセスを再起動してみます。

$ sudo systemctl restart monit

結果

f:id:paloma69:20180121125519p:plain

できました!
これでアラートが飛んでくるはずですね。

今後改良したいこと

  • NASを作って録画ファイルはそこに保存する
  • Slack通知に変更する
  • メールよりより気づけるはず

参考サイト

MonitでGmailをSMTPサーバとして使う - Qiita

ということで簡単に監視設定ができました!

本当はmonitインストールまでにaptitudeのインストールやら
bootディレクトリ容量フルの解決などしてたので準備が結構時間かかりました...。

参考サイト見つつ作りたいものは作れるようになってきましたが、お世話になりっぱなしです。
今年は自分からそういう発信をしていきたいですね。
なのでもっと勉強しないと!

パルスのファルシのルシがコクーンでパージをランダムで展開する

インフラ屋としてシェル芸勉強中の身ですが、こんなtweetが流れてきました。

f:id:paloma69:20171223112858p:plain

このtweetを見てなぜかこれを思い出したので、
(FF13ですよね。未プレイですが)

dic.nicovideo.jp

この文をpythonでやってみようと思ったのがこちら。

ちなみに2点候補があるようですが私は未プレイのため個人的に語感のいい1を正解とします。

  1. パルスのファルシのルシがコクーンでパージ
  2. パルスのファルシのルシがパージでコクーン
#! python3

import random

pulse = ['パルス', 'ファルシ', 'ルシ', 'パージ', 'コクーン']

shuffle = random.sample(pulse, 5)

print('{0}の{1}の{2}が{3}で{4}'.format(*shuffle))

やりたいこと

  • 文字列のリストをシャッフルして出力する
  • 文字列の重複はしない

シャッフルはrandomモジュールを使用します。
シャッフルしたリストを返してほしいのでsample関数を使用します。
(shuffle関数だと一回シャッフルするだけなので、値は返らない)

また、最後のリストを展開する際に前に*をつけないとエラーになるようです。

>>> print('{0}の{1}の{2}が{3}で{4}'.format(shuffle))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: tuple index out of range # これは後で調べる

実行してみる

環境はfedora python classroom の vagrant版です。

(python3) [vagrant@localhost vagrant]$ python FF13.py
パージのコクーンのファルシがパルスでルシ

できました!
シャッフル率ってどのくらいなんですかねえ。
試しに20回ほど回してみます。

(python3) [vagrant@localhost vagrant]$ for a in {1..20} ; do python FF13.py ; done
パージのルシのパルスがコクーンでファルシ
ルシのコクーンのパージがファルシでパルス
パルスのファルシのルシがコクーンでパージ  # 正解
パルスのパージのコクーンがファルシでルシ
パージのファルシのルシがコクーンでパルス
パルスのコクーンのファルシがパージでルシ
コクーンのパルスのファルシがパージでルシ
ルシのパルスのコクーンがファルシでパージ
パルスのルシのパージがコクーンでファルシ
ルシのコクーンのファルシがパルスでパージ
コクーンのルシのファルシがパージでパルス
ルシのファルシのコクーンがパージでパルス
パージのコクーンのパルスがファルシでルシ
ルシのファルシのコクーンがパージでパルス
パージのコクーンのルシがファルシでパルス
パージのファルシのルシがパルスでコクーン
ファルシのパルスのルシがパージでコクーン
パルスのルシのファルシがパージでコクーン
ルシのコクーンのファルシがパルスでパージ
ルシのコクーンのパルスがパージでファルシ
(python3) [vagrant@localhost vagrant]$

一回でてきましたね。 1/20だから正解率は5%でしょうか。

とは書いたものの、未プレイのためどの文章が本当は正しいかわかりません...

参考サイト

qiita.com

シェルだとこちら

echo "パルス,ファルシ,ルシ,コクーン,パージ"  \
  | tr "," "\n" | sort -R | tr "\n" " " | awk '{print $1"の"$2"の"$3"が"$4"で"$5}'
(python3) [vagrant@localhost vagrant]$ echo "パルス,ファルシ,ルシ,コクーン,パージ"  \
>   | tr "," "\n" | sort -R | tr "\n" " " | awk '{print $1"の"$2"の"$3"が"$4"で"$5}'
パルスのパージのファルシがコクーンでルシ
(python3) [vagrant@localhost vagrant]$

上と同じ仕組みですが、寿司バージョン

echo "寿司,ご飯,魚,神" \
| tr "," "\n" | sort -R | tr "\n" " " | awk '{print $1"は"$2"の上に"$3"が乗ってるから"$4}'
(python3) [vagrant@localhost vagrant]$ 
ご飯は魚の上に寿司が乗ってるから神
(python3) [vagrant@localhost vagrant]$

スクレイピングでFワードを数える

映画が好きでよく見るんですが、パルプフィクションが面白くて3回くらい見てしまいました。
映画を見ていても感じるんですが、Wikiにもこんな記載があります。

パルプ・フィクション - Wikipedia

  • 劇中でのfxxkの使用回数は250回を超える。
    ※一応全編通して伏字にします。

本当に250回も言っているのか?
勉強中のスクレイピングで検証します。

コード

スクレイピングの書き方は勉強中のこちら
Automate the Boring Stuff with Python

#! python3

import requests, bs4
from collections import Counter, defaultdict

url = 'http://www.imsdb.com/scripts/Pulp-Fiction.html'

res = requests.get(url)
res.raise_for_status()

soup = bs4.BeautifulSoup(res.text, "html.parser")

# Search script
script = soup.pre.text
dict = Counter(script.split())

# Convert to lower case
lower_d = defaultdict(int)

for key, val in dict.items():
    lower_d[key.lower()] += val

# Search f-word
for key, val in lower_d.items():
    if key.find('fxxk') >= 0:
        print(key.ljust(40), str(val).rjust(1))

実行してみる

メインマシンは環境が汚いので、Fedora Python ClassroomのVagrant版で実行します。

(python3) [vagrant@localhost work]$ python pulp.py
fxxking                                  3
fxxkin'                                  91
motherfxxkers'                           1
fxxk                                     30
fxxk,                                    1
motherfxxkers!                           2
fxxked                                   7
motherfxxkin-house,                      1
motherfxxker                             5
motherfxxker.                            8
motherfxxker,                            2
english-motherfxxker-can-you-speak-      1
motherfxxkin'                            4
motherfxxkers                            3
fxxker                                   1
fxxks                                    1
fxxk's                                   3
motherfxxker!                            2
motherfxxker's                           1
fxxked-up                                1
motherfxxker"                            1
(python3) [vagrant@localhost work]$

取れました!
いろんなバリエーションがありますね。 

数を計算すると...169個!
あれ...全然少ない。
アドリブで言ってるってこと?
とりあえずうまいことスクレイピングできたので良しとします。

あとがき

復習がてらコードの解説も書こうと思ったけど長くなりそうなのでやめます。
簡単なコードですが、世の中に公開する私の初めてのコードになります。
これからもっと頑張って勉強したいと思います。
でも本業のインフラの勉強もやらないと!

おまけ

shellでやれば一発でした。

(python3) [vagrant@localhost work]$ curl -s http://www.imsdb.com/scripts/Pulp-Fiction.html | tr " " "\n" | grep [fF]xxk  | sort | uniq -c | awk '{s += $1} END {print s}'
169

詳細

(python3) [vagrant@localhost work]$ curl -s http://www.imsdb.com/scripts/Pulp-Fiction.html | tr " " "\n" | grep [fF]xxk  | sort | uniq -c
      1 English-motherfxxker-can-you-speak-
     25 fxxk
      1 fxxk,
      5 fxxk
      7 fxxked
      1 fxxked-up
      1 fxxker
     89 fxxkin'
      2 fxxkin'
      3 fxxking
      1 fxxks
      3 fxxk's
      3 motherfxxker
      2 motherfxxker,
      2 motherfxxker!
      8 motherfxxker.
      2 Motherfxxker
      1 Motherfxxker"
      3 motherfxxkers
      1 motherfxxker's
      2 motherfxxkers!
      1 motherfxxkers'
      4 motherfxxkin'
      1 motherfxxkin-house,

退屈なことはPythonにやらせよう4

仕事のトラブルで気づいたら2週間近く更新してなかった。 読み進めてるので溜まってるので書けるとこまで。

今読んでる章

Chapter 9 – Organizing Files

覚えた構文

Chapter 7 正規表現

  • import re
  • re.compile(r'文字列')

    • 文字列をコンパイルし検索を早くする
    • r(raw)はバックスラッシュ等も表示
  • search

    • 文字列の検索
  • group
    • マッチした文字列の出力
  • findall
    • マッチした部分をすべて表示

Chapter 8 ファイルの読み書き

  • open
    • ファイルオープン
    • open('filename', 'mode')
      • mode: r(read), w(write), a(append)
  • close
    • ファイルクローズ
    • 閉じないとPythonがプロセス持ち続けてしまう
  • shelve
    • 別ファイルにデータを格納する
      • .bak, .dat, .dir (使い分けは調べる)
    • 消したくないデータはこのモジュールを使う
    • DBを使うほどではないが消したくないときに使うのがよいらしい

Chapter 9 ファイルのコピーとか

  • import shutil
  • os.walk
    • ディレクトリ内のファイル、フォルダを表示できる
    • TreeをとるにはForで回す
  • import zipfile
    • zipの作成、展開ができる
    • close()を忘れずに
code
  • 多いので割愛

実行環境にAnacondaを入れてみた。 今日からJupyterを使って動作確認しています。 正しい使い方ではないかもしれないがログがとりやすくなった...と思う。

こんな感じ f:id:paloma69:20171111223532p:plain

退屈なことはPythonにやらせよう3

昨日の続き

今読んでる章

Chapter 6 – Manipulating Strings

覚えた構文

code
  • 章の最後にあるプログラムを作ろうコーナー

  • コード内に記載のパスワードをクリップボードにコピーする
    pyperclipというモジュールを使ってクリップボードに保管するらしいが、pyperclipのエラーが出て今く動かない...
    もう少し調べる。

#! python3
# pw.py - An insecure password locker program.

PASSWORDS = {'email': 'xxxxxxxx',
             'blog': 'xxxxxxx'}

import sys, pyperclip
if len(sys.argv) < 2:
    print('Usage: python pw.py [account] - copy account password')
    sys.exit()

account = sys.argv[1] # first command line arg is the account name

if account in PASSWORDS:
    pyperclip.copy(PASSWORDS[account])
    print('Password for ' + account + ' copied to clipboard.')
else:
    print('There is no account named ' + account)

退屈なことはPythonにやらせよう2

英語なので不明な単語は飛ばしつついきます。

今読んでる章

Chapter 6 – Manipulating Strings

覚えた構文

  • upper()
  • lower()
    • 文字列を大文字、小文字にする
  • isalpha()
    • 文字のみであればTrueを返す
  • isalnum()
    • 文字と数字があればTrueを返す
  • isdecimal()
    • 数字のみであればTrueを返す
  • isspace()
    • スペース、タブ、改行のみであればTrueを返す
  • istitle()

    • 大文字で始まり小文字が続く語句であればTrueを返す(間違ってるかも)
  • isX系のmethodはvalidationに使われるらしい。

  • startwith()

  • endwith()

    • 文字列の開始、終わり系
  • join()

  • split()

    • 文字列の分割、結合
  • rjust()

  • ljust()
  • center()
    • 文字列の詰め系

code

def printPicnic(itemsDict, leftWidth, rightWidth):
    print('PICNIC ITEMS'.center(leftWidth + rightWidth, '-'))
    for k, v in itemsDict.items():
        print(k.ljust(leftWidth, '.') + str(v).rjust(rightWidth))
picnicItems = {'sandwiches': 4, 'apples': 12, 'cups': 4, 'cookies': 8000}
printPicnic(picnicItems, 12, 5)
printPicnic(picnicItems, 20, 6)
---PICNIC ITEMS--
sandwiches..    4
apples......   12
cups........    4
cookies..... 8000
-------PICNIC ITEMS-------
sandwiches..........     4
apples..............    12
cups................     4
cookies.............  8000
  • Stringの説明はusefulが多くて全部書くとリファレンスの和訳になってしまうので割愛します。
  • 文字列はいろんな表現に活用できるようでいろいろ紹介されているだけあって覚えたほうがよさそう。

退屈なことはPythonにやらせよう1

ちょっとさぼったら間が空いていけませんね。
首記の英語版が無料で読めるので通勤の電車で読んでます。

Udacityと違ってわからないとこは飛ばせるのでこっちを書いていこう。

途中の章からですが、とりあえず一日一個書き続けなければ。

今読んでる章

Chapter 5 – Dictionaries and Structuring Data

覚えた構文

辞書型

  • {}で囲む
  • 順序性はない
method
  • key()
    • keyを出力
  • value()
    • 値を出力
  • items()
    • 両方出力
code
spam = {'color': 'red', 'age': 42}
for k, v in spam.items():
    print('Key: ' + k + ' Value: ' + str(v))