PerlのNet::FTPでログインチェック

★設定が同じ構成のサーバを大量に構築した際、作成したユーザーがFTPでログイン可能かテストするスクリプト

#!/usr/bin/perl
use strict;
use warnings;
use Net::FTP;

###################################################
# SET VALIABLE
###################################################
my $pass_file = $ARGV[0];
my $host_file = $ARGV[1];
my %hash;
my @hostname;

###################################################
# SET SUBROUTINES
###################################################
sub ftp_connect {
    my ($hostname) = @_;
    my $ftp = Net::FTP->new($hostname)
    or die;
}

sub ftp_login {
    my ($hostname,$user,$pass) = @_;
    my $ftp = Net::FTP->new($hostname);
    $ftp->login($user,$pass)
        or die;
    $ftp->quit;
}

###################################################
# MAIN
###################################################
if (@ARGV != 2) {
    die "Usage: perl FtpLoginCheck.pl <passward.list> <hostname.list>\n"
}

open(FH, "<", $pass_file);

while (my $file = <FH>) {
    chomp $file;
    my ($_user, $_pass) = split /,/, $file;
    $hash{$_user} = $_pass;
}

close(FH);

open(FH, "<", $host_file);

@hostname = <FH>;

close(FH);

foreach my $host (@hostname) {
    chomp $host;
    printf "%-15s %-25s %-20s\n","==============","$host: [START]","==============";

        foreach my $user (sort keys %hash) {
            eval { &ftp_connect($host); };

                if ($@) {
                    print "Connect [Failure] $host\n";
                    last;
                }

            eval { &ftp_login($host,$user,$hash{$user}); };

                if ($@) {
                    print "Login [Failure] $user\n";

                } else {
                    print "Login [Success] $user\n";
            }
        }
    printf "%-15s %-25s %-20s\n\n","==============","$host: [END]","==============";

}

1.FTPでログインが許可されているユーザー、パスワードのリストを作成。

[root@ha-01 tmp]# cat passwd.lst
root,xxxxxxxx
abcd,xxxxxxxx
masatoshi,xxxxxxxx
[root@ha-01 tmp]#

2.対象サーバのホストリストを作成。

[root@ha-01 tmp]# cat host.lst
hadoop-slave1
hadoop-slave2
hadoop-slave3
[root@ha-01 tmp]#

3.実行結果

[root@ha-01 tmp]# ./FtpLoginCheck.pl passwd.lst host.lst
==============  hadoop-slave1: [START]    ==============
Login [Failure] abcd
Login [Success] masatoshi
Login [Success] root
==============  hadoop-slave1: [END]      ==============

==============  hadoop-slave2: [START]    ==============
Login [Failure] abcd
Login [Success] masathoshi
Login [Success] root
==============  hadoop-slave2: [END]      ==============

==============  hadoop-slave3: [START]    ==============
Connect [Failure] hadoop-slave3
==============  hadoop-slave3: [END]      ==============

[root@ha-01 tmp]#

puppetマニフェストメモ

★puppetマニフェストで使う変数の定義方法がいまいちわかってなかったのでメモ

■puppetの構成

[root@ha-01 puppet]# tree
.
|-- auth.conf
|-- autosign.conf
|-- fileserver.conf
|-- manifests
|   `-- site.pp
|-- modules
|   |-- hadoop
|   |   `-- manifests
|   |       `-- init.pp
|   `-- os
|       `-- manifests
|           `-- init.pp
|-- namespaceauth.conf
`-- puppet.conf

6 directories, 8 files
[root@ha-01 puppet]#

■/etc/puppet/manifests/site.pp

[root@ha-01 puppet]# cat manifests/site.pp
case $operatingsystemrelease {                     #facterコマンドで表示されるから定義する必要なし
            5.6: {                                 
                    include common
                    include hadoop_create_dir
                 }

            5.7: {
                    include common
            }
}

class hadoop_create_dir {
    hadoop::create_dir{test:}
}

class common {
    os::etc{test:
        resolv => "192.168.11.1",                  # facterコマンドで表示されない変数は定義してあげる
        com => COMMON,                             # ↑ と同じ
    }
}

[root@ha-01 puppet]#

■/etc/puppet/modules/os/manifests/init.pp

[root@ha-01 puppet]# cat modules/os/manifests/init.pp
define os::etc($resolv,$com) {                     # ← site.ppで定義した変数は「()」の中に「$」をつけて記述しておく
    file { "/etc/hosts":
            owner => root,
            group => root,
            mode => 644,
            content => template("/test/templates/$com/etc/hosts"),   # ←「$com」はsite.ppで定義した「COMMON」になる
    }

    file { "/etc/resolv.conf":
            owner => root,
            group => root,
            mode => 644,
            content => template("/test/templates/$com/etc/resolv.conf"),  # ←「$com」はsite.ppで定義した「COMMON」になる
    }

    case $network_eth0 {                          # ← facterコマンドで表示されるからそのまま使える

        "192.168.11.0" : {                         
            file { "/tmp/sample.txt":
                owner => root,
                group => root,
                mode => 755,
                content => template("/test/templates/$operatingsystemrelease/sample.txt"),            
            }                                      # ↑ facterコマンドで表示されるからそのまま使える
        }

        "192.168.100.0" : {
            file { "/tmp/sample.txt":
                owner => root,
                group => root,
                mode => 755,
                content => template("/test/templates/$operatingsystemrelease/sample.txt"),
             }                                     # ↑ facterコマンドで表示されるからそのまま使える
        }
    }

    file { "/tmp/hostname.txt":
            owner => root,
            group => root,
            mode => 644,
            content => template("/test/templates/$hostname/hostname.txt"), 
    }                                          # ↑ facterコマンドで表示されるからそのまま使える

}
[root@ha-01 puppet]#

■site.ppで定義した変数「resolv => "192.168.11.1",」を配布する設定ファイル内に定義する時

例)

[root@ha-01 test]# cat templates/COMMON/etc/resolv.conf
nameserver <%= resolv %>         # ← <%=  %> で囲むことで参照できる。「$」は付ける必要なし
[root@ha-01 test]#


※配布するファイルは「content => template()」の「()」内のパスに配置してあげる。
 デフォルトは「/var/puppet/templates」配下だけど、フルパスで書けばどこでもOK


★メモ 
■puppetのver0.25以降だと正規表現が使える。「/」で囲んであげるとOK

例)
/^hadoop-slave[1-17]$/

■puppetマスターとpuppetクライアントで時刻が一致していないと認証に失敗してしまうので注意

■puppetmasterへの接続は、↓のコマンドラインだったらどっちでもOK
1. puppetd --no-daemonize --onetime --server ha-01 --verbose

2. puppetd --test --server ha-01

NETWORKアドレスとBROADCASTアドレスを取得するスクリプト

★「IPアドレス」と「サブネットマスク」の情報から「NETWORKアドレス」と「BROADCASTアドレス」を取得するスクリプト

#!/bin/sh

######################################################
# SET VARIABLE
######################################################
SHELL_NAME=`basename $0`
HOSTLIST=$1
NET_LST=$2
LOG=./log/GET_NWADDR.$$

######################################################
# SET ARGUMENT
######################################################
if [ $# -ne 2 ]; then
        echo "Usage : sh ${SHELL_NAME} <hostlist> <net.lst>"
        exit 1
fi

if [ ! -f ${HOSTLIST} ]; then
        echo "Error : File not found [${HOSTLIST}]"
        exit 1
fi

if [ ! -f ${NET_LST} ]; then
        echo "Error : File not found [${NET_LST}]"
        exit 1
fi

######################################################
# MAIN
######################################################
for HOST in `cat ${HOSTLIST}`
do
        echo --------------------------- ${HOST} ---------------------------                                      | tee -a ${LOG}
        ################################
        # CHECK HOSTNAME
        ################################
        grep -q ${HOST} ${NET_LST}
        if [ $? -ne 0 ]; then
                echo "Host is not found ${HOST}"                                                                  | tee -a ${LOG}
                echo                                                                                              | tee -a ${LOG}
                continue
        fi

        ################################
        # SET IPADDR & NETMASK
        ################################
        IPADDR=`grep ${HOST} ${NET_LST} | awk -F, '{print $2}'`
        NETMASK=`grep ${HOST} ${NET_LST} | awk -F, '{print $3}'`

        ################################
        # GET NETWORK & BROADCAST
        ################################

        NETWORK=`ipcalc -n ${IPADDR} ${NETMASK} | awk -F= '{print $2}'`
        BROADCAST=`ipcalc -b ${IPADDR} ${NETMASK} | awk -F= '{print $2}'`

        printf "%s\n%s\n%s\n%s\n" IPADDR=${IPADDR} NETMASK=${NETMASK} NETWORK=${NETWORK} BROADCAST=${BROADCAST}   | tee -a ${LOG}
        echo                                                                                                      | tee -a ${LOG}

done

1.ホストリストを作成

[root@ha-01 SHELL]# cat host.lst
hadoop-slave1
hadoop-slave2
hadoop-slave3
[root@ha-01 SHELL]# 

2.ホスト名、IPアドレスサブネットマスクをコンマで区切ったリストを作成

[root@ha-01 SHELL]# cat net.lst
hadoop-slave1,172.16.11.151,255.255.252.0
hadoop-slave2,192.168.11.152,255.255.255.0
hadoop-slave3,10.16.11.123,255.255.255.224
[root@ha-01 SHELL]#

3.実行結果

[root@ha-01 SHELL]# sh GET_NWADDR.sh host.lst net.lst
 --------------------------- hadoop-slave1 ---------------------------
IPADDR=172.16.11.151
NETMASK=255.255.252.0
NETWORK=172.16.8.0
BROADCAST=172.16.11.255

 --------------------------- hadoop-slave2 ---------------------------
IPADDR=192.168.11.152
NETMASK=255.255.255.0
NETWORK=192.168.11.0
BROADCAST=192.168.11.255

 --------------------------- hadoop-slave3 ---------------------------
IPADDR=10.16.11.123
NETMASK=255.255.255.224
NETWORK=10.16.11.96
BROADCAST=10.16.11.127

[root@ha-01 SHELL]#

ssh-keygen自動化スクリプト

ssh-keygenコマンドで対話形式の部分を自動化し、パスフレーズなしの「authorized_keys」を作るスクリプト

#!/bin/sh

#################################
# SET VARIABLE
#################################
DSA_PUB="${HOME}/.ssh/id_dsa.pub"
KEYS="${HOME}/.ssh/authorized_keys"

#################################
# MAIN
#################################

ssh-keygen -t dsa -P "" << EOF

EOF

if [ ! -f ${DSA_PUB} ]; then
        echo "ERROR : File not found [${DSA_PUB}]"

else
        cat ${DSA_PUB} >> ${KEYS}
        chmod 600 ${KEYS}

fi

リモートホストに対してロケールでShift-JISを設定する

#!/bin/sh

##########################################################
# SET VARIABLE
##########################################################
CURDIR=`dirname $0`
LOG=${CURDIR}/log/check_rsh.$$
HOSTLIST=$1
SHELL_NAME=`basename $0`
RSH="/usr/bin/rsh"
LOCALE="/usr/bin/locale -a"
LOCALEDEF="/usr/bin/localedef -f SHIFT_JIS -i ja_JP ja_JP.SJIS"
SJIS="ja_JP.sjis"
DATE=`date | awk '{print $5}'`
COUNT=1

##########################################################
# CHECK ARGUMENT
##########################################################
if [ $# -ne 1 ]; then
        echo "USAGE : ${SHELL_NAME} <hostlist>"
        exit 1
fi

if [ ! -f ${HOSTLIST} ]; then
        echo "ERROR : File not found [${HOSTLIST}]"
        exit 1
fi


##########################################################
# MAIN
##########################################################

for HOST in `cat ${HOSTLIST}`
do


        ##################################################
        # CHECK HOSTNAME
        ##################################################
        grep -q ${HOST} /etc/hosts
        if [ $? -ne 0 ]; then
                echo "[Host not found] ${HOST}"
                echo
                continue
        fi


${RSH} ${HOST} "${LOCALE} | grep -q ${SJIS} ; echo \$?" > ${LOG}

STAT=`cat ${LOG}`

        if [ ${STAT} -ne 0 ]; then
                ${RSH} ${HOST} "${LOCALEDEF} > /dev/null 2>&1"
                ${RSH} ${HOST} "${LOCALE} | grep -q ${SJIS} ; echo \$?" > ${LOG}

                _STAT=`cat ${LOG}`

                if [ ${_STAT} -ne 0 ]; then
                        echo "[${COUNT}] ${DATE} [FAILURE] ${HOST} "
                        echo

                else
                        echo "[${COUNT}] ${DATE} [SUCCESS] ${HOST}"
                        echo
                fi

        else
                echo "[${COUNT}] ${DATE} [SUCCESS] ${HOST}"
                echo
        fi

rm -f ${LOG}
COUNT=`expr ${COUNT} + 1`

done

LVMでディスク管理

★fdiskでLVM用のパーティション作成して、PV、VG、LVの作成&削除はなにかと忘れやすいのでメモ。

1.LVM用パーティションの作成

[root@ha-01 ~]# fdisk /dev/vdb

2.パーティションの確認

コマンド (m でヘルプ): p

Disk /dev/vdb: 10.4 GB, 10485760000 bytes
16 heads, 63 sectors/track, 20317 cylinders
Units = シリンダ数 of 1008 * 512 = 516096 bytes

デバイス Boot      Start         End      Blocks   Id  System

3.新規パーティションの作成

コマンド (m でヘルプ): n
コマンドアクション
   e   拡張
   p   基本領域 (1-4)
p
領域番号 (1-4): 1
最初 シリンダ (1-20317, default 1):
Using default value 1
終点 シリンダ または +サイズ または +サイズM または +サイズK (1-20317, default 20317): +5000M

4.システムIDをLVMへ変更

コマンド (m でヘルプ): t
Selected partition 1
16進数コード (L コマンドでコードリスト表示): 8e
領域のシステムタイプを 1 から 8e (Linux LVM) に変更しました

5.パーティションの確認

コマンド (m でヘルプ): p

Disk /dev/vdb: 10.4 GB, 10485760000 bytes
16 heads, 63 sectors/track, 20317 cylinders
Units = シリンダ数 of 1008 * 512 = 516096 bytes

デバイス Boot      Start         End      Blocks   Id  System
/dev/vdb1               1        9689     4883224+  8e  Linux LVM

6.書き込み

コマンド (m でヘルプ): w
領域テーブルは交換されました!

ioctl() を呼び出して領域テーブルを再読込みします。

警告: 領域テーブルの再読込みがエラー 16 で失敗しました: デバイスもしくはリソースがビジー状態です。
カーネルはまだ古いテーブルを使っています。
新しいテーブルは次回リブート時に使えるようになるでしょう。
ディスクを同期させます。

7.パーティションテーブルの再読み込み

[root@ha-01 ~]# partprobe

8.物理ボリュームの初期化

[root@ha-01 ~]# pvcreate /dev/vdb1
  Physical volume "/dev/vdb1" successfully created

9.物理ボリュームの情報を表示

[root@ha-01 ~]# pvdisplay /dev/vdb1
  "/dev/vdb1" is a new physical volume of "4.66 GB"
  --- NEW Physical volume ---
  PV Name               /dev/vdb1
  VG Name
  PV Size               4.66 GB
  Allocatable           NO
  PE Size (KByte)       0
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               kKfHKQ-KaDD-ANpQ-K2ZA-a0Zn-heEA-lPWpgd

10.ボリュームグループの作成

[root@ha-01 ~]# vgcreate vg01 /dev/vdb1
  Volume group "vg01" successfully created

11.ボリュームグループの情報を表示

[root@ha-01 ~]# vgdisplay vg01
  --- Volume group ---
  VG Name               vg01
  System ID
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  1
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                0
  Open LV               0
  Max PV                0
  Cur PV                1
  Act PV                1
  VG Size               4.66 GB
  PE Size               4.00 MB
  Total PE              1192
  Alloc PE / Size       0 / 0
  Free  PE / Size       1192 / 4.66 GB
  VG UUID               c1lgvu-z7j9-zem3-Ygk9-Mp3J-hPt0-Sz6RkG

12.論理ボリュームの作成

[root@ha-01 ~]# lvcreate -L128M -n drbdmeta vg01
  Logical volume "drbdmeta" created

[root@ha-01 ~]# lvcreate -L4000M -n drbddata vg01
  Logical volume "drbddata" created

13.論理ボリュームの情報を表示

[root@ha-01 ~]# lvdisplay /dev/vg01/drbdmeta
  --- Logical volume ---
  LV Name                /dev/vg01/drbdmeta
  VG Name                vg01
  LV UUID                ETpJdU-dcNF-fdwW-bwhd-eoDt-A8hL-bcLTCK
  LV Write Access        read/write
  LV Status              available
  # open                 0
  LV Size                128.00 MB
  Current LE             32
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           252:5

[root@ha-01 ~]# lvdisplay /dev/vg01/drbddata
  --- Logical volume ---
  LV Name                /dev/vg01/drbddata
  VG Name                vg01
  LV UUID                eSTz28-anPp-zTG3-o7da-B7LH-NtC0-cRBmtT
  LV Write Access        read/write
  LV Status              available
  # open                 0
  LV Size                3.91 GB
  Current LE             1000
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           252:6

★LVMの削除の流れは、作成の時とは逆でLV、VG、PVの順に削除する

1.論理ボリュームの削除

[root@ha-01 ~]# lvremove /dev/vg01/drbdmeta
Do you really want to remove active logical volume drbdmeta? [y/n]: y
  Logical volume "drbdmeta" successfully removed

[root@ha-01 ~]# lvremove /dev/vg01/drbddata
Do you really want to remove active logical volume drbddata? [y/n]: y
  Logical volume "drbddata" successfully removed

2.ボリュームグループの削除

[root@ha-01 ~]# vgremove vg01
  Volume group "vg01" successfully removed

3.物理ボリュームの削除

[root@ha-01 ~]# pvremove /dev/vdb1
  Labels on physical volume "/dev/vdb1" successfully wiped

Bondingドライバの設定

★2つの物理NIC「eth1」と「eth2」の上に論理デバイス「bond0」を設定し、NIC冗長化を行う手順

1.「/etc/modprobe.conf」に対象のBondingデバイスを定義する。
論理デバイス「bond0」のaliasを追加し、デバイス・ドライバ「bonding」を指定

■「/etc/modprobe.conf」の設定
alias eth1 8139cp
alias eth2 8139cp
alias bond0 bonding

2.ネットワーク設定ファイル「eth1」と「eth2」の設定ファイルを編集
各設定ファイルで、bond0をマスターとし自身をスレイブ・アダプタとして指定

■「/etc/sysconfig/network-scripts/ifcfg-eth1」の設定
DEVICE=eth1
MASTER=bond0
SLAVE=yes
BOOTPROTO=none
HWADDR=54:52:00:1a:9d:de
■「/etc/sysconfig/network-scripts/ifcfg-eth2」の設定
DEVICE=eth2
MASTER=bond0
SLAVE=yes
BOOTPROTO=none
HWADDR=54:52:00:40:d5:f7

3.論理アダプター「bond0」の設定ファイルを作成

■「/etc/sysconfig/network-scripts/ifcfg-bond0」の設定
DEVICE=bond0
IPADDR=192.168.11.155
NETMASK=255.255.255.0
GATEWAY=192.168.11.1
ONBOOT=yes
BOOTPROTO=static
BONDING_OPTS="mode=1 primary=eth1 miimon=100 updelay=5000"

4.networkサービスの再起動

[root@ha-01 ~]# service network restart

5.Bondingデバイスの稼働状況確認。

[root@ha-01 ~]# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v3.4.0-1 (October 7, 2008)

Bonding Mode: fault-tolerance (active-backup)
Primary Slave: eth1 (primary_reselect always)
Currently Active Slave: eth1
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 5000
Down Delay (ms): 0

Slave Interface: eth1
MII Status: up
Speed: 100 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 54:52:00:1a:9d:de

Slave Interface: eth2
MII Status: up
Speed: 100 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 54:52:00:40:d5:f7
[root@ha-01 ~]#

★アクティブ・アダプタを手動で切り替える場合は、ifenslaveコマンドを使用する

例)eth2をbond0のアクティブに変更

[root@ha-01 ~]# ifenslave -c bond0 eth2

★メモ
「ifcfg-bondX」の設定で「BONDING_OPTS」の「primary」を指定している場合、
対象の「ethX」が優先的にアクティブになる。アクティブの「ethX」の障害後、復旧すると自動的にアクティブに戻る。

自動切り戻しを行いたくない場合は、「primary」パラメータを指定しないようにする。
この場合、サーバ起動時にアクティブのethファイルがどちらになるかはわからない。
起動時にアクティブに指定したい場合は、「/etc/rc.local」に「ifenslave -c bondX ethX」を記載し、
明示的に切り替えるよう指定する。