File: //usr/bin/aliyun_init
#!/bin/bash
#################################################################
# configs
cloudinit_version=0.1
cloudinit_name='aliyun_init'
cloud_cfg=/etc/aliyun_init/cloud.cfg
aliyun_cloud_cfg=/etc/cloud/cloud.cfg.d/aliyun_cloud.cfg
cloudinit_log=/var/log/aliyun_init.log
cloudinit_work_dir=/var/lib/aliyun_init
cloudinit_iids=$cloudinit_work_dir/instances
cloudinit_iid_link=$cloudinit_work_dir/instance
cloudinit_sem=$cloudinit_iid_link/sem/
cloudinit_userdata_raw=$cloudinit_iid_link/user-data.txt
my_hostname=''
my_ip=''
my_ssh_pubkey=''
my_iid=''
# defaults
cloudinit_enable=1
cloudinit_debug=0
manage_hostname=1
manage_hosts=1
manage_ssh_host_key=1
manage_ssh_pub_key=1
ssh_passwd_enable=1
lock_root_passwd_login=0
run_userdata=0
config_passwd=1
retries=60
max_timeout=1
key_retries=5
sleep_time=0.5
metaserver='http://100.100.100.200'
api_version='2016-01-01'
metadata_url=$metaserver/$api_version/meta-data
userdata_url=$metaserver/$api_version/user-data
#################################################################
# common
is_enable() { test $1 == 1; }
my_log() {
local level=$1
shift
echo "[`date +%Y-%m-%d-%H-%M-%S.%N`] [$level] $@" >> $cloudinit_log
}
log_info() { my_log "INFO" "$@"; }
log_error() { my_log "ERROR" "$@"; }
log_debug() { is_enable $cloudinit_debug && my_log "DEBUG" "$@"; }
netmask2cidr() {
local dst_netmask=$1
local lookup_table=(
255.255.255.255:32
255.255.255.254:31
255.255.255.252:30
255.255.255.248:29
255.255.255.240:28
255.255.255.224:27
255.255.255.192:26
255.255.255.128:25
255.255.255.0:24
255.255.254.0:23
255.255.252.0:22
255.255.248.0:21
255.255.240.0:20
255.255.224.0:19
255.255.192.0:18
255.255.128.0:17
255.255.0.0:16
255.254.0.0:15
255.252.0.0:14
255.248.0.0:13
255.240.0.0:12
255.224.0.0:11
255.192.0.0:10
255.128.0.0:9
255.0.0.0:8
254.0.0.0:7
252.0.0.0:6
248.0.0.0:5
240.0.0.0:4
224.0.0.0:3
192.0.0.0:2
128.0.0.0:1
0.0.0.0:0
)
for i in ${lookup_table[@]}; do
if [[ $dst_netmask == ${i%%:*} ]]; then
echo ${i##*:} # cidr
return 0
fi
done
return 1
}
lease_tmp_dir=`mktemp -d`
dhcp_lease=""
eth_ip=""
eth_routers=""
eth_mask=""
eth_cidr=""
obtain_lease_and_up_eth0() {
cp /usr/sbin/dhclient $lease_tmp_dir
eth0_up_cmd="ip link set dev eth0 up"
eval $eth0_up_cmd
dhcp_lease=$lease_tmp_dir/dhcp.lease
dhcp_pid=$lease_tmp_dir/dhclient.pid
lease_cmd="$lease_tmp_dir/dhclient -1 -v -lf $dhcp_lease -pf $dhcp_pid -sf /bin/true"
eval $lease_cmd
if [[ -f $dhcp_pid ]];then
pid=`cat $dhcp_pid`
if [[ -n "$pid" ]];then
log_info "kill dhclient pid : $pid"
kill -9 $pid
fi
fi
if [[ -f $dhcp_lease ]];then
eth_ip=`grep fixed-address $dhcp_lease |awk '{match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/);print substr($0,RSTART,RLENGTH)}'|grep -Ev "^127|^$"`
eth_routers=`grep routers $dhcp_lease |awk '{match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/);print substr($0,RSTART,RLENGTH)}'|grep -Ev "^127|^$"`
eth_mask=`grep subnet-mask $dhcp_lease |awk '{match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/);print substr($0,RSTART,RLENGTH)}'|grep -Ev "^127|^$"`
eth_cidr=`netmask2cidr $eth_mask`
if [[ -n "$eth_ip" ]];then
ip_add_cmd="ip -family inet addr add $eth_ip/$eth_cidr dev eth0"
eval $ip_add_cmd
log_info $ip_add_cmd
ip_link_up="ip -family inet link set dev eth0 up"
eval $ip_link_up
log_info $ip_link_up
ip_route_show="ip route show 0.0.0.0/0"
ip_route_add="ip -4 route add $eth_routers dev eth0 src $eth_ip"
ip_default_route="ip -4 route add default via $eth_routers dev eth0"
if [[ "X" == `${ip_route_show}`"X" ]];then
eval $ip_route_add
eval $ip_default_route
fi
fi
fi
return 0
}
del_lease_and_down_eth0() {
if [[ -f $dhcp_lease ]]; then
if [[ -n "$eth_ip" ]];then
ip_route_default_del="ip -4 route del default dev eth0"
eval $ip_route_default_del
ip_route_del="ip -4 route del $eth_routers dev eth0"
eval $ip_route_del
ip_del_cmd="ip -family net addr del $eth_ip/$eth_cidr dev eth0"
eval $ip_del_cmd
ip_link_down="ip -family inet link set dev eth0 down"
eval $ip_link_down
rm -rf $lease_tmp_dir
log_info "del network info"
fi
fi
}
wait_network_ready() {
while [[ $retries -gt 0 ]]; do
log_info "wait_network_ready, retries $retries"
if curl -s --fail -m $max_timeout $metaserver >& /dev/null; then
return 0
fi
sleep $sleep_time
retries=$(($retries-1))
done
return 1
}
prepare_env() {
log_info "prepare_env"
if ! which curl >& /dev/null; then
log_error "system not install curl"
return 1
fi
# if ! obtain_lease_and_up_eth0; then
# log_error "failed to get dhcp ip info"
# return 1
# fi
if ! wait_network_ready; then
log_error "network is not ready"
exit 1
else
log_info "network is ready"
fi
my_iid=`get_metadata_iid`
if [[ -z $my_iid ]]; then
log_error "failed to get instance-id"
return 1
fi
log_info "instance-id: $my_iid"
log_info "create $cloudinit_iids/$my_iid"
mkdir -p $cloudinit_iids/$my_iid
log_info "create symbol link $cloudinit_iid_link"
ln -sfn $cloudinit_iids/$my_iid $cloudinit_iid_link
log_info "create semaphore dir $cloudinit_sem"
mkdir -p $cloudinit_sem
}
load_config() {
log_info "try load config file $cloud_cfg"
source $cloud_cfg
}
is_not_run() {
test ! -e $cloudinit_sem/$1
}
mark_run() {
log_info "run $1"
$1 # run it
ret=$?
echo $ret > $cloudinit_sem/$1
log_info "$1 end with return code $ret"
}
try_run() {
if is_not_run $1 ; then
mark_run $1
else
log_info "$1 is already run in the previous time, skip"
fi
}
check_and_run() {
log_info "$2 is_enable:$1"
is_enable $1 && try_run $2
}
my_curl() {
every_key_retries=$key_retries
while [[ $every_key_retries -gt 0 ]];
do
cmd="curl --fail -s -m $max_timeout $1"
result=`$cmd`
log_info "$cmd, return result $result"
if [[ -z $result ]];then
every_key_retries=$(($every_key_retries-1))
sleep $sleep_time
else
break
fi
done
echo $result
}
#################################################################
# meta-server
get_metadata_iid() { my_curl $metadata_url/instance-id; }
get_metadata_hostname() { my_curl $metadata_url/hostname; }
get_metadata_sshkey() {
key_exist=`curl --fail -s -m $max_timeout $metadata_url/public-keys/0/`
log_info "public-kyes: $key_exist"
if [[ -n $key_exist ]];then
my_ssh_pubkey=`my_curl $metadata_url/public-keys/0/openssh-key`
fi
[[ -n "$my_ssh_pubkey" ]]
}
#################################################################
# configs
get_my_ip() {
if [[ -e /sys/class/net/eth0 ]]; then
my_ip=`ip a show dev eth0 | awk '/inet/ {print $2}' | cut -d'/' -f1`
else
my_ip=`my_curl $metadata_url/private-ipv4`
fi
[[ -n $my_ip ]]
}
get_my_hostname() {
[[ -n $my_hostname ]] && return 0
my_hostname=`get_metadata_hostname`
[[ -n $my_hostname ]]
}
config_lock_root_passwd_login() {
log_info `passwd -l root`
}
config_hostname() {
get_my_hostname || return 1
log_info "config_hostname: $my_hostname"
hostnamectl set-hostname --static $my_hostname
hostname $my_hostname
}
#only support root,encrypted
config_passwd(){
log_info "config_passwd"
sshd_config=/etc/ssh/sshd_config
if [[ -L $aliyun_cloud_cfg && -f $aliyun_cloud_cfg ]];then
if grep -q "^password:" $aliyun_cloud_cfg;then
passwd=`grep -nr "^password:" $aliyun_cloud_cfg |awk '{print $NF}'`
if [[ $passwd =~ \$(1|2a|2y|5|6)(\$.+){2} ]];then
echo "root:$passwd" | chpasswd -e
if grep -q -i "ssh_pwauth:[[:space:]]*true" $aliyun_cloud_cfg;then
sed -i '/PasswordAuthentication/d' $sshd_config
echo "PasswordAuthentication yes" >> $sshd_config
fi
log_info "success config_passwd"
return 0
fi
fi
fi
log_info "not config_passwd"
return 1
}
config_hosts() {
get_my_hostname || return 1
get_my_ip || return 1
if [[ -e /etc/hosts ]]; then
sed -i "/$my_hostname/d" /etc/hosts
sed -i "/$my_ip/d" /etc/hosts
fi
log_info "config_hosts: $my_ip $my_hostname"
echo "$my_ip $my_hostname $my_hostname" >> /etc/hosts
}
config_ssh_pub_key() {
if ! get_metadata_sshkey ; then
log_info "user not set ssh pubkey"
return 1
fi
auth_file=/root/.ssh/authorized_keys
sshd_config=/etc/ssh/sshd_config
if [[ ! -e $auth_file ]]; then
mkdir -p /root/.ssh/
echo "$my_ssh_pubkey" > $auth_file
chmod 600 $auth_file
elif ! grep -q "$my_ssh_pubkey" $auth_file; then
echo "$my_ssh_pubkey" >> $auth_file
fi
sed -i '/PasswordAuthentication/d' $sshd_config
echo "PasswordAuthentication no" >> $sshd_config
}
# ssh host key must after hostname
config_ssh_host_key() {
rm -f /etc/ssh/ssh_host_*_key*
log_info `ssh-keygen -A -N ''`
}
#################################################################
# execute user-data
config_user_data() {
if ! curl -s --fail $userdata_url -o $cloudinit_userdata_raw; then
log_info "user not set the userdata"
return 0
fi
workdir=`mktemp -d cloudinit_userdata_XXXX`
if [[ $? != 0 ]]; then
log_error "failed to create tempdir"
return 1
fi
log_info "execute userdata in $workdir"
( cd $workdir;
cp $cloudinit_userdata_raw part-00;
bash ./part-00;
)
log_info "rm -rf $workdir"
rm -rf $workdir
}
#################################################################
# main
main() {
if [[ $1 == 'version' || $1 == '--version' || $1 == '-v' ]]; then
echo "$cloudinit_name $cloudinit_version"
exit 0
fi
log_info "$cloudinit_name $cloudinit_version start"
if ! load_config; then
log_error "faild to load config file, exit"
exit 1
fi
if ! is_enable $cloudinit_enable; then
log_info "aliyun_init not enabled, exit"
exit 1
fi
if ! prepare_env; then
log_error "prepare_env failed, exit"
exit 1
fi
check_and_run $manage_hostname config_hostname
check_and_run $manage_ssh_host_key config_ssh_host_key
check_and_run $manage_ssh_pub_key config_ssh_pub_key
check_and_run $config_passwd config_passwd
log_info "$cloudinit_name $cloudinit_version finished"
}
main $@
#################################################################