この投稿は「さくらインターネット Advent Calendar 2019」の9日目の記事です。
概要
- ディスク情報を取得するコマンドを Go 言語で実装してみました。
- さくらのクラウドで試してみます。
- コマンドの仕様について説明します。
動機について
普段 Go 言語をメインで使っているので、Go 製のライブラリやツールなどをよく検索しています。
そんな中、Go 言語で実装されたハードウェア情報を取得するツール ghw を見つけたのですが、ghw をはじめ、udevadm info
や util-linux の findmnt
などがどのようにディスク情報を取得しているのかが気になり、学習がてら実装してみました。
ディスク情報を取得する試作コマンドについて
以下がリポジトリとなります。
なお、本コマンドを実行するには、大雑把に言いますと、Linux であり、systemd が使われており、コンテナではない環境が必要になります。
ここでは例としてさくらのクラウドの Ubuntu 18.04 を利用してみます。
さくらのクラウドのサーバで試す手順について
ご紹介したい機能がありますので、シンプルモードではない方法で説明します。
サーバの追加画面から、右上の「シンプルモード」のチェックを外します。
サーバの詳細な作成画面から、仮想コアやメモリや OS などを埋めた上で「ディスクの修正」の項目まで進みます。
「github.comから取得」を設定すると、指定したアカウントの公開鍵があらかじめサーバに設定されます。
非常に便利ですので、ぜひご利用ください。
サーバ作成後、ssh でログインもしくはコントロールパネルの「コンソール」のタブから作業をしてみることとします。
「コンソール」のタブから作業する場合は、以下の位置になります。
コマンドのインストール方法について
こちらの README.md にも記載していますが、
$ wget https://github.com/blp1526/blkinfo/releases/latest/download/blkinfo_linux_x86_64.tar.gz
$ tar zxvf blkinfo_linux_x86_64.tar.gz
を実行し、コマンドをインストールしてから、
$ ./blkinfo /dev/vda3
を実行してみると、若干の差異はあると思いますが、以下のようなディスク情報が JSON で取得できると思います。
なお、Ubuntu 18.04 のパブリックアーカイブでない場合には /dev/vda3
は存在しないかもしれませんので、別のパスを指定してみてください。
{
"path": "/dev/vda3",
"resolved_path": "/dev/vda3",
"parent_path": "/dev/vda",
"child_paths": [],
"sys_path": "/sys/block/vda/vda3",
"resolved_sys_path": "/sys/devices/pci0000:00/0000:00:05.0/virtio2/block/vda/vda3",
"sys": {
"uevent": [
"MAJOR=252",
"MINOR=3",
"DEVNAME=vda3",
"DEVTYPE=partition",
"PARTN=3"
],
"slaves": [],
"holders": []
},
"major_minor": "252:3",
"udev_data_path": "/run/udev/data/b252:3",
"udev_data": [
"S:disk/by-uuid/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"S:disk/by-partuuid/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"S:disk/by-path/virtio-pci-0000:00:05.0-part3",
"S:disk/by-path/pci-0000:00:05.0-part3",
"W:4",
"I:1583813",
"E:ID_SCSI=1",
"E:ID_PART_TABLE_TYPE=gpt",
"E:ID_PART_TABLE_UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"E:ID_PATH=pci-0000:00:05.0",
"E:ID_PATH_TAG=pci-0000_00_05_0",
"E:ID_FS_UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"E:ID_FS_UUID_ENC=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"E:ID_FS_VERSION=1.0",
"E:ID_FS_TYPE=ext4",
"E:ID_FS_USAGE=filesystem",
"E:ID_PART_ENTRY_SCHEME=gpt",
"E:ID_PART_ENTRY_UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"E:ID_PART_ENTRY_TYPE=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"E:ID_PART_ENTRY_NUMBER=3",
"E:ID_PART_ENTRY_OFFSET=8392704",
"E:ID_PART_ENTRY_SIZE=33548288",
"E:ID_PART_ENTRY_DISK=252:0",
"E:net.ifnames=0",
"G:systemd"
],
"mount_info_path": "/proc/self/mountinfo",
"mount_info": {
"mount_id": "28",
"parent_id": "0",
"major_minor": "252:3",
"root": "/",
"mount_point": "/",
"mount_options": [
"rw",
"relatime"
],
"optional_fields": [
"shared:1"
],
"filesystem_type": "ext4",
"mount_source": "/dev/vda3",
"super_options": [
"rw",
"errors=remount-ro",
"data=ordered"
]
},
"os_release_path": "/etc/os-release",
"os_release": {
"BUG_REPORT_URL": "https://bugs.launchpad.net/ubuntu/",
"HOME_URL": "https://www.ubuntu.com/",
"ID": "ubuntu",
"ID_LIKE": "debian",
"NAME": "Ubuntu",
"PRETTY_NAME": "Ubuntu 18.04.3 LTS",
"PRIVACY_POLICY_URL": "https://www.ubuntu.com/legal/terms-and-policies/privacy-policy",
"SUPPORT_URL": "https://help.ubuntu.com/",
"UBUNTU_CODENAME": "bionic",
"VERSION": "18.04.3 LTS (Bionic Beaver)",
"VERSION_CODENAME": "bionic",
"VERSION_ID": "18.04"
}
}
自作コマンドの仕様について
出力されたフィールドについて説明します。
-
path
- コマンドの引数として与えたパスを入れています。
-
resolved_path
-
path
がシンボリックリンクだった場合 resolved なパスを入れています。- 例えば、
path
として/dev/disk/by-uuid/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
あたりのパスを指定したとすると、そのパスの resolved なパスが入ることになります。
- 例えば、
-
-
sys_path
,parent_path
,child_paths
-
sys_path
は/sys
配下のディレクトリから、指定したディスクの情報を取得できるパスを入れています。 -
parent_path
,child_paths
は、sys_path
から見て、親階層、子階層のブロックデバイスを入れています。
-
-
resolved_sys_path
-
sys_path
はシンボリックリンクのため、そのパスの resolved なパスを入れています。
-
-
sys
のuevent
,slaves
,holders
-
sys_path
ディレクトリのuevent
ファイルの中身と、slaves
,holders
ディレクトリに存在するファイルの情報となります。 -
slaves
,holders
は LVM の OS をブートしたときに存在するようです。さくらのクラウドを利用して検証する場合には、ISO イメージからサーバを作成し、パーティションの作成時に LVM を指定するとよさそうです。- LVM の OS だった場合のサンプルを https://godoc.org/github.com/blp1526/blkinfo#Sys にコメントとして残してあります。
-
-
major_minor
- デバイスのメジャー番号とマイナー番号をコロンで結合したものを入れています。デバイスのメジャー番号とマイナー番号は、(たとえば)
lsblk
コマンドで表示でき、cat /proc/devices
で一覧を確認できる番号となります。
- デバイスのメジャー番号とマイナー番号をコロンで結合したものを入れています。デバイスのメジャー番号とマイナー番号は、(たとえば)
-
udev_data_path
,udev_data
-
udev_data
はudevadm info /dev/vda3
などで取得できる情報を入れています。udev_data_path
から取得できるものです。-
udevadm info
がどこから情報を取得しているのかman
などからわからなかったため、strace udevadm info /dev/vda3
でファイルを開いている場所を探し、当たりをつけました。 - ソースコードはこのあたりでしょうか...
-
-
-
mount_info_path
,mount_info
-
findmnt
コマンドで取得できる情報が欲しくて追加したフィールドです。path
で指定したブロックデバイスがマウントされているのであれば、値を入れるようにしています。 -
findmnt
コマンドについてはman 8 findmnt
で/proc/self/mountinfo
を参照していることがわかりました。 - ただ、
/proc/self/mountinfo
で表示される各項目が何を表しているのか不明でしたので、調査したものをコメントとして https://godoc.org/github.com/blp1526/blkinfo#MountInfo に残してあります。
-
-
os_release_path
,os_release
-
マウントポイント + /etc/os-release
から取得できるos-release
の情報を入れています。-
マウントポイント + /etc/os-release
という実装にしたので、たとえば Ubuntu サーバ内の/mnt
に CentOS のディスクをマウントしていた場合、その CentOS のブロックデバイスのパスをコマンドの引数として指定すれば、(Ubuntu ではなく)CentOS の/etc/os-release
の情報が取得できます。
-
-
まとめ
コンテナ上では /dev
配下などの問題でこのコマンドは実行できず、 さくらのクラウドという IaaS で検証できるものとして、この記事を書いてみました。
以上、「さくらインターネット Advent Calendar 2019」の9日目の記事でした。