#!/bin/bash
# 说明:本脚本可以实现多并发控制,向大批量主机分发秘钥。解决单线程处理任务耗时太久的问题。
# 编写时间:2021-04-20
# 作者:wanhebin
# 博客:https://www.wanhebin.com

# 获取脚本运行的开始时间的时间戳
start_time=`date +%s`

# 设置并发数
Concurrency='10'

HostUser='root'
HostPass='1'
Ip_File='/opt/ip_list.txt'
Key_Dir='/root/.ssh'
Pri_Key='id_rsa'
Pub_Key='id_rsa.pub'
Access_Log='/tmp/sshcopykey_access.log'
Error_Log='/tmp/sshcopykey_error.log'
Ssh_Copy_Log='/tmp/ssh-copy.log'


[ -f $Access_Log ] || touch $Access_Log
[ -f $Error_Log ] || touch $Error_Log
[ -f $Ssh_Copy_Log ] || touch $Ssh_Copy_Log

> $Access_Log
> $Error_Log
> $Ssh_Copy_Log

# 创建有名管道
[ -e /tmp/fd1 ] || mkfifo /tmp/fd1

# 创建文件描述符,以可读(<)可写(>)的方式关联管道文件,此时文件描述符3就有了有名管道文件的所有特性
exec 3<>/tmp/fd1
# 关联后的文件描述符拥有管道文件的所有特性,所以这时候管道文件可以删除,留下文件描述符来用就可以了
rm -rf /tmp/fd1

# 控制并发数量
for ((n=1;n<=${Concurrency};n++))
do
    # &3代表引用文件描述符3,这条命令代表往管道里面放入了一个"令牌"
    echo >&3
done

# 生成ssh-key秘钥
ssh-keygen -t rsa -f ${Key_Dir}/${Pri_Key} -P "" -q &&\

# 免密推送秘钥给其他服务器
for ip in `cat ${Ip_File}`
do
    # 从管道中读取一个令牌
    read -u3 
    {
        # 以密码的方式传输
        echo -e "\n\n================================= 主机: ${ip} =================================" >> $Ssh_Copy_Log
        sshpass -p${HostPass}  ssh-copy-id -i ${Key_Dir}/${Pub_Key} -o StrictHostKeyChecking=no ${HostUser}@${ip} &>> $Ssh_Copy_Log
        if [ $? -eq 0 ]; then
            echo "主机 ${ip} 秘钥分发成功!" | tee -a $Access_Log
        else
            echo "主机 ${ip} 秘钥分发失败!" | tee -a $Error_Log
        fi
        # 重新向管道中放入一个令牌
        echo >&3
    }&
done
wait

# 关闭文件描述符的读
exec 3<&-
# 关闭文件描述符的写
exec 3>&-

# 获取脚本运行的结束时间的时间戳
stop_time=`date +%s`

echo -e "\n所有秘钥分发完成。"
echo "耗时: `expr $stop_time - $start_time` 秒"