nemunemu_zzzの日記

備忘録的な何かになればいいな

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画面にてアイテムを登録する

f:id:nemunemu_zzz:20191210143530p:plain

キーは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/

 

通知の設定の仕方は参考サイトのとおりです。

 

ここから少し通知わかりやすくする手順です。

用意したパラメータとコードです。

f:id:nemunemu_zzz:20191127004928p:plain

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 だとアラートメッセージが表示されます。

f:id:nemunemu_zzz:20191127010254p:plain

 

基本的にはSlack の blocks 芸なので凝ろうと思うとどこまでもやってしまいそうです(笑)

このサイトを頼りに整合性を取りながら作ってました

block-kit-builder

 

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 なるものの存在を知ってしまい, 動かしてみたくなったのがきっかけです

FRRとは

Quagga から fork して開発してるらしいです

ubuntu 環境での FRR の展開方法がこちら

私はこれを見たときめんどくさそう...ってのが第一感想でした

Docker ないかな...って探したら普通にありましたね. こちら

とりあえずこの通りにDocker For Mac で動かしてみました

問題なく動いたんですが, nicMacnic をそのまま認識していて????

どうやら, Docker の --net オプションで host を指定するとどうやら HostOS の nic をそのまま使うらしい

つまり, ubuntu の上にそのまま動かせば良さそう

今回考えた構成は, ubuntu の Docker の上に frr の Docker を動かしてやろうという頭の悪いことします

Q. そもそも Docker の上で Dcoker が動くのか?

A. できそう. dind (Docker in Docker) とか Docker マトリョーシカとか前例あり

docker run に --privileged オプションをつければできる. 参考

実際に Docker For Macubuntu 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 を作成すると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{}

[]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冊でした

リーダブルコード