bash: คัดลอกข้อมูลผู้ใช้ไปเครื่องใหม่

ต้องการโอนข้อมูลผู้ใช้ไปเครื่องใหม่

ถ้าเราคัดลอกไฟล์ /etc/passwd /etc/shadow /etc/group /etc/gshadow ไปทับเครื่องใหม่แบบตรง ๆ จะเกิดปัญหาเรื่องผู้ใช้ของระบบจะติดไปด้วย ซึ่งอาจมีค่า UID และ GID ที่ไม่ตรงกัน

ค้นกูเกิลได้วิธีการจากที่นี่ครับ Move or migrate user accounts from old Linux server to a new Linux server

เขาใช้หลักการที่ว่า UID ของผู้ใช้ทั่วไป จะมีค่ามากกว่า 1000 (ของ RedHat คือ 500) และใช้ awk เป็นตัวกรอง

--- ข้อเขียนต่อจากนี้ไป ไม่จำเป็นต้องใช้ตามนี้ และมีอันตราย ควรทดสอบกับเครื่องทดสอบ ก่อนใช้งานจริง---

ขั้นตอนตามต้นฉบับก็ไม่มากเท่าไหร่ แต่กลัวว่าเวลาย้ายจริงจะพิมพ์พลาด เลยเอามาเขียนเป็นสคริปต์เพื่อช่วยลดความผิดพลาดตอนพิมพ์บนบรรทัดคำสั่ง รวมทั้งเป็นการศึกษาการเขียนสคริปต์ของ bash ร่วมกันแล้วกันนะครับ

ตั้งชื่อว่า d.migrate-groupuser ผมใส่ไว้ใน /root
(ห้ามใส่ในพาธการค้นหาของระบบเด็ดขาด เพราะต้องมีการแก้ไขค่าก่อนใช้งานจริง)

ตอนใช้งานก็เปลี่ยนค่าตัวแปร TARGETMACHINE ให้เป็นชื่อเครื่องใหม่ที่เราจะโอนไป แล้วก็สั่งรันได้เลย

โปรแกรมจะทำงานดังนี้

  1. คัดลอกไฟล์ /etc/{passwd,shadow,group,gshadow} และบีบอัดไดเรกทอรี /home และ /var/spool/mail มาไว้ในไดเรกทอรี $MIGRATEDIR
  2. ผลิตสคริปต์ชื่อ d.import-groupuser เอาไว้สั่งรันที่เครื่องใหม่ และ d.rollback-groupuser เอาไว้สั่งทำย้อนกลับที่เครื่องใหม่เช่นกัน
  3. โอนไฟล์ทั้งหมดใน $MIGRATEDIR ไปยังเครื่องใหม่

หลังจากนั้น เราก็สั่งรันสคริปต์ d.import-groupuser ที่เครื่องใหม่ได้เลย

*** ใช้ด้วยความระมัดระวัง ***

เริ่มเลย

# vi /root/d.migrate-groupuser
#!/bin/bash
#PREREQUIST:
#  1. INSTALL PACKAGE: openssh-client
#  2. EDIT THIS FILE, CHANGE VARIABLE "TARGETMACHINE" TO REAL TARGET 
#THEN RUN AS root

MIGRATEDIR="/root/migrategroupuser"    #MIGRATE DIR
UGIDLIMIT=1000    #UID&GID OF USER DATA: DEBIAN=1000, REDHAT=500

# EDIT TARGETMACHINE 
TARGETMACHINE="newserver"              #COPY TO THIS MACHINE
TARGETDIR="/root/importgroupuser"      #COPY DATA TO THIS DIR

if [ "$1" != "OK" ]; then
    PROG=`basename $0`
    cat << EOF

*** DON'T PLACE THIS SCRIPT IN SYSTEM SEARCH PATH
*** USE WITH CARE
*** EDIT TARGETMACHINE VARIABLE THEN RUN AS ROOT

Move or migrate user accounts from old Linux server to a new Linux server
FROM: http://www.cyberciti.biz/faq/howto-move-migrate-user-accounts-old-to-new-server/

USE WITH CARE, PLEASE BACKUP OLD DATA, RUN AS ROOT
- COPY FILTERED /etc/{passwd,group,shadow,gshadow} TO $MIGRATEDIR WITH EXT .mig 
- BACKUP /home, /var/spool/mail TO $MIGRATEDIR .tar.gz
- TRANSFER ALL FILES IN $MIGRATEDIR TO root@$TARGETMACHINE:$TARGETDIR WITH scp
 
USAGE:
    $PROG OK

('OK' is safety argument)
DON'T FORGET TO EDIT TARGETMACHINE VARIABLES

EOF
    exit 1
fi

if [ ! `which scp` ]; then
    echo "Please install 'openssh-client' first."
    exit 1
fi

mkdir -p $MIGRATEDIR

echo "
Copy /etc/{password,group,shadow,gshadow} to $MIGRATEDIR ..."
for i in /etc/{passwd,group,shadow,gshadow}; do
    j=`basename $i`
    awk -v LIMIT=$UGIDLIMIT -F: '($3>=LIMIT) && ($3!=65534)' $i > $MIGRATEDIR/$j.mig
done

echo "
gzip /home ..."
tar -zcpf $MIGRATEDIR/home.tar.gz /home/*

echo "
gzip /var/spool/mail ..."
tar -zcpf $MIGRATEDIR/mail.tar.gz /var/spool/mail/*

#------------------------------------------------

echo "
Generate import script ..."
IMPORTPROG="d.import-groupuser"
cat > $MIGRATEDIR/$IMPORTPROG << VIRTUAL_EOF
#!/bin/bash

IMPORTDIR="/root/importgroupuser"     #COPY DATA TO THIS DIR
BACKUPDIR="/root/backupgroupuser"     #BACKUP OLD DATA

if [ "\$1" != "OK" ]; then
    PROG=\`basename \$0\`
    cat << EOF

Move or migrate user accounts from old Linux server to a new Linux server
FROM: http://www.cyberciti.biz/faq/howto-move-migrate-user-accounts-old-to-new-server/

USE WITH CARE, PLEASE BACKUP OLD DATA, RUN AS ROOT
- BACKUP /etc/{passwd,group,shadow,gshadow} TO \$BACKUPDIR/etc
- BACKUP /home /var/spool/mail TO \$BACKUPDIR/tar 
- ADD NEW GROUP-USER DATA FROM \$IMPORTDIR TO /etc
- ADD NEW /home AND /var/spool/mail TO /
 
USAGE:
    \$PROG OK

('OK' is safety argument.)
    
EOF
    exit 1
fi


if [ ! -d \$IMPORTDIR ]; then
    echo "\$IMPORTDIR not exist, program aborted"
    exit 1
fi


echo "
Backup old data and add migrate data to /etc/{passwd,group,shadow,gshadow} ..."
mkdir -p \$BACKUPDIR
pushd \$BACKUPDIR
ls | while read FILE; do
    mv "\$FILE" "\$FILE.bak"
done
mkdir -p {etc,tar}
for i in {passwd,group,shadow,gshadow}; do
    cp /etc/\$i etc
    cat \$IMPORTDIR/\$i.mig >> /etc/\$i
done

echo "
Backup /home and /var/spool/mail in \$BACKUPDIR/tar ..."
tar -zcpf tar/home.tar.gz /home/*
tar -zcpf tar/mail.tar.gz /var/spool/mail/*
popd

echo "
Extract imported data in \$IMPORTDIR to /home and /var/spool/mail ..."
pushd /
echo "
gunzip \$IMPORTDIR/home.tar.gz to / ..." 
tar -zxf \$IMPORTDIR/home.tar.gz

echo "
gunzip \$IMPORTDIR/mail.tar.gz to / ..." 
tar -zxf \$IMPORTDIR/mail.tar.gz
popd

echo "
Import finished."
echo
echo "Please delete these files to finish the work:"
echo "  \$BACKUPDIR"
echo "  \$IMPORTDIR/d.import-groupuser"
echo "  \$IMPORTDIR/d.rollback-groupuser"
echo

VIRTUAL_EOF
chmod 700 $MIGRATEDIR/$IMPORTPROG
#------------------------------------------------

echo "Generate rollback script ..."
ROLLBACKPROG="d.rollback-groupuser"
cat > $MIGRATEDIR/$ROLLBACKPROG << VIRTUAL_EOF
#!/bin/bash

BACKUPDIR="/root/backupgroupuser"     #BACKUP OLD DATA

if [ "\$1" != "OK" ]; then
    PROG=\`basename $0\`
    cat << EOF

Move or migrate user accounts from old Linux server to a new Linux server
FROM: http://www.cyberciti.biz/faq/howto-move-migrate-user-accounts-old-to-new-server/

USE WITH CARE, PLEASE BACKUP OLD DATA, RUN AS ROOT, NO WARNING
- COPY BACKUP DATA IN \$BACKUPDIR/etc TO /etc
- *** REMOVE OLD /home AND /var/spool/mail ***
- COPY BACKUP DATA IN \$BACKUPDIR/tar TO /home and /var/spool/mail
- ROLLBACK \$BACKUPDIR/*.bak
 
USAGE:
    \$PROG OK

('OK' is safety argument.)

EOF
    exit 1
fi

if [ ! -d \$BACKUPDIR/etc ]; then
    echo "\$BACKUPDIR/etc not exist, program aborted"
    exit 1
fi
if [ ! -d \$BACKUPDIR/tar ]; then
    echo "\$BACKUPDIR/tar not exist, program aborted"
    exit 1
fi


echo "
Copy \$BACKUPDIR/etc to /etc ..."
pushd \$BACKUPDIR
cp etc/* /etc
popd


echo "
*** Remove /home and /var/spool/mail *** ..."
rm -rf /home /var/spool/mail

echo "
Copy \$BACKUPDIR/tar to /home and /var/spool/mail ..."
pushd /
tar -zxf \$BACKUPDIR/tar/home.tar.gz
tar -zxf \$BACKUPDIR/tar/mail.tar.gz
popd

echo "
Remove last rollback data ..."
pushd \$BACKUPDIR
rm -rf etc tar
for i in *.bak; do
    mv \$i \${i%.bak}
done

echo "
Rollback finished."

VIRTUAL_EOF
chmod 700 $MIGRATEDIR/$ROLLBACKPROG
#------------------------------------------------

echo "
Transfer data to root@$TARGETMACHINE:$TARGETDIR, enter $TARGETMACHINE root password:"
echo "COMMAND RUN: scp -r $MIGRATEDIR root@$TARGETMACHINE:$TARGETDIR"
scp -r $MIGRATEDIR root@$TARGETMACHINE:$TARGETDIR

echo "
Finished.

Next, run $TARGETDIR/$IMPORTPROG at $TARGETMACHINE
(*** Use $ROLLBACKPROG to undo the job, BUT DO USE WITH CARE ***)
"

เปลี่ยนสถานะให้รันได้

# chmod 700 /root/d.migrate-groupuser

ทดลองรัน
เริ่มที่เครื่องเก่า

# /root/d.migrate-groupuser OK
Copy /etc/{password,group,shadow,gshadow} to /root/migrategroupuser ...

gzip /home ...
tar: Removing leading `/' from member names

gzip /var/spool/mail ...
tar: Removing leading `/' from member names

Generate import script ...
Generate rollback script ...

Transfer data to root@newserver:/root/importgroupuser, enter newserver root password:
COMMAND RUN: scp -r /root/migrategroupuser root@newserver:/root/importgroupuser
root@newserver's password: <<<---NEWSERVER_ROOT_PASSWORD
d.import-groupuser                              100% 1668     1.6KB/s   00:00
d.rollback-groupuser                            100% 1291     1.3KB/s   00:00
group.mig                                       100%   90     0.1KB/s   00:00
gshadow.mig                                     100%    0     0.0KB/s   00:00
home.tar.gz                                     100%   61MB  10.2MB/s   00:06
mail.tar.gz                                     100%   10KB  10.4KB/s   00:00
passwd.mig                                      100% 1287     1.3KB/s   00:00
shadow.mig                                      100% 2937     2.9KB/s   00:00

Finished.

Next, run /root/importgroupuser/d.import-groupuser at newserver
(*** Use d.rollback-groupuser to undo the job, BUT DO USE WITH CARE ***)

ย้ายไปทำที่เครื่อง newserver

# /root/importgroupuser/d.import-groupuser OK
Backup old data and add migrate data to /etc/{passwd,group,shadow,gshadow} ...
~/backupgroupuser ~

Backup /home and /var/spool/mail in /root/backupgroupuser/tar ...
tar: Removing leading `/' from member names
tar: Removing leading `/' from member names
~

Extract imported data in /root/importgroupuser to /home and /var/spool/mail ...
/ ~

gunzip /root/importgroupuser/home.tar.gz to / ...

gunzip /root/importgroupuser/mail.tar.gz to / ...
~

Import finished.

Please delete these files to finish the work:
  /root/backupgroupuser
  /root/importgroupuser/d.import-groupuser
  /root/importgroupuser/d.rollback-groupuser

เสร็จแล้ว เครื่องใหม่จะมีชื่อผู้ใช้งานและข้อมูลของผู้ใช้ครบตามเครื่องเก่าทุกประการ
หากสำเร็จเป็นที่พอใจแล้ว ควรลบไฟล์ต่าง ๆ ตามคำแนะนำนะครับ

Topic: 
Creative Commons License ลิขสิทธิ์ของบทความเป็นของเจ้าของบทความแต่ละชิ้น
ผลงานนี้ ใช้สัญญาอนุญาตของครีเอทีฟคอมมอนส์แบบ แสดงที่มา-อนุญาตแบบเดียวกัน 3.0 ที่ยังไม่ได้ปรับแก้