それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

ruby でGmail(smtp) 経由でメールを送信する。TLS有効化

ruby でメールを送信する

ruby からgmail を送信するには、 mail ライブラリだけでも出来るんだけど。

MIMEエンコードされたデータを受け取ってそのまま forward するには、もう少しいい方法がないかなと思って考えていた。

メールリレーの中間に入って、指定メールだけを転送したいとか、smtp-proxy を作っておきたいとかそういうときに活用できる。いちいちデコードして作り直しててめんどくさくてですね。

net/smtpgmail 送信。

require 'bundler'
Bundler.setup
require 'net/smtp'
require 'mail'
require_relative '../etc/gmail-passwd'



smtp = Net::SMTP.new("smtp.gmail.com", '587')
smtp.enable_starttls
smtp.start(
    'smtp.gmail.com',
    $gmail_account.username,
    $gmail_account.password,
    :login
)

mail = Mail.new
mail.from = "webmaster@example.com"
mail.to  = "takuya@example.com"
mail.subject = "test"
mail.body ="test test"
mail.attachments["photo.jpg"] = File.binread( File.expand_path( "./photo.jpg",  File.dirname($0) ) )


smtp.send_mail( mail.encoded , mail.from, mail.to )

これで、ファイルを入れているプロジェクトで bundle install したら大丈夫。

添付ファイルの準備。

送信テストで添付ファイルを使いたいので準備します。

convert -background white -fill black -pointsize 256 label:'Hello World' photo.jpg

送信テスト。

bundler init 
bundler add mail
bundler install 
ruby test-mail.rb

これで送信できます。

Mailのみの場合

mail ライブラリで新規メール作成して、送信するにはMail だけでいける。

require 'mail'


mail = Mail.new

mail.delivery_method(:smtp,
                     address:        "smtp.gmail.com",
                     port:           587,
                     domain:         "smtp.gmail.com",
                     authentication: :login,
                     user_name:      $gmail_account.username,
                     password:       $gmail_account.password
)


mail.from = "webmaster@example.com"
mail.to  = "takuya@example.com"
mail.subject = "test"
mail.body ="test test"

mail.deliver

qcow2へ raw(qcowのnon-sparse) イメージを変換して sparse にする virt-sparsify

non-sparse から sparse なファイルにコピーする

qemu で使える raw image なnon sparseな hdd イメージを qcow2 形式の sparse なファイルにする。

生イメージだとどうしてもディスク容量が節約できないので動的にディスク容量を確保するほうが良いよね。

virt-sparsify

直接イメージをマウントしてコピーすると手順が大変なことになってしまいます。そこで virt-sparsify というコマンドが用意されています。

インストール

virt-sparsify は guestfs-tools に含まれて配布されるようです。

takuya@:~$ virt-sparsify

Command 'virt-sparsify' not found, but can be installed with:

sudo apt install libguestfs-tools

変換

変換は、直接ファイルを「書き換える」のではなく、コピーになります。

sudo virt-sparsify   FROM TO

コマンド例

virt-sparsifyはいくつオプションがあり、便利に使える。

virt-sparsify --check-tmpdir=fail  $SRC  $DST
virt-sparsify --in-place  $SRC $DST
virt-sparsify   $SRC--compress $DST

--check-tmpdir=fail/tmp を使う前に残容量を確認し、容量不足になりそうならエラーとする。

--compress は出来上がりのファイルを圧縮形式にする。使ってみた感じだとシングルスレッドで実行は遅いので時間がかかる。非圧縮に比べ容量は確実に減る。

--in-placeは、一時ファイルを作成せずに直接ファイルを書き換えに行く。容量不足になりそうならこれも選択肢である。ただし、sparsify 中に電源断などプロセスが止まったらファイルは壊れる。

状況に応じて使い分けるのがいい。

実際に変換してみた

takuya@host:~$ sudo virt-sparsify   /var/lib/libvirt/images/ubuntu-1910.img  /var/lib/libvirt/images/ubuntu-1910.sp.qcow2
[   0.0] Create overlay file in /tmp to protect source disk
[   0.0] Examine source disk
[  10.4] Fill free space in /dev/ubuntu-vg/root with zero
[ 477.6] Fill free space in volgroup ubuntu-vg with zero
[ 478.0] Copy to destination and make sparse
[ 922.2] Sparsify operation completed with no errors.
virt-sparsify: Before deleting the old disk, carefully check that the
target disk boots and works correctly.

なるほど。これでsparse ファイルになるのか。

無事に sparse なファイルに変換されました。メッセージには「念の為、起動してチェックしろよ」と書いてあります。

出来上がりを見てみます。

こっちが元のファイル。

takuya@:~$ sudo qemu-img info  /var/lib/libvirt/images/ubuntu-1910.img
[sudo] password for takuya:
image: /var/lib/libvirt/images/ubuntu-1910.img
file format: qcow2
virtual size: 200G (214748364800 bytes)
disk size: 191G
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: false
    refcount bits: 16
    corrupt: false
After

次に、スパースファイルになった側

takuya@:~$ sudo qemu-img info  /var/lib/libvirt/images/ubuntu-1910.sp.qcow2
image: /var/lib/libvirt/images/ubuntu-1910.sp.qcow2
file format: qcow2
virtual size: 200G (214748364800 bytes)
disk size: 71G
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: false
    refcount bits: 16
    corrupt: false

実際に消費する実ディスク容量が 191GB→ 71GB と削減されていることがわかります。仮想サイズはどちらも200GBです。

なぜ最初から sparseにしてなかったのか。

virt-manager で作ったqcow2のディスクで、特に設定しないとsparseにならないので注意が必要でした。

virt-manager ってsparseにしないんですね。いまはSSDだし?メモリもいっぱいあるから再配置オーバーヘッドよりもSSDのディスク容量のほうが貴重だしなぁ。

qemu-img を使ってる

libvirt と qcow2 で使ったっ場合、virt-spasify は内部的に qemu-img が使われていて、/tmp に書き出されるので作業用の容量はある程度確保する必要がある。

参考資料

https://milestone-of-se.nesuke.com/sv-basic/linux-basic/resize-kvm-image-sparse-file/

http://libguestfs.org/virt-sparsify.1.html

2022-05-22

追記

2023-02-01

オプションについて追記。

iOS SafariのWeb Inspectorがmacで動かない

Mac から iOS iphone / iPadSafariにアクセスできない

iOSSafariで JS / CSS の動作を確認しながら、shortcut.app の ページ内javascript 実行を書いてたのですが。

どうも謎のjavascript エラーが出るので Macに接続して iPhone Safari を Web Inspector ( 開発ツール)で覗こうとしたのですが 出来ない。

MacSafariを開いても「開発」に、自分のiOSバイスが出現しない、空っぽで iphoneが表示されない。なんどもUSB抜き差ししても現れない。本来なら WiFi/Bluetooth でつないでさえあれば、近くのiOSバイスSafariデバッグツールはUSB接続していなくてもネットワーク経由で見えるはずなのだ。

対応

iOS 側でセキュリティ設定をリセット掛けると治る

iOS 一般 →  リセット → 位置情報とプライバシー

iOS とUSB 接続

信頼済みのコンピュータ登録し直し

その後 iphone をUSB接続し、iOSの信頼済みのコンピュータを再設定する。

私の場合はこれで解決しました。

理由

信頼済みのコンピュータがおかしなことになってたと思われる。

リセット掛けるしか無いですね。

注意点

iOS/iphone のプライバシー設定がリセットされるんので、アプリ毎にGPS利用許可、カメラ利用許可など、アプリを起動するたびに再度利用許可が求められることになった。

lxc 間の通信で ホスト名を使って直IPを避ける

LXC コンテナ間の通信でホスト名を使いたい。

LXC のコンテナ間の通信で、IPアドレスをいちいち調べるのがめんどくさい。

docker-compose に記載したホスト間なら、ホスト名でアクセスできるので、おなじことをLXCでやりたいなと思ったら。

調べたら→出来る

出来るじゃん!!!

ホスト名.lxc でアクセス

ping my-container-01.lxc

これで出来ることがわかる。

コンテナ間で、役割分担をするとき、とてもべんりである。

例えば、次のようなlxc コンテナが立ち上がっているときに

takuya@:~$ lxc list
+---------------+---------+----------------------+------+-----------+-----------+
|     NAME      |  STATE  |         IPV4         | IPV6 |   TYPE    | SNAPSHOTS |
+---------------+---------+----------------------+------+-----------+-----------+
| mycontainer   | RUNNING | 10.185.93.111 (eth0) |      | CONTAINER | 0         |
+---------------+---------+----------------------+------+-----------+-----------+
| nginx         | RUNNING | 10.185.93.112 (eth0) |      | CONTAINER | 0         |
+---------------+---------+----------------------+------+-----------+-----------+
ping nginx.lxc
ping mycontainer.lxc

と指定できるわけです。

iOS Safari で再生ができる h265 フォーマット

iOSSafariで hevc 再生してみよう。

とりあえず、ffmpeg でぱぱっと変換してみる。

普通に、libx265 にしたら出来ない。

ffmpeg -y -i ../video/sample.mp4  -vcodec libx265  -vf scale=720:-1 -acodec copy   libx265.mp4

これだけでは、再生ができない。

tag をつけたら出来る。

x265 で変換した動画に tag:v hvc1 を付加すると iOS Safari で再生できる動画になる。

ffmpeg -i libx265.mp4  -c:v copy -c:a copy -tag:v hvc1 libx265-tag.mp4

おおお、再生できるじゃん。高圧縮使えるじゃん!

h264 を、タグを付けて h265 に変換する

ffmpeg -y -i ../video/sample.mp4  -vcodec libx265  -vf scale=720:-1 -acodec copy -tag:v hvc1  libx265.mp4

これで、iOS Safariで再生できる動画ができあがる。TSの変換で活躍しそうですね。

結論

iOS Safariで再生するなら、保存しているmp4 を変換するならタグだけでいいっぽい

必ずしもHLSにしてストリーミングにする必要はなさそう。

ただし、chrome

macgoogle chrome だと再生できませんでした。調査が必要かと思われる。chrome は webm使ってことかねぇ。

google chrome 見れる→ 見れない
VLC では見れる? → 見れる
omxplayer で再生できるのだろうか → raspi で再生できるのかな?→ 未チェック

参考資料

https://qiita.com/khagi/items/4d731fbe4df91df68254

unboundによるDNSブロッキング

dns ブロッキングをunboundで実現する。

ともちゃ先輩が面白そうなことをやっていたので、ちょっと真似てみる。

とも ちゃ日記(Tomo cha) - 元大学生のOL日記-

ちまたで、kawangoが暴れているDNSブロッキングというネタがあり、元々実装を検討していたものについて、便乗してみました。 (略) 糞みたいな広告で通信料および、お金が擦り落とされるのが非常に腹正しく、何かする方法がないか考えていた。もちろん、部屋でゴロゴロとしてPCでネットを見ていても、広告があまりにもうざく、嫌気を指していたので、対処するべく実装に至った。 そのほか、 @kawango2525の頭の悪さに、こいつの関係するサイトもブロッキングする実装とした。

つまり、広告で余計なパケットを浪費させられるのは「意図しないプログラムの実行」なので止めていいよね。カワンゴもdnsで都合の悪いものは止めろと公言してるわけで、kawangoさんの会社のサービスもDNSで止めちゃえってこと。前からやってみようと思ってたけど、unbound入れるまともなOpenWRTルーターがなかったので延期にしていた。VPSDNSサービス立ち上げ選択肢もあったが、この場合一歩間違うとDNS amp の攻撃に使われちゃうし。x86 OpenWrt が無事に稼働しているし 設定をぶっ飛ばして初期化したのでついでに実装しておくことにした。*1

DNSによるブロッカーの仕組み

unboundの場合、次のようなホスト名の名前解決のルールを記入してあげると、該当のドメイン名は、ローカルに対する問合わせと処理され、「そのドメイン名にIPはなにもないぜ」という応答がクライアントに返されるようになる。

local-zone: "trafficgate.net." static

これは書式として次のようになっている。

# ゾーン=ローカル  " ドメイン名 + . "  static なにもなし
local-zone: "${domain_name}." static

この書式に従っってドメイン名を追記していけば、「なにもない」という応答を返せる。

書式が通りに実際に記入してためしてみて、実際に問い合わせた結果が空になることが確認できたら、ドメイン名を追加していけばいい。 ブロックしたいドメイン名の一覧をどこからか取得すればいいわけです。

ドメインリストがあれば、dns blocking をローカルでやることができる。

準備 unbound をいれる。

今回は、私は、openwrt に入れたルーターのunbound dnsを使って 実験することにしました。

opkg install unbound 

ubuntudebian なら

apt install unbound*

unboundの設定にサンプルを追加して試す。

わたしは、OpenWrt のunboundなので、次のようになっています。

unbound.conf

私の環境では、次のような include 関係になっています。include を重ねて管理していくのはどなたでも同じだと思います。

##
## 略
# 
include: /var/lib/unbound/unbound_srv.conf

unbound_srv.conf

include: /etc/unbound/280blocker-list.conf

280blocker-list.conf

## 適当なドメイン名で実在するものをテストで入れておく
local-zone: "trafficgate.net." static

設定を書いたら再起動してためします。

再起動

/etc/init.d/unbound restart
/etc/init.d/dnsmasq restart

わたしは、dnsmasq がフロント(0.0.0.0:53)で、実際に問い合わせる先にunbound(0.0.0.0:5300)を指定してるので両方を再起動しています。両方のキャッシュを削除し設定を反映させています。

確認

dig trafficgate.net @192.168.1.1
dig trafficgate.net @1.1.1.1

unbound(+dnsmasq)に問い合わせた結果と、public dns に問い合わせた結果が異なることを確認します。

無事にDNS問い合わせが、マスキングされて空っぽになっていたら、これでブロッキングに使えますね。

280blocker さんから ホスト名一覧を借りる。

ブロッキングしたいDNS一覧を探しておきます。

https://280blocker.net/files/280blocker_domain.txt

これを借りてきます。

curl -L https://280blocker.net/files/280blocker_domain.txt  \
 | sed -e "s/\r//"  \
 | grep -E '^[a-z0-9]'  \
 | awk '{print "local-zone: \""$1".\" static"}'  \
 | sort  | uniq

sed / awk / grep / sort /uniq をつかって整形します。

これで完成です。

定期的に更新出来るように、スクリプトにまとめておきます。

スクリプトに更新して再起動する手順を手っ取り早くまとめておいて、あとはcron に登録しておきました。280blockerさんによると、毎月1度の取得で十分だそうです。

unboundのdnsブロッキングリストを更新する。 · GitHub

#!/usr/bin/env sh

## @since 2020-05-15 
## @last 2021-01-05 
## @author takuya
## unbound にブロッキング
## ブロッキングするURLを定期的に更新する

function update_domain_lists(){
  update280blocker
  updateYoutubeAdblocker
}
function geneate_conf(){

  URL=$1
  OUTPUT=$2
  curl -sL $URL \
    | sed -e "s/\r//"   \
    | grep -E '^[a-z0-9]' \
    | awk '{print "local-zone: \""$1".\" static"}' \
    | sort \
    | uniq \
    > $OUTPUT
}

function checkHTTPStatusIs200(){
  URL=$1
  RET=$(curl -IL -s -o /dev/null -w '%{http_code}' $URL)

  [[ $RET == 200 ]];

}
function update280blocker () {

  URL=https://280blocker.net/files/280blocker_domain_$(date +%Y%m).txt
  ## mirror
  ## URL=https://raw.githubusercontent.com/junkurihara/280blocker_domain-mirror/master/280blocker_domain.txt
  OUTPUT=/etc/unbound/280blocker-list.conf
  if ! checkHTTPStatusIs200 $URL ; then
    echo failed;
    return 1
  fi
  ##
  geneate_conf $URL $OUTPUT
}

function updateYoutubeAdblocker () {

  URL=https://raw.githubusercontent.com/anudeepND/youtubeadsblacklist/master/domainlist.txt
  OUTPUT=/etc/unbound/youtube-ad.conf
  ##
  if ! checkHTTPStatusIs200 $URL ; then
    echo failed;
    return 1
  fi
  ##
  geneate_conf $URL $OUTPUT
}

function restart_unbund(){
  [ -e /etc/init.d/unbound ] &&
  /etc/init.d/unbound restart
}
function restart_dnsmasq(){
  [ -e /etc/init.d/dnsmasq ] &&
  /etc/init.d/dnsmasq restart 2>&1 > /dev/null
}
function main(){
  update_domain_lists &&
  restart_unbund &&
  restart_dnsmasq
}



main


DNSブロッキングってすごく強力

ためしてみてわかったのですが、DNSブロッキングは強烈に強力です。

DNSTLS化したりHTTPS化してコンテンツの書き換えを防止したいというセキュリティ上の欲求の要請がよくわかります。

強烈に強力なので、これを監視に使いたいという欲求もよくわかります。

インターネット・イコール・DNSと言っても過言ではないので、こんな強力すぎるものをkawango と政府に握られるのはとても恐ろしやと思いますね。中国怖いです。はい。

DNSだけは死守しないと死にますね。8.8.8.8 / google public dnsや 1.1.1.1 / cloudflare dns がコンテンツフィルタリングしないとも限らないので、ちゃんとroot . から問い合わせる unboundを自宅に一つ持っておくべきだと思います。安易な8.8.8.8、ダメゼッタイ。

関連資料

unboundでrootから引くdnsサーバを作り、DNSフィルタリングに備える - それマグで!
ついに牙を向いたPublic DNS - それマグで!
我々のDNS問い合わせは監視されている。 - それマグで!

参考資料

Adguard HomeでVPSに広告ブロックDNSを立てました | 280blocker

とも ちゃ日記(Tomo cha) - 元大学生のOL日記-

https://blog.unko.pro/adblock-by-resolver/

2021-01-05

280blocker さんに迷惑をかけないように書き直し。

*1: ローカルネットのdebian/ubuntuのサーバーで色々と試してたりしますが、実運用に使うにはPPPoE持ってるルータに入れないと回線断やら再起動やら常時起動を考えると別サーバー運用にするのは煩雑だし。DHCP割り振りも考えると、キャッシュDNSの仕組み上、ルーターに持たせるのが楽なんですよ。

仮想マシンのqemu - qcow2 のイメージに 変換する。(raw->qcow2, ova->qcow2)

VirtualBoxのイメージを変換する。

まぁそのままでも動くんだけど、管理を統一したいので qcow2 にする。 パフォーマンス云々はあるだろうけど。そこま気にしないことにする。

qemu コマンド

次のコマンドを使う。

qemu-img convert

ファイル名を指定する。

qemu-img convert -O qcow2 input.raw output.qcow2

拡張子は任意である。

実際の例

マイクロソフトが配布する MSEged 用のova イメージをqcow2 に変換しています。

takuya@:~$ qemu-img convert MSEdge\ -\ Win10.ova -O qcow2 MSEdge\ -\ Win10.qcow2

出来上がりを確認する。

takuya@:~$ qemu-img info MSEdge\ -\ Win10.qcow2
image: MSEdge - Win10.qcow2
file format: qcow2
virtual size: 6.8G (7255876608 bytes)
disk size: 6.8G
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: false
    refcount bits: 16
    corrupt: false
takuya@m75q-1:~$ qemu-img info MSEdge\ -\ Win10.ova
image: MSEdge - Win10.ova
file format: raw
virtual size: 6.8G (7255876608 bytes)
disk size: 6.8G

参考資料

https://www.randomhacks.co.uk/how-to-convert-virtualbox-vdi-to-kvm-qcow2/ https://medium.com/@lonardogio/convert-vdi-virtualbox-to-raw-in-windows-c96bded29640

shutdown コマンドについて調べました。

なんとなく使っているshutdown

Ubuntu デスクトップを使っていと、なんとなく、reboot だとか shutdown コマンドを打ち込んでるんですよね。

今すぐシャットダウン

shutdown -h now 

強制シャットダウンをわりと気軽に打ち込んでるんだけど、shutdown コマンドってたしかスケジュールできたよな。と思って調べました

今すぐシャットダウン

shutdown now

今すぐ、再起動

shutdown -r now

15分後にシャットダウン

showdown +15

60 分後に再起動

shutdown -r +60

13:33に再起動

shutdown -r 13:33

キャンセル

さっき再起動って言ったな、やっぱりなし

shutdown -c 

シャットダウンコマンドの他

シャットダウンのコマンドの他に似たような物がある。

halt
reboot 

などコマンドは多数あります。好きなのを使えばいいんだけど、じつは微妙に違うんだけど再起動・シャットダウンする目的であれば、あまり気にせず使える。

最後に起動したのって何時だっけ

uptime を見ればわかるのですが、uptimeの基準になる起動時間最後のshutdown -r を見ることが出来る。

takuya@~$ who -b
         system boot  2020-04-28 18:30

最近どれくらい reboot してるんだ

最近の再起動の履歴を見ることが出来ます。

takuya@:~$ last -x reboot
reboot   system boot  4.19.0-8-amd64   Fri Apr 24 05:13   still running
reboot   system boot  4.19.0-8-amd64   Wed Apr  8 03:15 - 05:12 (16+01:57)
reboot   system boot  4.19.0-8-amd64   Sat Apr  4 18:20 - 03:14 (3+08:54)
reboot   system boot  4.19.0-8-amd64   Thu Mar 26 16:22 - 18:20 (9+01:57)
reboot   system boot  4.19.0-8-amd64   Fri Feb 28 17:38 - 16:22 (26+22:43)
reboot   system boot  4.19.0-8-amd64   Fri Feb 28 17:30 - 17:37  (00:07)
reboot   system boot  4.9.0-11-amd64   Sun Feb  9 06:50 - 17:37 (19+10:46)
reboot   system boot  4.9.0-11-amd64   Sat Feb  8 23:22 - 17:37 (19+18:15)
reboot   system boot  4.9.0-11-amd64   Sat Feb  8 20:33 - 17:37 (19+21:04)
reboot   system boot  4.9.0-11-amd64   Sat Feb  8 18:35 - 17:37 (19+23:02)
reboot   system boot  4.9.0-11-amd64   Sat Feb  8 12:00 - 17:37 (20+05:37)
reboot   system boot  4.9.0-11-amd64   Sat Feb  8 07:22 - 17:37 (20+10:15)
reboot   system boot  4.9.0-11-amd64   Fri Feb  7 21:18 - 17:37 (20+20:19)
reboot   system boot  4.9.0-11-amd64   Fri Feb  7 18:55 - 17:37 (20+22:41)
reboot   system boot  4.9.0-11-amd64   Fri Feb  7 11:41 - 17:37 (21+05:56)

参考資料

apt で v6 を使わせない。IP v4 に限定して、aptを使う設定。

NTT の壊れた閉域IPv6

NTTの壊れたv6を使っていると、IPoEを設定しない限り、外向きの通信ができない。

v6の設定をあれこれ触っていたりすると、v6 で apt 出来たり出来なかったりするので、とたんに不便になる。 まじ困る。

apt がv6 フォールバック待ちで遅い。

ubuntu の apt だとIPv6 で通信できないときに自動的にv4 に切り替わる。でも遅いよね。何が起きてるんだってパニクるので、つながらんときははっきりつながらんほうが良い。

sysctl で ipv6 全般を禁止するのは流石に不便なので、それはしたくない。でもapt とかはv4 に限定して安心したい。

apt を IPv6 を禁止して IPv4 に限定する

apt の設定に、v4 強制の設定が追加されています。これを使うと解決します。

ipv4-only な apt にする。

echo 'Acquire::ForceIPv4 "true";' | sudo tee /etc/apt/apt.conf.d/99force-ipv4

rubyのプロセス起動で、smtpを使わずに、sendmail コマンドでメール送信するとカンタン

ubuntuシステムからメールを送りたい。

メールを送ろうとすると、SMTPをつかって、MIMEエンコードして SMTP over TLSで接続してとあれこれ手順が必要。

その手順をrubygemでインストールして使い方を調べるのも面倒。

ローカルの postfix にリレーさせる。

ubuntu とかサーバーで使ってるとローカルホストに exim4 や postfix くらいは用意していると思うんですよ。するとsendmail コマンドが使えるじゃないですか。

sendmail でメール送信する例。

$ sendmail takuya@example.com
Subject: Hi Hi

hello from test
.

ruby のプロセス open は標準入力を渡すのがとても楽。

ruby はIO周りと列挙周りだけは、本当にガチで便利ですよね。

シンプルなExim4と、シンプルなsendmail、そしてシンプルな ruby open。単純なものを組み合わせてしまう。

#!/usr/bin/env  ruby
#

open("|sendmail -i -t > /dev/null",'w'){|f|

  f.puts 'To:takuya@example.com'
  f.puts 'Subject: Hello from ruby '
  f.puts '  '
  f.puts '  '
  f.puts 'this is sample from ruby stdin'
  f.puts '  '
  f.puts ''
}

gem 何も要らない

gem のインストールの管理が面倒だったり、 bundler といえども、どこにgemを導入しているか GEM_HOMEのLOAD_PATHであれこれ考える必要もない。gem を外すと楽だった。

単純なことは単純にやるのが一番ですよね。

KISS / Keep it simple stupid が大事ですよ。ほんと。凝りだすときりがない。

ローカルホストにpostfix などMTAを導入する例

takuya-1st.hatenablog.jp

macOSに Linux の ip ( iproute ) コマンドを入れてしまうという邪教

mac でも ip / iproute2 コマンドを使いたい。

ついつい、癖で ip route show って打ち込んでしまうんですよ。

旧き良きBSDなんだし ifconfig / netstat を使えばいいんだけど、 netstat -nr って覚えにくいじゃないですか。

iproute のフリをするショートカット集が用意されている

ip コマンドを出来る限り、 mac 用コマンドにWrappingした代替用の関数群が用意されてる。

iproute2mac のインストール

これをいれれば、MacOSでも Linux / Ubuntu の ip コマンドが使える。完璧に一致することは不可能だけど、よく使うシンプルなものであれば問題なく使えそう。

takuya@Desktop$ uname
Darwin # ⇐ mac です
takuya@Desktop$ brew reinstall iproute2mac
==> Reinstalling iproute2mac
==> Downloading https://github.com/brona/iproute2mac/releases/download/v1.2.3/iproute2mac-1.2.3.tar.gz
Already downloaded: /Users/takuya/Library/Caches/Homebrew/downloads/fdb133eaa8f1346a259295ba9aa22ab568e0dd6b6506cafab6891ae6e31fcf84--iproute2mac-1.2.3.tar.gz
🍺  /usr/local/Cellar/iproute2mac/1.2.3: 6 files, 22.5KB, built in 3 seconds

ip コマンドが使えるぞ

takuya@Desktop$ ip a
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
    ether f0:18:
    inet 169.254.146.78/16 brd 169.254.255.255 en0

ip route show でルーティングが見れる。

takuya@Desktop$ ip route show
default via 192.168.1.1 dev en0
127.0.0.0/8 via 127.0.0.1 dev lo0
255.255.255.255/32 dev en0  scope link

ip route add も使えるので、ルーティングテーブルについては覚えることが減って楽になる。

公式にも書いてあるとおり、ちゃんと使う。

ただし、所詮は糖衣錠です。子供用のシロップ風邪薬です。なので、BSDのネットワークコマンドと、mac の networksetup コマンド、これらをちゃんと覚えたほうがいいことは間違いない。

For advanced usage use netstat, ifconfig, ndp, arp, route and networksetup directly.

デリケートでデディケートな詳細な操作は、 netstat / ifconfig / ndp / arp / route / networksetup の各種コマンドを使う。

ルートを追加したり削除する。ip を追加したり削除する程度なら 十分に動いていました。

参考資料

https://github.com/brona/iproute2mac

空白を含むパス名を含むコマンド文字列をシェル(bash)で処理する

" program files " のような空白を含むパス名を持ったコマンド全体を、変数に保持しててそれを実行したい時

そのままだと動かない。

## これが実行できない。
cmd='ls ~/Library/Application\ Support/'
$cmd

空白を含むパス名を入れたコマンドを文字列として、それを実行しようとするとエスケープの処理で頭を悩ますことになる。

eval を使う

cmd='ls ~/Library/Application\ Support/'
eval $cmd

または、sh 経由にする

cmd='ls ~/Library/Application\ Support/'
sh -c "$cmd":

参考資料

https://stackoverflow.com/questions/836334/executing-commands-containing-space-in-bash

qemu の仮想マシンのイメージのディスクサイズを変更する。

libvirtkvmでつかうqemu 用マシンのサイズを変更したい

通常のディスクであれば、ddしたイメージファイルのサイズを変えてあげれば済むのだけれど、qcow2 のイメージファイルはsparse ファイルになっています。

なので、仮想マシンから見えるディスクサイズと、実際のディスクサイズが異なります。

qcowのファイルの現在の情報をみる

qcow のファイルが実ファイルサイズと、仮想マシンからみたファイルサイズが異なるSPARSEファイルかどうか、それを確認するには次のようにします。

sudo qemu-img info  test.qcow

qcow のファイルのサイズを拡張する。

可変サイズのファイルを増やしていく時は、次のように、resize と増分を指定します。

qemu-img resize -f qcow2 test.qcow +10G

コマンドは次の通り

qemu-img resize -f タイプ  ファイル名  +増分サイズ

タイプは殆どの場合 qocw2 ですね。

ファイルサイズを縮小する。

逆に縮小するときは、--shrink オプションを付与します。

qemu-img resize --shrink  -f qcow2 test.qcow -1G

ただし、--shrink は削除していくので、データが有るとロストします。ディスクパーティションの後方から削除していくので、後方が空き領域になっている必要があります。gdisk / resize2fs や gpt GPated などで後方を開けてとかないと怖いですね。

実際にやってみる。

試しに、QCOW2 のファイルを作成してみます。

$ qemu-img create -f qcow2 test.qcow 1G
Formatting 'test.qcow', fmt=qcow2 size=1073741824 cluster_size=65536 lazy_refcounts=off refcount_bits=16

作成された仮想マシン用イメージのファイルの情報を確認します。

ホスト上の実ファイルのサイズは196Kで、仮想マシンのディスクとしてのサイズは1.0Gです。スパースファイルです。

$ sudo qemu-img info  test.qcow
image: test.qcow
file format: qcow2
virtual size: 1.0G (1073741824 bytes)
disk size: 196K
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: false
    refcount bits: 16
    corrupt: false

リサイズしてみます。+1Gしてサイズを増大させます。

$ qemu-img resize -f qcow2 test.qcow +1G
Image resized.

確認します。 ちゃんと、2GBになっていて、ホストから見たサイズは200Kになっていることがわかります。

$ qemu-img info  test.qcow
image: test.qcow
file format: qcow2
virtual size: 2.0G (2147483648 bytes)
disk size: 200K
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: false
    refcount bits: 16
    corrupt: false

libguestfs-tools を使う場合 / virt-resize

最近は、仮想マシンのサイズ変更については、いちいち仮想マシン内部で resize2fs や gdisk をしなくてもいいように virt-resize というツールが用意されていて、容易に仮想マシンのディスクイメージを操作できるようになっています。仮想マシン内部でパーティションがどう使われていようとも、ホスト側から操作することができます。LVM化されてても。

この後の作業

リサイズをしたあとに、resize2fs を掛けると思う。resize2fs を掛けるために仮想マシンを起動するのはナンセンスなので、nbd 経由でQcowを直接マウントしてresize2fsすると楽

qcow2をnbd経由で接続する

リサイズは容量不足で起きる→Sparseする

リサイズをするときは、殆どの場合で容量不足や無駄容量の節約である。

スパース(sprase file ) に変換して無駄容量を削減するのも一つの選択肢である

sparseにして容量削減・節約

参考資料

man qemu-img

関連資料

2022-09-04 追記

sparse / resize /nbd はペアになってないと意味がないので記述とリンクを追加

PostgresSQLの基本的な使い方(ユーザ作成・テーブル作成・確認)ー SQL編+psql で結果確認

目次

psqlPostgreSQLの基本的な操作

PostgreSQLの基本的な管理を見ていきます。

基本的な管理はSQLとして psql のプロンプトで行うものを取り扱います。

initdb や createdb dropuser のようなシェルコマンドは今回扱いません。

psql を使う前に。

インストール前に、日本語を扱う場合のポイント。

日本語環境が設定されて無いときは、日本語環境を作っておく。 時刻も日本JSTにしておく。

Debian / ubuntu の例

dpkg-reconfigure locales
dpkg-reconfigure tzdata

日本語環境の設定してからインストールするのが無難。

インストール ( debian )

sudo apt install postgersql  sudo 

psql の対話型シェルの起動

postgres ユーザーが作成されるので、最初の処理は postgresql ユーザーで行う。

root@:~# sudo -u postgres psql

ユーザーの管理。

ユーザーの管理を psql コマンドで行うことができます。postgresql user と role がありますが、歴史的経緯みたいなものだと思っていればいいです。

ユーザーは login role のエイリアスだったはず。

ユーザーの追加削除と確認

ユーザーの一覧は psql\du を使います。 du は display user とでも覚えときましょう。

実行サンプル

postgres ユーザー1つだけが存在します。

postgres=# \du
                                   List of roles
 Role name |                         Attributes                         | Member of
-----------+------------------------------------------------------------+-----------
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS | {}

ユーザーの追加。

ユーザーの追加は、 SQLCREATE USER を使えば可能です。

CREATE USER "takuya_1st" PASSWORD 'j0qViQjCzQMFfqH7';

シングルクォーテーション`ダブルクォーテーションに注意する!!PSQLは厳密に区別してる。

ユーザ追加サンプル

ユーザーを追加して、結果を確認。一つ増えるのがわかります。

postgres=# CREATE USER "takuya_1st" PASSWORD 'j0qViQjCzQMFfqH7';
postgres=# \du
takuya_1st  |                                                            | {}
 postgres               | Superuser, Create role, Create DB, Replication, Bypass RLS | {}

ユーザーを削除して、結果を確認。

ユーザーの削除は、 SQLDROP USER 文でできます。

DROP USER "takuya_1st" ;

ユーザー削除サンプル

ユーザーを削除して、ユーザー一覧から消えたことがわかります。

postgres=# DROP USER "takuya_1st" ;
postgres=# \du
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS | {}

パスワードの変更

パスワードの変更もSQLを使って可能です。

postgres=# ALTER USER postgres  WITH PASSWORD 'rHBrECDNjbWax1IZ';
ALTER ROLE

初期ユーザーの postgres のパスワードを変えてみるなど。

ROLEロール。create user と create role の違い。

postgresql では ユーザのことを role と呼びます。 LOGIN できるロールのことをユーザーと呼ぶ。と覚えてください。 歴史的経緯によるとでも思っておけばいいと思います。UNIXのユーザーようにPostgreSQLのユーザーはグループをもっていて、グループにロールで管理されています。1つのデータベースのインスタンスを多数のクライアントで共有していた名残りでしょう。個人でデータベースを作る、個人でプログラムから使うときなど、はあまり気にしなくていいと思います。

ロールの作成と確認

これは、create user と同じ

CREATE ROLE "outline_Admin" PASSWORD '01UNeD86gwVmRDRG';

データベースを作成する

日本語UTF-8に対応したテンプレートを作る。

シェル環境変数が LANG=ja_JP.UTF-8なら自動で作られるのだけど。作られていないとUTF-8でも行けそうなん。 気持ち悪いなら、日本語対応したテンプレートを作っておくといいかもしれない。

CREATE DATABASE template1 LC_COLLATE 'ja_JP.UTF-8' LC_CTYPE 'ja_JP.UTF-8' ENCODING 'UTF8' TEMPLATE template0;
CREATE DATABASE template2 LC_COLLATE 'ja_JP.UTF-8' LC_CTYPE 'ja_JP.UTF-8' ENCODING 'UTF8' TEMPLATE template0;
UPDATE pg_database SET datistemplate = true where datname = 'template2';

データベースの一覧

対話プロンプト psql のコマンドで \l でデータベースの一覧を見れます。 List database の L(エル)と覚えておけばいいでしょう。

postgres=# \l
                                  List of databases
   Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges
-----------+----------+----------+-------------+-------------+-----------------------
 postgres  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 template0 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres

ここで出てくる template は言語ごとのCollationが設定されたテンプレートです。debian/ubuntu の場合 LANG=ja_JP.UTF-8bashから apt install postgres すると postgres のaptインストールスクリプトで自動生成されます。

データベースの切替え

データベースを切り替えるにはつぎのように psql コマンド \c で可能です。

\c databae_name

これは、mysql の use DATABASENAME に相当する。

実行サンプル

切り替えたときのサンプル。プロンプトが変わるのでわかる。

postgres=# \c outline
You are now connected to database "outline" as user "postgres".
outline=# \q

データベースを作成。

SQLでデータベースを作成することができます。

CREATE DATABASE my_database;

データベースの作成サンプル

outline という名前でデータベースを作って一覧を見てみます。

postgres=# create database outline;
CREATE DATABASE
postgres=# \l
                                  List of databases
   Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges
-----------+----------+----------+-------------+-------------+-----------------------
 outline   | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 postgres  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 template0 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres

データベースを削除する

SQL 構文でデータベースを削除することができます。

DROP DATABASE my_database;

実行サンプル

outline という名前のデータベースを削除し、一覧を見てみます。

postgres=# drop database outline;
DROP DATABASE
postgres=# \l
                                  List of databases
   Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges
-----------+----------+----------+-------------+-------------+-----------------------
 postgres  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
template0 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres

オーナー指定してデータベースを作る

SQLでデータベースを作るときに所有者(オーナー)を指定して作ることができます。

CREATE DATABASE takuya_database  OWNER "takuya";

これは非常によく使います。

実行サンプル

ユーザーを作成し、続けてそのユーザーのデータベースを作成します。

postgres=# CREATE USER "outline_Admin" PASSWORD 'kj4zzkvVXuU7MlSL';
CREATE ROLE
postgres=# create database outline owner "outline_Admin";
CREATE DATABASE
postgres=# \l
                                         List of databases
   Name    |         Owner          | Encoding |   Collate   |    Ctype    |   Access privileges
-----------+------------------------+----------+-------------+-------------+-----------------------
 outline   | outline_Admin | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 postgres  | postgres               | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
template0 | postgres               | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |                        |          |             |             | postgres=CTc/postgres
 template1 | postgres               | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |                        |          |             |             | postgres=CTc/postgres

データベース作成時:文字コードを指定

文字コードを指定してつくると便利です。 テンプレートを使って作る事が多いです。

CREATE DATABASE outline  LC_COLLATE 'ja_JP.UTF-8' LC_CTYPE 'ja_JP.UTF-8' ENCODING 'UTF8' 
CREATE DATABASE outline  LC_COLLATE 'ja_JP.UTF-8' LC_CTYPE 'ja_JP.UTF-8' ENCODING 'UTF8' TEMPLATE template0;

template が en_US だし困ったなぁってときに、日本語でDBを作成しておくとトラブルが減る*1

実行サンプル

オーナー指定とテンプレート指定、文字コード指定を「全部合わせ」てデータベースを作成している例です。

CREATE DATABASE outline owner "outline_Admin"  LC_COLLATE 'ja_JP.UTF-8' LC_CTYPE 'ja_JP.UTF-8' ENCODING 'UTF8' TEMPLATE template0;

postgres=# \l
                                         List of databases
   Name    |         Owner          | Encoding |   Collate   |    Ctype    |   Access privileges
-----------+------------------------+----------+-------------+-------------+-----------------------
 outline   | outline_Admin | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8 |
 postgres  | postgres               | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 repost    | repost                 | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 template0 | postgres               | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |                        |          |             |             | postgres=CTc/postgres
 template1 | postgres               | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |                        |          |             |             | postgres=CTc/postgres
(5 rows)

おさらい psql コマンド

データベースの切り替え

postgres=#  \c outline
### データベースの一覧
postgres=#  \l
### ユーザー一覧
postgres=# \du

おさらい SQL での管理。

# ユーザー作成
 CREATE USER "takuya_1st" PASSWORD 'j0qViQjCzQMFfqH7';

## パスワード変更
ALTER USER postgres  WITH PASSWORD 'rHBrECDNjbWax1IZ';

# データベース作成
CREATE DATABASE takuya_database ;
CREATE DATABASE takuya_database  OWNER "takuya";
CREATE DATABASE outline  owner "takuya" LC_COLLATE 'ja_JP.UTF-8' LC_CTYPE 'ja_JP.UTF-8' ENCODING 'UTF8' 

2020-07-19

更新

*1: 個人の感想です。