mysql_failover の --exec-after --exec-before の引数調査

メモ。

mysql_failover のサービス定義は

[Unit]
Description=MySQL Failover
After=network.target

[Service]
Type=forking
Restart=always
TimeoutSec=120
PIDFile=/var/run/mysql_failover.pid
ExecStart=/usr/bin/mysqlfailover \
  -vv \
  --master=root@10.10.10.12 \
  --discover-slaves-login=root \
  --candidates=root@10.10.10.13,root@10.10.10.14 \
  --pidfile=/var/run/mysql_failover.pid \
  --interval 10 \
  --failover-mode=auto \
  --daemon=start \
  --force \
  --exec-before=/var/lib/mysql_failover/exec_before.sh \
  --exec-after=/var/lib/mysql_failover/exec_after.sh \
  --log=/var/log/mysql/failover.log

[Install]
WantedBy=multi-user.target

としてある。

--exec-{before|after}で指定したスクリプトの中身は

#! /bin/bash

# print stdout
cat - > /tmp/mysql_failover_before_stdout

# print args 
echo $* > /tmp/mysql_failover_before_args


マスターを落としてログを見てみると

# tailf /var/log/mysql/failover.log

2016-12-25 20:39:07 PM INFO host: 10.10.10.12, port: 3306, role: MASTER, state: UP, gtid_mode: ON, health: OK, version: 5.6.35-log, master_log_file: mysql-bin.000004, master_log_pos: 191, IO_Thread: , SQL_Thread: , Secs_Behind: , Remaining_Delay: , IO_Error_Num: , IO_Error: , SQL_Error_Num: , SQL_Error: , Trans_Behind:
2016-12-25 20:39:07 PM INFO host: 10.10.10.13, port: 3306, role: SLAVE, state: UP, gtid_mode: ON, health: OK, version: 5.6.35-log, master_log_file: mysql-bin.000004, master_log_pos: 191, IO_Thread: Yes, SQL_Thread: Yes, Secs_Behind: 0, Remaining_Delay: No, IO_Error_Num: 0, IO_Error: , SQL_Error_Num: 0, SQL_Error: , Trans_Behind: 0
2016-12-25 20:39:07 PM INFO host: 10.10.10.14, port: 3306, role: SLAVE, state: UP, gtid_mode: ON, health: OK, version: 5.6.35-log, master_log_file: mysql-bin.000004, master_log_pos: 191, IO_Thread: Yes, SQL_Thread: Yes, Secs_Behind: 0, Remaining_Delay: No, IO_Error_Num: 0, IO_Error: , SQL_Error_Num: 0, SQL_Error: , Trans_Behind: 0
2016-12-25 20:39:07 PM INFO host: 10.10.10.15, port: 3306, role: SLAVE, state: UP, gtid_mode: ON, health: OK, version: 5.6.35-log, master_log_file: mysql-bin.000004, master_log_pos: 191, IO_Thread: Yes, SQL_Thread: Yes, Secs_Behind: 0, Remaining_Delay: No, IO_Error_Num: 0, IO_Error: , SQL_Error_Num: 0, SQL_Error: , Trans_Behind: 0
2016-12-25 20:39:26 PM INFO Master may be down. Waiting for 3 seconds.
2016-12-25 20:39:41 PM INFO Failed to reconnect to the master after 3 attemps.
2016-12-25 20:39:41 PM CRITICAL Master is confirmed to be down or unreachable.
2016-12-25 20:39:41 PM INFO Failover starting in 'auto' mode...
2016-12-25 20:39:41 PM INFO Checking eligibility of slave 10.10.10.13:3306 for candidate.
2016-12-25 20:39:41 PM INFO GTID_MODE=ON ... Ok
2016-12-25 20:39:41 PM INFO Replication user exists ... Ok
2016-12-25 20:39:41 PM INFO Candidate slave 10.10.10.13:3306 will become the new master.
2016-12-25 20:39:41 PM INFO Checking slaves status (before failover).
2016-12-25 20:39:41 PM INFO Preparing candidate for failover.
2016-12-25 20:39:41 PM INFO Missing transactions found on 10.10.10.14:3306. SELECT gtid_subset() = 0
2016-12-25 20:39:41 PM INFO Connecting candidate to 10.10.10.14:3306 as a temporary slave to retrieve unprocessed GTIDs.
2016-12-25 20:39:41 PM INFO Waiting for candidate to catch up to slave 10.10.10.14:3306.
2016-12-25 20:39:41 PM INFO Missing transactions found on 10.10.10.15:3306. SELECT gtid_subset() = 0
2016-12-25 20:39:41 PM INFO Connecting candidate to 10.10.10.15:3306 as a temporary slave to retrieve unprocessed GTIDs.
2016-12-25 20:39:41 PM INFO Waiting for candidate to catch up to slave 10.10.10.15:3306.
2016-12-25 20:39:41 PM INFO Creating replication user if it does not exist.
2016-12-25 20:39:41 PM INFO Spawning external script.
2016-12-25 20:39:41 PM INFO Script completed Ok.
2016-12-25 20:39:41 PM INFO Stopping slaves.
2016-12-25 20:39:41 PM INFO Performing STOP on all slaves.
2016-12-25 20:39:41 PM WARNING Executing stop on slave 10.10.10.13:3306 WARN - slave is not configured with this master
2016-12-25 20:39:41 PM INFO Executing stop on slave 10.10.10.13:3306 Ok
2016-12-25 20:39:41 PM WARNING Executing stop on slave 10.10.10.14:3306 WARN - slave is not configured with this master
2016-12-25 20:39:41 PM INFO Executing stop on slave 10.10.10.14:3306 Ok
2016-12-25 20:39:41 PM WARNING Executing stop on slave 10.10.10.15:3306 WARN - slave is not configured with this master
2016-12-25 20:39:41 PM INFO Executing stop on slave 10.10.10.15:3306 Ok
2016-12-25 20:39:41 PM INFO Switching slaves to new master.
2016-12-25 20:39:41 PM INFO Disconnecting new master as slave.
2016-12-25 20:39:41 PM INFO Execute on 10.10.10.13:3306: RESET SLAVE ALL
2016-12-25 20:39:41 PM INFO Starting slaves.
2016-12-25 20:39:41 PM INFO Performing START on all slaves.
2016-12-25 20:39:41 PM INFO Executing start on slave 10.10.10.14:3306 Ok
2016-12-25 20:39:41 PM INFO Executing start on slave 10.10.10.15:3306 Ok
2016-12-25 20:39:41 PM INFO Spawning external script.
2016-12-25 20:39:41 PM INFO Script completed Ok.
2016-12-25 20:39:41 PM INFO Checking slaves for errors.
2016-12-25 20:39:41 PM INFO 10.10.10.14:3306 status: Ok
2016-12-25 20:39:41 PM INFO 10.10.10.15:3306 status: Ok
2016-12-25 20:39:41 PM INFO Failover complete.
2016-12-25 20:39:41 PM INFO Discovering slaves for master at 10.10.10.13:3306
2016-12-25 20:39:41 PM INFO Discovering slave at 10.10.10.14:3306
2016-12-25 20:39:41 PM INFO Found slave: 10.10.10.14:3306
2016-12-25 20:39:41 PM INFO Server '10.10.10.14:3306' is using MySQL version 5.6.35-log.
2016-12-25 20:39:41 PM INFO Discovering slave at 10.10.10.15:3306
2016-12-25 20:39:41 PM INFO Found slave: 10.10.10.15:3306
2016-12-25 20:39:41 PM INFO Server '10.10.10.15:3306' is using MySQL version 5.6.35-log.
2016-12-25 20:39:46 PM INFO Unregistering existing instances from slaves.
2016-12-25 20:39:46 PM INFO Registering instance on new master 10.10.10.13:3306.
2016-12-25 20:39:46 PM INFO Master Information
2016-12-25 20:39:46 PM INFO Binary Log File: mysql-bin.000004, Position: 723, Binlog_Do_DB: N/A, Binlog_Ignore_DB: N/A
2016-12-25 20:39:46 PM INFO GTID Executed Set: ab1f57f3-ca8f-11e6-bbb9-525400225b53:1-2[...]
2016-12-25 20:39:46 PM INFO Getting health for master: 10.10.10.13:3306.
2016-12-25 20:39:46 PM INFO Health Status:
2016-12-25 20:39:46 PM INFO host: 10.10.10.13, port: 3306, role: MASTER, state: UP, gtid_mode: ON, health: OK, version: 5.6.35-log, master_log_file: mysql-bin.000004, master_log_pos: 723, IO_Thread: , SQL_Thread: , Secs_Behind: , Remaining_Delay: , IO_Error_Num: , IO_Error: , SQL_Error_Num: , SQL_Error: , Trans_Behind:
2016-12-25 20:39:46 PM INFO host: 10.10.10.14, port: 3306, role: SLAVE, state: UP, gtid_mode: ON, health: OK, version: 5.6.35-log, master_log_file: mysql-bin.000004, master_log_pos: 723, IO_Thread: Yes, SQL_Thread: Yes, Secs_Behind: 0, Remaining_Delay: No, IO_Error_Num: 0, IO_Error: , SQL_Error_Num: 0, SQL_Error: , Trans_Behind: 0
2016-12-25 20:39:46 PM INFO host: 10.10.10.15, port: 3306, role: SLAVE, state: UP, gtid_mode: ON, health: OK, version: 5.6.35-log, master_log_file: mysql-bin.000004, master_log_pos: 723, IO_Thread: Yes, SQL_Thread: Yes, Secs_Behind: 0, Remaining_Delay: No, IO_Error_Num: 0, IO_Error: , SQL_Error_Num: 0, SQL_Error: , Trans_Behind: 0
2016-12-25 20:39:59 PM INFO Discovering slaves for master at 10.10.10.13:3306
2016-12-25 20:40:00 PM INFO Discovering slave at 10.10.10.14:3306
2016-12-25 20:40:00 PM INFO Discovering slave at 10.10.10.15:3306
2016-12-25 20:40:00 PM INFO Master Information
2016-12-25 20:40:00 PM INFO Binary Log File: mysql-bin.000004, Position: 723, Binlog_Do_DB: N/A, Binlog_Ignore_DB: N/A
2016-12-25 20:40:00 PM INFO GTID Executed Set: ab1f57f3-ca8f-11e6-bbb9-525400225b53:1-2[...]
2016-12-25 20:40:00 PM INFO Getting health for master: 10.10.10.13:3306.
2016-12-25 20:40:00 PM INFO Health Status:
2016-12-25 20:40:00 PM INFO host: 10.10.10.13, port: 3306, role: MASTER, state: UP, gtid_mode: ON, health: OK, version: 5.6.35-log, master_log_file: mysql-bin.000004, master_log_pos: 723, IO_Thread: , SQL_Thread: , Secs_Behind: , Remaining_Delay: , IO_Error_Num: , IO_Error: , SQL_Error_Num: , SQL_Error: , Trans_Behind:
2016-12-25 20:40:00 PM INFO host: 10.10.10.14, port: 3306, role: SLAVE, state: UP, gtid_mode: ON, health: OK, version: 5.6.35-log, master_log_file: mysql-bin.000004, master_log_pos: 723, IO_Thread: Yes, SQL_Thread: Yes, Secs_Behind: 0, Remaining_Delay: No, IO_Error_Num: 0, IO_Error: , SQL_Error_Num: 0, SQL_Error: , Trans_Behind: 0
2016-12-25 20:40:00 PM INFO host: 10.10.10.15, port: 3306, role: SLAVE, state: UP, gtid_mode: ON, health: OK, version: 5.6.35-log, master_log_file: mysql-bin.000004, master_log_pos: 723, IO_Thread: Yes, SQL_Thread: Yes, Secs_Behind: 0, Remaining_Delay: No, IO_Error_Num: 0, IO_Error: , SQL_Error_Num: 0, SQL_Error: , Trans_Behind: 0

このログから Master が 10.10.10.12 → 10.10.10.13 にフェイルオーバーされたのがわかる

このとき、--exec-{before|after}の動作結果は

# cat /tmp/mysql_failover_{before|after}_stdout
(なし)

# cat /tmp/mysql_failover_{before|after}_args
10.10.10.12 3306 10.10.10.13 3306

つまり、標準入力ではなにもわたされず、引数で

$1 = 旧マスター IP
$2 = 旧マスター Port 
$3 = 新マスター IP
$4 = 新マスター Port 

が渡されているのがわかる。

Slack に メッセージを飛ばす

▼前準備
 ・curl をインストールしておく (ex. yum install curl)

 ・Add Service Integrations から Incoming WebHooks を選択する。
  メッセージをどのチャンネルに飛ばすかを選択する。
  'Your Unique Webhook URL' の内容に注目

▼以下のプログラムでGO~

use strict;
use warnings;
use utf8;

use JSON::XS;

my $teamname = 'xxxxxxxxxx';  # Your Unique Webhook URL の一部に書いてある
my $token    = 'xxxxxxxxxx';  # Your Unique Webhook URL の一部に書いてある
slack_notification(

  # Slack incoming-webhook API URL
    "https://$teamname.slack.com/services/hooks/incoming-webhook?token=$token",

  # チャンネル名
    '#from_perl_test',

  # メッセージテキスト
    'notification from perl program',

  # ユーザ名を偽装?できる
    'user_name_',
);

sub slack_notification
{
    my ( $url, $channel, $text, $user_name ) = @_;

    my $json_text = JSON::XS->new->utf8->encode( {
        "channel"  => $channel,
        "text"     => $text,
        "username" => $user_name,
    } );
    my $http_content = sprintf( "payload=%s", $json_text );
    `curl -X POST --data-urlencode '$http_content' $url > /dev/null 2>&1`;
}

ディレクトリ一括 require

<? php

function require_dir( $dir )
{
    $dir_last = substr( $dir, -1 );
    if ( $dir_last !== '/' ) {
        $dir .= '/';
    }

    if ( is_dir( $dir ) ) {
        if ( $dh = opendir( $dir ) ) {
            while ( ( $file = readdir( $dh ) ) !== false ) {
                if ( $file !== '.' && $file !== '..' ) {
                    if ( is_dir( $dir . $file ) ) {
                        require_dir( $dir . $file );
                    }
                    else {
                        require_once( $dir . $file );
                    }
                }
            }
            closedir( $dh );
        }
    }
}

grep で tab を検索する

grep $'\t' ${filename}

man bash より抜粋

       Words  of  the  form  $'string' are treated specially.  The word expands to string, with backslash-escaped characters replaced as
       specified by the ANSI C standard.  Backslash escape sequences, if present, are decoded as follows:
              \a     alert (bell)
              \b     backspace
              \e
              \E     an escape character
              \f     form feed
              \n     new line
              \r     carriage return
              \t     horizontal tab
              \v     vertical tab
              \\     backslash
              \'     single quote
              \"     double quote
              \nnn   the eight-bit character whose value is the octal value nnn (one to three digits)
              \xHH   the eight-bit character whose value is the hexadecimal value HH (one or two hex digits)
              \cx    a control-x character

       The expanded result is single-quoted, as if the dollar sign had not been present.

git リモートリポジトリをローカルにバックアップ

リモートリポジトリ消すってなときに
git clone とかしてきたら

current_branch=`git rev-parse --abbrev-ref HEAD`

git fetch
git fetch --prune

for remote_branch in `git branch -r`
do
     $remote_branch =~ ^origin/(.*)$ 
    branch_name=${BASH_REMATCH[1]}
    if [ $branch_name = $current_branch ]; then
        continue
    fi
    if [ ! $branch_name = 'HEAD' ]; then
        echo "checkout : $branch_name <- $remote_branch"
        git checkout -b $branch_name $remote_branch
    fi
done

git checkout $current_branch

CentOS に vagrant インストールのメモ

 puppet module install skoblenick-vagrant
 puppet apply --execute 'include vagrant'
 vagrant --version
 # puppet 入ってなかったら
 rpm -ivh http://yum.puppetlabs.com/el/6/products/x86_64/puppetlabs-release-6-7.noarch.rpm
 yum install -y puppet

Jenkins インストール powered by puppet

puppet を経由で Jenkins インストールとプラグインのセットップまでしちゃうよ。

 # puppet インストール
 yum install puppet

 # puppet::jenkins モジュールをインストール
 puppet module install rtyler-jenkins

 # jenkins をインストール
 puppet apply --execute 'include jenkins'

 これで、
  ・jenkins のインストール
   └gpgkey ファイルを apt-key add してとか全自動
  ・サービススタート(service jenkins start)
  ・自動起動(chkconig jenkins on)
 までやってくれる。

Jenkins Plugin をインストールしたいときは、
puppet の manifest に インストールしたい plugin-id を記述すれば

# jenkins/plugin.pp
jenkins::plugin {
    [ 'show-build-parameters' ] :
}
jenkins::plugin {
    [ 'multiple-scms', 'github-api', 'git', 'github' ] :
}
jenkins::plugin {
    [ 'conditional-buildstep' ] :
}
jenkins::plugin {
    [ 'promoted-builds', 'subversion', 'parameterized-trigger' ] :
}
jenkins::plugin {
    [ 'run-condition' ]:
}
jenkins::plugin {
    [ 'ircbot' ]:
}
 puppet apply jenkins/plugin.pp

 これでできあがり。

 こういう意図でつくられている puppet 使っていれば
 このお手軽さはあたりまえだな。

※インストールは以前は6行だった

wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'
sudo apt-get update
sudo apt-get install jenkins
sudo service jenkins start
sudo chkconfig jenkins on