ループ処理でのユーザ登録/削除

###【まえがき】
三か月前から配属した現場ではユーザ登録/削除の手順が決まっておらず、
3年ほど在籍している1人の担当者がコマンドを使って一括登録したり、
その担当者がいない場合は、他の担当者がWebGUIを駆使してなんとか対応したりと、
色々と問題のある状態でした。

そういった状況から、以下の状態になるように、
LinuxOSユーザIDの登録/削除業務の運用方法を改善するよう取り組んでいます。

　・属人化の排除
　・業務手順の標準化
　・保守性の高い運用手順

環境OSはRHEL 7.4です。

###【改善方針】
改善方針はザっと以下の通りです。

　・シェルによる自動化運用(比較的簡易な構文で作成)
　・運用手順書の作成
　・作業エビデンスの出力

###【利用シェル】
以下がシェル内容です。

```BASH:Userconfig.sh
#!/bin/bash
########基本設定########
OUT_DIR=/root/useradd
OUT_FILE=Evidence_`date +%Y%m%d%H`.log
ERR_FILE=ErrorLog_`date +%Y%m%d%H`.log
INP_FILE=user_config

########処理ログ出力関数#########
writinglog () {
echo "["`date +%Y/%m/%d\ %H:%M:%S`"]" $*
}

########ID登録＆削除の本処理################
JOBCNT=`cat $OUT_DIR/$INP_FILE | wc -l`
writinglog `echo "★${JOBCNT}件分の処理を開始します..."`  1>> $OUT_DIR/$OUT_FILE
ADDCNT=0
DELCNT=0
ERRCNT=0
STATUSCNT=0
while read LINE
do
ACTION=`echo $LINE | awk '{print $1}'`
ID=`echo $LINE | awk '{print $2}'`
GRPID=`echo $LINE | awk '{print $3}'`
USRID=`echo $LINE | awk '{print $4}'`
if [[ ${ACTION} = "ADD" ]]; then
useradd -g ${GRPID} -u ${USRID} ${ID} 1>/dev/null 2>> $OUT_DIR/$ERR_FILE
chmod 700 /home/${ID} 1>/dev/null 2>> $OUT_DIR/$ERR_FILE
writinglog `cat /etc/passwd | grep ${ID}` 1>> $OUT_DIR/$OUT_FILE
writinglog `ls -l /home | grep ${ID}` 1>> $OUT_DIR/$OUT_FILE
writinglog `echo "----> ${ID}：登録処理完了" ` 1>> $OUT_DIR/$OUT_FILE
ADDCNT=`expr ${ADDCNT} + 1`
elif [[ ${ACTION} = "DELETE" ]]; then
userdel ${ID} 1>/dev/null 2>> $OUT_DIR/$ERR_FILE
rm -fr /home/${ID} 1>/dev/null 2>> $OUT_DIR/$ERR_FILE
writinglog `cat /etc/passwd | grep ${ID} | wc -l | sed -e "s/^0/${ID}：ID削除成功/" -e "s/^1/${ID}：ID削除失敗/"` 1>> $OUT_DIR/$OUT_FILE
writinglog `ls -l /home | grep ${ID} | wc -l | sed -e "s/^0/${ID}：ホームディレクトリ削除済み/" -e "s/^1/${ID}のホームディレクトリ未削除/"` 1>> $OUT_DIR/$OUT_FILE
writinglog `echo "----> ${ID}：削除処理完了"` 1>> $OUT_DIR/$OUT_FILE
DELCNT=`expr ${DELCNT} + 1`
else
echo "${ID}：エラーです。${INP_FILE}の設定値に誤りがあります(設定値：「${ACTION}」)" 1>> $OUT_DIR/$ERR_FILE
ERRCNT=`expr ${ERRCNT} + 1`
fi
STATUSCNT=`expr ${STATUSCNT} + 1`
writinglog `echo "実行中...(${STATUSCNT}/${JOBCNT})"`
done < $OUT_DIR/$INP_FILE

ALLCNT=`expr ${ADDCNT} + ${DELCNT} + ${ERRCNT}`

writinglog `echo "★全ID(${ALLCNT}件)の処理が完了しました(登録${ADDCNT}件、削除${DELCNT}件、誤記${ERRCNT}件)"` 1>> $OUT_DIR/$OUT_FILE

SHELLERR=`cat $OUT_DIR/$ERR_FILE | wc -l`
writinglog `echo "全件の処理が完了しました(エラー：${SHELLERR}件)"`
```
while read LINEで繰り返しuseradd/userdel処理をさせています。
実は現場での登録/削除処理はuseradd/userdelではなく、特定のアプリケーションの
コマンドを利用して行っておりますが、繰り返し処理部分は今回の記述を
流用できるため、検証がてら作成しています。

またシェル内でuser_configというパラメータを読み込む仕様にしております。
以下がuser_configのサンプルです。

```user_config
DELETE  testuser001     group001        2001
DELETE  testuser002     group001        2002
DELETE  testuser003     group001        2003
DELETE  testuser004     group001        2004
DELETE  testuser005     group001        2005
DELETE  testuser006     group001        2006
DELETE  testuser007     group001        2007
DELETE  testuser008     group001        2008
DELETE  testuser009     group001        2009
DELETE  testuser010     group001        2010
```
左から、作業指示(ADD or DELETE)、ユーザID、GID、UIDの
順番で引数を設定し、シェルへ引き渡すようにしました。

また1番目の引数でADDとDELETE以外を記入してしまった場合は、
エラーログに出力されるように分岐処理しています。

###【登録時のエビデンス】
Userconfig.shを実行すると、
Evidence_yyyymmddhh.logという名称のエビデンスファイルが
作成されます。登録成功時は以下の文言で出力されます。

```Evidence_2018021809.log
[2018/02/19 21:03:25] ★10件分の処理を開始します...
[2018/02/19 21:03:25] testuser001:x:2001:1003::/home/testuser001:/bin/bash
[2018/02/19 21:03:25] drwx------ 2 testuser001 group001 62 2月 19 21:03 testuser001
[2018/02/19 21:03:25] ----> testuser001：登録処理完了
[2018/02/19 21:03:25] testuser002:x:2002:1003::/home/testuser002:/bin/bash
[2018/02/19 21:03:25] drwx------ 2 testuser002 group001 62 2月 19 21:03 testuser002
[2018/02/19 21:03:25] ----> testuser002：登録処理完了
[2018/02/19 21:03:25] testuser003:x:2003:1003::/home/testuser003:/bin/bash
[2018/02/19 21:03:25] drwx------ 2 testuser003 group001 62 2月 19 21:03 testuser003
[2018/02/19 21:03:25] ----> testuser003：登録処理完了
.........................................
.........................................
[2018/02/19 21:03:25] ★全ID(10件)の処理が完了しました(登録10件、削除0件、誤記0件)
```
最初の行に今から処理するID分の件数を表示します。
一行目でcat /etc/passwdをユーザIDでgrepして登録成功の事後確認、
二行目でls /homeをユーザIDでgrepしてパーミッションの事後確認をしています。
三行目で該当ID登録処理自体の登録処理が完了したことを記載しています。
繰り返し処理が終わった最後の行で全ての処理件数を表示するようにしています。

###【削除時のエビデンス】
削除時は以下の通りです。

```Userevidence_2018021809.log
[2018/02/19 21:08:20] ★10件分の処理を開始します...
[2018/02/19 21:08:20] testuser001：ID削除成功
[2018/02/19 21:08:20] testuser001：ホームディレクトリ削除済み
[2018/02/19 21:08:20] ----> testuser001：削除処理完了
[2018/02/19 21:08:20] testuser002：ID削除成功
[2018/02/19 21:08:20] testuser002：ホームディレクトリ削除済み
[2018/02/19 21:08:20] ----> testuser002：削除処理完了
[2018/02/19 21:08:20] testuser003：ID削除成功
[2018/02/19 21:08:20] testuser003：ホームディレクトリ削除済み
[2018/02/19 21:08:20] ----> testuser003：削除処理完了
.......................................
.......................................
[2018/02/19 21:08:20] ★全ID(10件)の処理が完了しました(登録0件、削除10件、誤記0件)
```
最初の行に今から処理するID分の件数を表示します。
一行目でcat /etc/passwdをユーザIDでgrepして削除成功の事後確認、
二行目でls /homeをユーザIDでgrepしてホームディレクトリ削除の事後確認をしています。
三行目で該当ID登録処理自体の登録処理が完了したことを記載しています。
繰り返し処理が終わった最後の行で全ての処理件数を表示するようにしています。

###【エラーログの内容】
上記登録時のtestuser001～testuser010が作成されている状態で、
以下のuser_configの設定値で回したとします。

```user_config(ERROR処理用)
ADD     testuser002     group001        2099
ADD     testuser099     group100        2100
ADD     testuser100     group001        2001
TEST    testuser101     group001        2102
```
一行目はユーザIDが既に存在するためエラーに、
二行目は存在しないGIDを設定しているためエラー、
三行目はUIDが既に使用されている値のためエラー、
四行目は一番目の引数にADDでもDELETEでもない文字列を入力したためエラー、
という順番になっています。

実行後のエラーログは以下の通りです。

```ErrorLog_2018021921.log
useradd: ユーザ 'testuser002' は既に存在します
useradd: グループ 'group100' は存在しません
chmod: `/home/testuser099' にアクセスできません: そのようなファイルやディレクトリはありません
useradd: ユーザ ID 2001 は重複しています
chmod: `/home/testuser100' にアクセスできません: そのようなファイルやディレクトリはありません
testuser101：エラーです。user_configの設定値に誤りがあります(設定値：「TEST」)
```
各コマンドの標準エラー出力と、
一番目の引数で(ADD or DELETE)を選択する場面で、
二つの文字列以外が入力されている場合にエラーログへ出力されるようにしています。

###【画面への出力】
またシェル処理中に進捗がわかるように
以下のような画面出力がされるようにしておきました。

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/198785/4b06e81c-6327-a7e2-5e2a-8beb4f08d14d.png)


エラーがある時は下の通りに出ます。
```画面出力時(エラー).
[2018/02/19 21:12:18] 実行中...(1/4)
[2018/02/19 21:12:18] 実行中...(2/4)
[2018/02/19 21:12:18] 実行中...(3/4)
[2018/02/19 21:12:18] 実行中...(4/4)
[2018/02/19 21:12:18] 全件の処理が完了しました(エラー：6件)
```
最後にエラー件数も表示されるようにしました。