OpenWrt でMACアドレスとホスト名が記された ethers データベースを、 Prometheus Node Exporter のメトリクスという形で晒すコレクタプローブを lua 言語で作成してみました。
OpenWrtのethersデータベースとPrometheus Exporter
以前、OpenWrtにPrometheus Node Exporterを導入した際に、ディスク情報を表示させるのにコレクタプローブファイルを決められたフォルダへ( /usr/lib/lua/prometheus-collectors/ )、追加したことがありました。
ここへ自作のコレクタプローブを配置すれば、欲しい情報をメトリクスという形で晒せるようになるのではないか、というのが今回の試みで、実際に晒したい情報は、MACアドレスとホスト名が記されたehtersデータベースです。
自身がDHCPサーバではないOpenWrt WiFi APで、接続中クライアントのホスト名が分からず名無しさんになってしまう問題を解決すべく、DHCPサーバを担う別のOpenWrtルータからMACアドレスとホスト名が記された、ethersデータベースファイルの提供を受ける仕組みを以前、構築したのですが、その内容をGUIベースで閲覧する手段が未だ無いのが難点。ethersデータベースの内容をPrometheus Node Exporterのメトリクスで公開できれば、参照手段の幅は広がります。
Ubuntu環境へのLua導入
稼働中のルータ上でコーディングするのは最小限で済ませたいので、別途Ubuntu PCへLuaをインストールし、開発環境とします。
まず、OpenWrtルータの中で使われているLuaのバージョンを確認、少し古めのv5.1.5が使われていました。
|
1 2 3 4 5 6 7 8 9 10 11 12 |
_______ ________ __ | |.-----.-----.-----.| | | |.----.| |_ | - || _ | -__| || | | || _|| _| |_______|| __|_____|__|__||________||__| |____| |__| W I R E L E S S F R E E D O M ----------------------------------------------------- OpenWrt 22.03.3, r20028-43d71ad93e ----------------------------------------------------- root@vWrt:~# uname -a Linux vWrt 5.10.161 #0 SMP Tue Jan 3 00:24:21 2023 x86_64 GNU/Linux root@vWrt:~# lua -v Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio (double int32) |
このバージョンと同等のLuaパッケージを、開発環境に見立てたUbuntu PCへインストール。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
uname -a Linux a1502u 5.15.0-127-generic #137-Ubuntu SMP Fri Nov 8 15:21:01 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux user@a1502u:~$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.5 LTS Release: 22.04 Codename: jammy user@a1502u:~$apt list -a lua5.1 lua5.1/jammy 5.1.5-8.1build4 amd64 user@a1502u:~$ sudo apt install lua5.1 以下のパッケージが新たにインストールされます: lua5.1 アップグレード: 0 個、新規インストール: 1 個、削除: 0 個、保留: 0 個。 user@a1502u:~$lua -v Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio |
Luaにおけるタブ区切り文字列分割
/etc/ethers データベースファイルの中身は、次のようにMACアドレスとホスト名が一行にタブ区切りされた書式になっています。
|
1 2 3 4 5 |
7c:10:c9:##:##:## ZS672KS 86:1e:0e:##:##:## iPhone13mini 24:0a:c4:##:##:## ESP32Cam4C 60:01:94:##:##:## ESP01EasyA2 5c:cf:7f:##:##:## ESPMatrix82 |
これを一行ずつ読み込んで分割したいのですが、生憎とLuaには split 内部関数はありません。調べてみると、 string.gmatch 関数を使ったこちらの例を見つけました。
今回、これを有り難くほぼそのまま拝借して、 split 関数を作成しました。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
local function split(inputstr, sep) if sep == nil then sep = "%s" end local t = {} for str in string.gmatch(inputstr, "([^"..sep.."]+)") do table.insert(t, str) end return t end line = "7c:10:c9:##:##:## ZS672KS" h = split(line, "\t") print("MAC: " .. h[1]) print("Name: " .. h[2]) |
実行結果は次の通り、MACアドレスとホスト名が1行にタブ分割されたethersデータベースの1エントリを、要素毎に分割できました。
|
1 2 3 |
~$ lua ./split.lua MAC: 7c:10:c9:##:##:## Name: ZS672KS |
ethers_database.luaの作成
ここからはPrometheus Node Exporterが導入済のOpenWrtルータへ移り、コレクタプローブが収録されている /usr/lib/lua/prometheus-collectors/ に次のファイルを新規作成します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
local function split(inputstr, sep) if sep == nil then sep = "%s" end local t = {} for str in string.gmatch(inputstr, "([^"..sep.."]+)") do table.insert(t, str) end return t end local function scrape() ethersfile = io.open("/etc/ethers", "r") local metric_ethers_database = metric("ethers_database", "gauge") local metric_ethers_count = metric("ethers_count", "counter") local count = 0 for line in ethersfile:lines() do if line:sub(1, 1) ~= "#" then h = split(line, "\t") labels = {mac=string.upper(h[1]), name=h[2]} metric_ethers_database(labels, 1) count = count + 1 end end metric_ethers_count({name="total"}, count) ethersfile:close() end return { scrape = scrape } |
作成したファイルに実行権限を付与したら、サービスを再起動させて反映。
|
1 2 3 4 |
root@vWrt:~# chmod +x /usr/lib/lua/prometheus-collectors/dhcp_lease.lua root@vWrt:~# /etc/init.d/prometheus-node-exporter-lua restart root@vWrt:~# /etc/init.d/prometheus-node-exporter-lua status running |
他のプローブを参考に、見よう見真似で初めてLua言語で組んだスクリプトですが、なんとか期待通りに動いてくれました。
副産物)dhcp_lease.luaの作成
以前の記事でも少し触れたDHCPサーバのリースファイル、 /tmp/dhcp.lease も似たようなテキストファイルで、リース期限やMACアドレス、ホスト名の他にIPアドレスがあるのが情報として特色。
|
1 2 3 |
1736747241 70:5f:a3:##:##:## 192.168.51.153 Xiaomi-11T-Pro * 1736743887 00:15:18:##:##:## 192.168.51.205 UBOXPROSPW * 1736746554 80:56:f2:##:##:## 192.168.51.201 BRAVIA800 * |
せっかくなので、このリースファイルからMACアドレス、IPアドレス、ホスト名を出力するプローブも作ってみました。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
local function split(inputstr, sep) if sep == nil then sep = "%s" end local t = {} for str in string.gmatch(inputstr, "([^"..sep.."]+)") do table.insert(t, str) end return t end local function scrape() lease = io.open("/tmp/dhcp.leases", "r") local metric_dhcp_host_leasing = metric("dhcp_host_leasing", "gauge") local metric_dhcp_host_leasing_count = metric("dhcp_host_leasing_count", "counter") local count = 0 for line in lease:lines() do h = split(line, " ") labels = {utime=h[1], mac=string.upper(h[2]), ip=h[3], name=h[4]} metric_dhcp_host_leasing(labels, 1) count = count + 1 end metric_dhcp_host_leasing_count({name="total"}, count) lease:close() end return { scrape = scrape } |
ブラウザでメトリクスを確認、利用法は追々考えましょう。
実はこれ、わざわざ自作せずとも、prometheus-node-exporter-lua-uci_dhcp_hostパッケージという、全く同じ方法を晒すプローブコレクタが用意されていました。
こちらのスクリプトは uci コマンドを通じて、エレガントに同等の情報を得ているようです。







