Jenkinsに設定しているSlave NodeのIPアドレスとAWS Elastic IPが一致しているか確認する方法


皆さん、[JenkinsでSlave,Master構成](http://qiita.com/yasuhiroki/items/d618796a1ba1366c4f80)していますか？

Master側のjobをバコバコぶっこんでるとそのうちJenkinsが重くなって「ヒィーー」ってなるので、先におすすめしておきます。

ところでJenkinsのNode設定なのですが、IPアドレス設定ですよね。
EC2インスタンスの場合、Elastic IPで固定すれば、まあ変わることはあんまりないと思いますが、クラウドサーバーの場合、基本

「IPアドレスは変わる」が前提だと思います。

そこで、jenkinsのNode情報からIPアドレスをぶっこ抜いて(JenkinsのリモートAPI)、[AWS CLI](https://aws.amazon.com/jp/cli/)で設定したNodeのIPアドレスが一致しているか確認するJobをつくってみました。

## 環境

* MacOSX(El Capition)
	* Jenkins 2.7

## 参考にしたサイト

* [[Jenkins] リモートAPI で Jenkins さんとお話をする ](http://d.hatena.ne.jp/akihirox/20111220)

## 事前準備に必要なもの

* [jenkins](https://jenkins.io/)
	* OSXの方は ``` brew install jenkins ``` でOK
* [AWS CLI](http://docs.aws.amazon.com/ja_jp/kinesis/latest/dev/kinesis-tutorial-cli-installation.html)
	* ``` pip install awscli --upgrade --ignore-installed six ``` を打とう

* [jq](https://stedolan.github.io/jq/)
	* jsonパーサー
	* OSXな方は ``` brew install jq ```　でOK
* [xmlint](http://xmlsoft.org/xmllint.html)
	* OSXなら最初から入ってるはず

## JenkinsのNode設定

* Jenkinsの管理 => ノードの管理

でノード一覧に行きます。
ノードを定義していない場合は、新規ノード作成でノードを作成してください。
その際に

ノード名 = EC2インスタンスのタグName

でノード名とAWS側Nameを一致させといてください。

## Jenkins リモートAPIで定義されているノード一覧を取得する

*  jq オプション ``` --raw-output ``` はjqで整形しないレスポンスを返すオプション

```shell:/path/to/hoge
bash -lc "curl -s -u ${username}:${password} http://${jenkins url}/computer/api/json | jq --raw-output '.computer[] | .displayName'"
```

上記を実行すると下記のようなノード名一覧のレスポンスが帰ってきます。

```
master
{node名1}
{node名2}
{node名3}
```
## 各ノードから設定されているIPアドレスをぶっこ抜く

xmllintとsedを使ってIPアドレスだけの状態にしておきます。

```shell:/path/to/hoge
curl -s -u "${username}":"${password}" "${jenkins_url}"/computer/"${node名}"/config.xml |xmllint --format --xpath '//host' - | sed -e "s/^.*<host.*>\(.*\)<\/host>.*$/\1/")
```

## AWS CLIでパブリックIPをぶっこ抜く

Elastic IP 設定されているインスタンス前提でお話は進めています。

```shell:/path/to/hoge
aws ec2 describe-instances \
--filters \"Name=tag:Name,Values=${node名}\" \
--query \"Reservations[0].Instances[0].PublicIpAddress\"" \
| sed -e 's/[^"]*"\([^"]*\)".*/\1/')
```

sed でダブルコーテーションを除去しています。


## 上記3つのJOBをつなげるとこんな感じ


```shell:/path/to/job
#!/usr/bin/env bash

set -e

username="your username"
password="your password"
jenkins_url="http://{jenkins URL endpoint}"
is_success=0

# jenkins nodeのリストを取得
nodes=$(bash -lc "curl -s -u "${username}":"${password}" ${jenkins_url}/computer/api/json | jq --raw-output '.computer[] | .displayName'")

for node in `echo "${nodes}"`
do
	# masterの整合がいらない場合
    if [ "${node}" = "master" ]; then
        continue
    fi

    # jenkinsのnode IPアドレスを調べる
    jenkins_ip_address=$(curl -s -u "${username}":"${password}" "${jenkins_url}"/computer/"${node}"/config.xml |xmllint --format --xpath '//host' - | sed -e "s/^.*<host.*>\(.*\)<\/host>.*$/\1/")

	# AWSのPublic IPを取得
    aws_ip_address=$(bash -lc "aws ec2 describe-instances \
        --filters \"Name=tag:Name,Values=${node}\" \
        --query \"Reservations[0].Instances[0].PublicIpAddress\"" \
        | sed -e 's/[^"]*"\([^"]*\)".*/\1/')
    fi

    if [ "${jenkins_ip_address}" != "${aws_ip_address}" ]; then
        echo "[FATAL] mismatch node:${node}"
        is_success=1
    else
        echo "[SUCCESS] match node:${node}"
    fi

    echo "================ jenkins node IP Address ==================="
    echo "${jenkins_ip_address}"
    echo "================ AWS public IP Address ==================="
    echo "${aws_ip_address}"
done
# これでjenkinsのsuccess failureを出し分け
exit $is_success
```

コレをjobでぶっ込んでおけば、

* jenkins slave nodeのIPアドレスを間違えてかえてしまった
* EC2 インスタンスのIPアドレスが変わっちゃった

上記2つをjenkins自信が検知できます。


## 最後に

以外とすんなりできたので思わず書いてしまった。。。