LoginSignup
7
1

More than 3 years have passed since last update.

ディスク情報を取得するコマンドを試作してみました

Last updated at Posted at 2019-12-08

この投稿は「さくらインターネット Advent Calendar 2019」の9日目の記事です。

概要

  • ディスク情報を取得するコマンドを Go 言語で実装してみました。
  • さくらのクラウドで試してみます。
  • コマンドの仕様について説明します。

動機について

普段 Go 言語をメインで使っているので、Go 製のライブラリやツールなどをよく検索しています。
そんな中、Go 言語で実装されたハードウェア情報を取得するツール ghw を見つけたのですが、ghw をはじめ、udevadm infoutil-linuxfindmnt などがどのようにディスク情報を取得しているのかが気になり、学習がてら実装してみました。

ディスク情報を取得する試作コマンドについて

以下がリポジトリとなります。

なお、本コマンドを実行するには、大雑把に言いますと、Linux であり、systemd が使われており、コンテナではない環境が必要になります。
ここでは例としてさくらのクラウドの Ubuntu 18.04 を利用してみます。

さくらのクラウドのサーバで試す手順について

ご紹介したい機能がありますので、シンプルモードではない方法で説明します。
サーバの追加画面から、右上の「シンプルモード」のチェックを外します。

simple.png

サーバの詳細な作成画面から、仮想コアやメモリや OS などを埋めた上で「ディスクの修正」の項目まで進みます。
「github.comから取得」を設定すると、指定したアカウントの公開鍵があらかじめサーバに設定されます。

add_server.png

非常に便利ですので、ぜひご利用ください。

サーバ作成後、ssh でログインもしくはコントロールパネルの「コンソール」のタブから作業をしてみることとします。
「コンソール」のタブから作業する場合は、以下の位置になります。

console.png

コマンドのインストール方法について

こちらの 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 なパスを入れています。
  • sysuevent, 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_dataudevadm 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日目の記事でした。

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1