Zabbix で KEA DHCP のアドレスの払い出し状況を監視する
環境
ubuntu 18.04
Zabbix 4.4
mariadb 15.1
KEAが動いているサーバで下記コマンドを実行すると, データベースにアクセスしてvlan 10についての払い出しているIPの数がわかる
$ mysql -u {myuser} -p{mypassword} -n kea -e "select count(subnet_id) from lease4 where subnet_id = 10;" | sed -n 2p
これをZabbix agentのリモートコマンドを設定して取得する。
zabbix_agent2.conf
### Option: Plugins.SystemRun.EnableRemoteCommands
# Whether remote commands from Zabbix server are allowed.
# 0 - not allowed
# 1 - allowed
#
# Mandatory: no
# Default:
# Plugins.SystemRun.EnableRemoteCommands=0 <- ここを1にしてコメントアウトを外す
設定を読み込むために再起動する
$ sudo systemctl restart zabbix-agent2
次にZabbix server のWeb画面にてアイテムを登録する
キーはsystem.runを用いる
commandにIP数を取得するコマンドを記入する
Zabbix4.4 webhook 連携
久しぶりにZabbixを構築する機会があったので, Zabbix4.4を使ってみました。
なんと通知方法にwebhookが選択できるようになってたんです!
これでスクリプトをディレクトリに下に置いてみたいなことをしなくてもzabbix内で完結することができるようになりました。
https://www.zabbix.com/documentation/current/manual/config/notifications/media/webhook
公式サイトにあるものをコピペすれば, actionにある通りのものがslackへ通知されるんですが, メッセージが届くだけで通知としてわかりずらく記事もあまりなかったのでめもしとこって感じです。
参考サイト
https://blog.apar.jp/zabbix/13116/
通知の設定の仕方は参考サイトのとおりです。
ここから少し通知わかりやすくする手順です。
用意したパラメータとコードです。
params = JSON.parse(value) var req = new CurlHttpRequest(); req.AddHeader('Content-Type: application/x-www-form-urlencoded'); Zabbix.Log(4, 'webhook request value='+value); attachments = [] if (params.subject.indexOf("Resolved:") === 0) { attachments.push({ "color": "#00FF00", "blocks": [ {"type": "section","text": {"type": "mrkdwn","text": "*Resolved:*"}},{"type": "divider"},{"type": "section", "text": {"type": "mrkdwn", "text": params.text}} ]}); } else { attachments.push({ "color": "#FF0000", "blocks": [ {"type": "section","text": {"type": "mrkdwn","text": "*Problem:*"}},{"type": "divider"},{"type": "section", "text": {"type": "mrkdwn", "text": params.text}} ]}); } payload={} payload.text = "" payload.blocks = [] payload.attachments = attachments req.Post( 'https://hooks.slack.com/services/********************************', 'payload='+JSON.stringify(payload) ); Zabbix.Log(4, 'response code: '+req.Status()); return JSON.stringify({ 'tags': { 'endpoint': 'slack' } });
ちゃんと綺麗に書くべきなんですが, とりあえずで(笑)
ALERT.SUBJECTを条件に分岐させて, バーの色を変えて視覚的にアラートか復帰かを判断できるようにしました。
色でわかるようにしてもメッセージでアラートか復帰かがわかりずらかったので, SUBJECTを切り取って頭に持っていきました。
下の写真がテストをした時のものになります。(設定間違っててProblemが緑になってます...)
実際のalert だとアラートメッセージが表示されます。
基本的にはSlack の blocks 芸なので凝ろうと思うとどこまでもやってしまいそうです(笑)
このサイトを頼りに整合性を取りながら作ってました
golang 2次元スライス
よくスライスの作り方を忘れてしまうのでメモメモ
空の2次元スライス
var s2 [][]int // or s2 := [][]int{} //後ろの{} 忘れ注意
確認
fmt.Println(s2) # => [] ftm.Println(reflect(s2)) # => [][]int
出力は空のスライスに見えるが、型はちゃんと2次元になっている
スライスの要素追加は append を使用する
s := []int{1, 2, 3} s2 = append(s2, s) fmt.Println(s2) # => [ [1 2 3] ] fmt.Println(s2[0]) # => [1 2 3] fmt.Println(s2[0][0]) # => 1
FRRouting で routing できる環境を Docker で作ろうとしたお話
FRRouting なるものの存在を知ってしまい, 動かしてみたくなったのがきっかけです
Quagga から fork して開発してるらしいです
私はこれを見たときめんどくさそう...ってのが第一感想でした
Docker ないかな...って探したら普通にありましたね. こちら
とりあえずこの通りにDocker For Mac で動かしてみました
問題なく動いたんですが, nic が Mac の nic をそのまま認識していて????
どうやら, Docker の --net オプションで host を指定するとどうやら HostOS の nic をそのまま使うらしい
つまり, ubuntu の上にそのまま動かせば良さそう
今回考えた構成は, ubuntu の Docker の上に frr の Docker を動かしてやろうという頭の悪いことします
Q. そもそも Docker の上で Dcoker が動くのか?
A. できそう. dind (Docker in Docker) とか Docker マトリョーシカとか前例あり
docker run に --privileged オプションをつければできる. 参考
実際に Docker For Mac で ubuntu Docker に dind で frr 動きました.
あとは docker の nic が増やせれば問題なさそうですね
今回 Docker の nic を増やすのには, Open VSwitch を使うことにしました.
理由は Docker に対して, OVS を使ってるケースを見かけるのと, OVS 触ったことないからってだけです. 参考
ほんとはこの参考サイトをもとに構成しようと思ったのですが, ubuntu in frr の dind が容量を取るため, ルータは2つだけで検証
とりあえず, OVS を使うために, VituralBox で ubuntu を立ち上げる.
ubuntu に入って, OVS を install
$ sudo apt install openvswitch-switch
bridge を作成
$ sudo ovs-vsctl add-br switch1
次に Docker を install
こちらの記事通りの手順で問題なく動きます
Docker で ubuntu のコンテナを作ります
$ sudo docker run -t -d --privileged --name router1 ubuntu:18.04 $ sudo docker run -t -d --privileged --name router2 ubuntu:18.04
次に 立ち上げた router コンテナ を OVS で繋いでいく
$ sudo ovs-docker add-port switch1 eth1 router1 --ipaddress=10.0.1.1/24 $ sudo ovs-docker add-port switch1 eth1 router2 --ipaddress=10.0.1.2/24
これで, 各コンテナに eth1 が生えました
疎通の確認も取れました
$ sudo docker exec -it router1 ping -c 2 10.0.1.2 PING 10.0.1.2 (10.0.1.2) 56(84) bytes of data. 64 bytes from 10.0.1.2: icmp_seq=1 ttl=64 time=0.373 ms 64 bytes from 10.0.1.2: icmp_seq=2 ttl=64 time=0.067 ms --- 10.0.1.2 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1035ms rtt min/avg/max/mdev = 0.067/0.220/0.373/0.153 ms
ここで何回も OVS の設定をやり直していると, VM の ubnutu にゴミの nic が大量にできてしまい通信がうまく行かなくて悩まされてました
VM 再起動でゴミは全部消しました
さらにここから, ubuntu docker に frr docker を乗せていきます. まずはコンテナ内へ
$ sudo docker exec -it router1 /bin/bash
ubuntu で docker を入れる手順は上記と同じです. frr を落としてきます
# docker pull cumulusnetworks/frrouting # docker run -t -d --net=host --privileged --name frr cumulusnetworks/frrouting:latest
ここで問題が発生しまして
# docker run -t -d --net=host --privileged --name frr cumulusnetworks/frrouting:latest Unable to find image 'cumulusnetworks/frrouting:latest' locally latest: Pulling from cumulusnetworks/frrouting d54efb8db41d: Pull complete f8b845f45a87: Pull complete e8db7bf7c39f: Pull complete 9654c40e9079: Pull complete 6d9ef359eaaa: Pull complete 4a732078a2f1: Pull complete 4f7cbc8d602e: Pull complete 13725b9e5347: Pull complete 37b1b30cb517: Pull complete 1549dc55e52f: Pull complete daac6794bfc5: Pull complete ab5b5e4985df: Pull complete d017e3cc4bac: Pull complete 0587bcefe519: Pull complete Digest: sha256:8049446ceee0c4a2bc9ee29965c2b14cead85f944fddaaba0d4477e7611772e0 Status: Downloaded newer image for cumulusnetworks/frrouting:latest docker: Error response from daemon: error creating aufs mount to /var/lib/docker/aufs/mnt/a45f20517fb6460ff82bec1811f90f55a607a0d4abb0a6f6b328f19f33151992-init: invalid argument.
Docker For Mac でやったときはなんの問題もなくコンテナを動かせたのにエラーが出ました
とりあえず docker info で 目diff で違いを探した結果 Storage Driver に違いがありました
Mac では vfs, ubuntu docker では aufs
エラーの内容的にもここを変更すればなんかいけそう
てなわけで変更します. 参考
storage driver の違いはちゃんと見てないので把握してませんが, vfs にします
# service docker stop // まず docker を止める # dockerd --storage-driver=vfs & //裏で動かす. そうするとDriver が vfs に変わっている # docker run -t -d --net=host --privileged --name frr cumulusnetworks/frrouting:latest
これで通るようになります. 実際にコンテナが作成されていることが確認できます
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d7657055e400 cumulusnetworks/frrouting:latest "/usr/lib/frr/start.…" 5 hours ago Up 5 hours frr
これで後は frr でループバックアドレス設定して, ospf 設定したら router1 と router2 で lo に対して ping が通りました
ルーティングのところはまた今度...
ルータ2つ brige 1つで容量は12G くらい
なんとなくVirtual Box を何個も立てずに Docker でできないかなって意地になってやりましたが, VM に frr コンテナを立てた方が楽ですね(容量的にも)
今回はこんな頭の悪いことしましたが, docker ネットワークについてちょっと詳しくなれたなって感じです
やはり手を動かさないとわからないことってあるなって思いました
IDE の vim のキーバインド使うとき
普段は vim を使ってるんですが, アプリケーション作るのにフレームワーク使う時はなんとなく IDE を使います.
いつも IDE を使う時に vim のキーバインドにするか, デフォルトのまま使うかで迷ってました.
ただ, 最近は選択肢が増えてるだけだしまぁいいかって vim のキーバインドでやってます.
IDE 使うと()が保管されたりして, )の向こうにカーソルを持って行きたいけど, Insert モード抜けるのめんどくさいなって思ったのが今回の記事の発端です.
vim 使ってるんだから, 普通に抜けたらよくない?とも思うんですが, めんどくさいなと思ってしまうときもあるんですね...
- Insert モード時に control + o で1操作だけ Insert モードを抜けられる
この方法だと, デフォルトの機能で)一つ分は問題ないですね
- .ideavimrc に insert モード時のキーバインドを設定する
~/の配下に .ideavimrc を作成するとideでの vim の設定ができる
.idevimrc を読み込んで, IDE を再起動すればok
そうすると Insert モード中でも デフォルトのキーバインドで上下左右に移動することができる
imap <C-p>imap <C-n> imap <C-b> imap <C-f>
こうまでして使う必要があるのかって言われるとう〜んって気もしますが, 選択肢の1つとしてあるのはいいんじゃないですかね
golangのinterface{}の不思議
golangを触り始めて約3ヶ月
interface{}が便利なのでよく使います
ただ最初はinterface{}の挙動がよくわかってなくて使うたびに苦戦してたのでメモメモ_φ(・_・
package main import( "fmt" ) func main() { Output("string") Output(100) Output(true) } func Output(x interface{}) { fmt.Println(x) } => string 100 true
特に型を宣言しなくてもなんでもこーい!なことができる
すごい便利
ただ, もし受け取った関数で型がしっかりと指定しないとダメなケースがある
大体がこのパターン, だから便利だけとメンドくささもある
例えば次のような場合
package main import( "fmt" ) func main() { Output(100) } func Output(x interface{}) { fmt.Println(x*2) } => # command-line-arguments ./test.go:12:16: invalid operation: x * 2 (mismatched types interface {} and int)
interface{}型とint型では計算できませんよって怒られます
なんでも受け取ってくれるのに実は繊細なのかなって感じです
解決作
package main import( "fmt" ) func main() { Output(100) } func Output(x interface{}) { fmt.Println(x.(int)*2) } => 200
変数の後ろにx.(int)と, interface{}型で受け取ったけど, この子はint型ですよーって書いてあげれば大丈夫
主にswitchを使って分岐処理をさせることが多いです
package main import( "fmt" ) func main() { Output("aaaaaaa") Output(100) Output([]string{"a", "b", "c"}) } func Output(x interface{}) { switch v := x.(type) { case string: fmt.Println(v) case int: fmt.Println(2*v) case []string: fmt.Println(v) } } => aaaaaaa 200 [a b c]
こんな感じで変数の型(type)によって処理を分岐させます
あともう1つ詰まったところがあり, それが
[]interface{}ってやっとけば, stringだろうがintだろうがboolだろうがうけとってくれるやろーって
package main import( "fmt" ) func main() { Output([]string{"a", "b", "c"}) Output([]int{100, 200, 300}) Output([]bool{true, false}) } func Output(x interface{}) { switch v := x.(type) { case []interface{}: fmt.Println(v) default: fmt.Println("ハズレ") } } => ハズレ ハズレ ハズレ
そうはうまくいかないんですね
見事にスルーされてます(泣
実は[]interface{}型の配列であれば受け取ってもらえます
package main import( "fmt" ) func main() { Output([]interface{}{"test1", 100, true}) } func Output(x interface{}) { switch v := x.(type) { case []interface{}: fmt.Println(v) default: fmt.Println("ハズレ") } } => [test1 100 true]
interface{}型の配列が存在するために, 配列の型なんでもこーいって形で使用することができないのかなって感じです
というな感じで, interface{}と戯れてましたってお話でした
interface{}は便利
リーダブルコード読んでみた
インフラ構築などが好きでプログラムを書くのが嫌いでした.
ただ, 最近はプログラマーもインフラを触れるようになってきている時代, ある程度は書けるようにならなきゃなぁ...っと思い言語を復習したり, Railsやswiftでアプリを作ってみたりしているうちにコード書くのも楽しく思えてきました.
ただ, 自分一人で完結するものばかり書いてたので, ものすごーーーーく汚かったw
「リファクタリング?何それ, 美味しいの?」ってレベルです
自分で書いてても何がなんだがわからないことばかり(笑)
しかし, 仕事で使うようになってこのままじゃダメだと思い, よく聞く良本「リーダブルコード」を買って読んでみた.
1章読むたびに, 「ごめんなさい...m(_ _)m」って気持ちになりました(笑)
直さなきゃいけないポイントがいっぱいあるんですが, 自分の中で少なくともこれだけは気をつけようと思ったポイントは3点
- 変数の名前
- ネストを深くしない
- コードの重複を避ける
これだけは何がなんでも気をつけると心に誓いました.
自分のコードを見ると,
- 変数名は「a」,「hoge」, 「hoge2」,「fuga」, 「piyo」...など
- forの中にfor, ifが大量発生
- main関数に全部書くから重複だらけ
力技だけで動いているものばかり, 目も当てられない_:(´ཀ`」 ∠):
実際にこの3点を気をつけるだけで, コードの見通しがかなりましになりました.
コード書くセンスないからを言い訳にせずに, せめて誰かに見せた時に「最高」とまでは厳しいですが「読めなくはない(笑)」といわれるように頑張りたい...!
リーダブルコードは読んで良かった思えた1冊でした