Skip to content

Instantly share code, notes, and snippets.

@haruue
Last active August 14, 2021 12:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save haruue/805c2c539e028453e0d5e909d918a149 to your computer and use it in GitHub Desktop.
Save haruue/805c2c539e028453e0d5e909d918a149 to your computer and use it in GitHub Desktop.
vps2arch for aliyun swas
#!/bin/sh
# Copyright 2015, Timothy Redaelli <tredaelli@archlinux.info>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License at <http://www.gnu.org/licenses/> for
# more details.
# patched for Aliyun SWAS by Haruue Icymoon <i@haruue.moe>
set -e
# Gathering informations about actual environment.
if command -v wget >/dev/null 2>&1; then
_download() { wget -O- "$@" ; }
elif command -v curl >/dev/null 2>&1; then
_download() { curl -fL "$@" ; }
else
echo "This script needs curl or wget" >&2
exit 2
fi
get_worldwide_mirrors() {
echo "http://mirrors.kernel.org/archlinux"
_download 'https://www.archlinux.org/mirrorlist/?country=all&protocol=http&protocol=https&ip_version=4' | awk '/^## /{if ($2 == "Worldwide") { flag=1 } else { flag=0 } } /^#Server/ { if (flag) { sub(/\/\$repo.*/, ""); print $3 } }'
}
cpu_type=$(uname -m)
is_openvz() { [ -d /proc/vz -a ! -d /proc/bc ]; }
is_lxc() { grep -aqw container=lxc /proc/1/environ ; }
download() {
local path="$1" x=
shift
for x in $mirrors; do
_download "$x/$path" && return 0
done
return 1
}
download_and_extract_bootstrap() {
local sha1 filename
download iso/latest/sha1sums.txt | fgrep "$cpu_type.tar.gz" > "sha1sums.txt"
read -r sha1 filename < "sha1sums.txt"
download "iso/latest/$filename" > "$filename"
sha1sum -c sha1sums.txt || exit 1
tar -xpzf "$filename"
rm -f "$filename"
cp -L /etc/resolv.conf "/root.$cpu_type/etc"
# Mount options taked from arch-chroot script
mount -t proc proc -o nosuid,noexec,nodev "/root.$cpu_type/proc"
mount -t sysfs sys -o nosuid,noexec,nodev,ro "/root.$cpu_type/sys"
mount -t devtmpfs -o mode=0755,nosuid udev "/root.$cpu_type/dev"
mkdir -p "/root.$cpu_type/dev/pts" "/root.$cpu_type/dev/shm"
mount -t devpts -o mode=0620,gid=5,nosuid,noexec devpts "/root.$cpu_type/dev/pts"
mount -t tmpfs -o mode=1777,nosuid,nodev shm "/root.$cpu_type/dev/shm"
mount -t tmpfs -o nosuid,nodev,mode=0755 run "/root.$cpu_type/run"
mount -t tmpfs -o mode=1777,strictatime,nodev,nosuid tmp "/root.$cpu_type/tmp"
# FIXME support multiple partitions
mount --bind / "/root.$cpu_type/mnt"
findmnt /boot >/dev/null && mount --bind /boot "/root.$cpu_type/mnt/boot"
# Workaround for Debian
mkdir -p "/root.$cpu_type/run/shm"
# Workaround for OpenVZ
rm -f "/root.$cpu_type/etc/mtab"
cp -L /etc/mtab "/root.$cpu_type/etc/mtab"
}
chroot_exec() {
chroot "/root.$cpu_type" /bin/bash -c "$*"
}
configure_chroot() {
local m
for m in $mirrors; do
echo 'Server = '"$m"'/$repo/os/$arch'
done >> "/root.$cpu_type/etc/pacman.d/mirrorlist"
# Install and initialize haveged if needed
if ! is_openvz && ! pidof haveged >/dev/null; then
# Disable signature check, install and launch haveged and re-enable signature checks.
sed -i.bak "s/^[[:space:]]*SigLevel[[:space:]]*=.*$/SigLevel = Never/" "/root.$cpu_type/etc/pacman.conf"
chroot_exec 'pacman --noconfirm -Sy haveged && haveged'
mv "/root.$cpu_type/etc/pacman.conf.bak" "/root.$cpu_type/etc/pacman.conf"
fi
chroot_exec 'pacman-key --init && pacman-key --populate archlinux'
chroot_exec 'pacman --noconfirm -Sy awk'
# Generate fstab
chroot_exec 'genfstab /mnt >> /etc/fstab'
if is_openvz && [ "$kernelver" '<' '2.6.32-042stab111.1' ]; then
# Use my repository for OpenVZ-patched systemd
sed -i 's;^#\[testing\]$;[tredaelli-systemd]\nServer = http://pkgbuild.com/~tredaelli/repo/systemd/$arch\n\n&;' "/root.$cpu_type/etc/pacman.conf"
fi
}
save_root_pass() {
grep '^root:' /etc/shadow > "/root.$cpu_type/root.passwd"
chmod 0600 "/root.$cpu_type/root.passwd"
}
backup_old_files() {
cp -fL /etc/hostname /etc/localtime "/root.$cpu_type/etc/" || true
}
delete_all() {
# Remove immutable flag from any files / directories
if command -v chattr >/dev/null 2>&1; then
find / -type f \( ! -path '/dev/*' -and ! -path '/proc/*' -and ! -path '/sys/*' -and ! -path '/selinux/*' -and ! -path "/root.$cpu_type/*" \) \
-exec chattr -i {} + 2>/dev/null || true
fi
# Delete *all* files from /
find / \( ! -path '/dev/*' -and ! -path '/proc/*' -and ! -path '/sys/*' -and ! -path '/selinux/*' -and ! -path "/root.$cpu_type/*" \) -delete 2>/dev/null || true
}
install_packages() {
local packages="base openssh reflector linux linux-firmware"
[ "$bootloader" != "none" ] && packages="$packages $bootloader"
# XXX Install gptdisk for syslinux. To be removed then FS#45029 will be closed
[ "$bootloader" = "syslinux" ] && packages="$packages gptfdisk"
# this may fail for filesystem package conflict,
# but at least we will get all packages downloaded
"/root.$cpu_type/usr/lib"/ld-*.so --library-path "/root.$cpu_type/usr/lib" \
"/root.$cpu_type/usr/bin/chroot" "/root.$cpu_type" /usr/bin/pacstrap -M /mnt $packages || true
# make sure /mnt is clean again
"/root.$cpu_type/usr/lib"/ld-*.so --library-path "/root.$cpu_type/usr/lib" \
"/root.$cpu_type/usr/bin/rm" -rf /{bin,lib,lib64,sbin} || true
# install filesystem before above directories re-created
"/root.$cpu_type/usr/lib"/ld-*.so --library-path "/root.$cpu_type/usr/lib" \
"/root.$cpu_type/usr/bin/chroot" "/root.$cpu_type" /usr/bin/pacman -S --noconfirm --needed -r /mnt filesystem
# Black magic!
"/root.$cpu_type/usr/lib"/ld-*.so --library-path "/root.$cpu_type/usr/lib" \
"/root.$cpu_type/usr/bin/chroot" "/root.$cpu_type" /usr/bin/pacstrap -M /mnt \--needed $packages
cp -L "/root.$cpu_type/etc/resolv.conf" /etc
}
restore_root_pass() {
# If the root password is not set, use vps2arch
if egrep -q '^root:.?:' "/root.$cpu_type/root.passwd"; then
echo "root:vps2arch" | chpasswd
else
sed -i '/^root:/d' /etc/shadow
cat "/root.$cpu_type/root.passwd" >> /etc/shadow
fi
}
cleanup() {
mv "/root.$cpu_type/etc/fstab" "/etc/fstab"
awk "/\/root.$cpu_type/ {print \$2}" /proc/mounts | sort -r | xargs umount -nl || true
rm -rf "/root.$cpu_type/"
}
configure_bootloader() {
local root_dev=$(findmnt -no SOURCE /) root_devs= tmp= needs_lvm2=0
case $root_dev in
/dev/mapper/*) needs_lvm2=1 ;;
esac
if [ $needs_lvm2 -eq 1 ]; then
# Some distro doesn't use lvmetad by default
sed -i.bak 's/use_lvmetad = 1/use_lvmetad = 0/g' /etc/lvm/lvm.conf
fi
if [ "$bootloader" = "grub" ]; then
# If you are still using eth* as interface name, disable "strange" ifnames
grep -q '^[[:space:]]*eth' /proc/net/dev && \
sed -i.bak 's/GRUB_CMDLINE_LINUX_DEFAULT="/&net.ifnames=0 /' /etc/default/grub
if [ $needs_lvm2 -eq 1 ]; then
local vg
vg=$(lvs --noheadings $root_dev | awk '{print $2}')
root_dev=$(pvs --noheadings | awk -v vg="$vg" '($2 == vg) { print $1 }')
fi
for root_dev in $root_dev; do
tmp=$(lsblk -npsro TYPE,NAME "$root_dev" | awk '($1 == "disk") { print $2}')
case " $root_devs " in
*" $tmp "*) ;;
*) root_devs="${root_devs:+$root_devs }$tmp" ;;
esac
done
# default initramfs won't work
sed -i 's/default_options=.*/default_options="-S autodetect"/' /etc/mkinitcpio.d/linux.preset
mkinitcpio -p linux
# i don't know why this directory does not exist
mkdir -p /boot/grub
grub-mkconfig > /boot/grub/grub.cfg
for root_dev in $root_devs; do
grub-install --target=i386-pc --recheck --force "$root_dev"
done
elif [ "$bootloader" = "syslinux" ]; then
# If you are still using eth* as interface name, disable "strange" ifnames
grep -q '^[[:space:]]*eth' /proc/net/dev && tmp="net.ifnames=0"
syslinux-install_update -ami
sed -i "s;\(^[[:space:]]*APPEND.*\)root=[^[:space:]]*;\1root=$root_dev${tmp:+ $tmp};" /boot/syslinux/syslinux.cfg
fi
if [ $needs_lvm2 -eq 1 ]; then
mv /etc/lvm/lvm.conf.bak /etc/lvm/lvm.conf
sed -i '/HOOKS/s/block/& lvm2/' /etc/mkinitcpio.conf
mkinitcpio -p linux
fi
}
configure_network() {
local gateway dev ip
read -r dev gateway <<-EOF
$(awk '$2 == "00000000" { ip = strtonum(sprintf("0x%s", $3));
printf ("%s\t%d.%d.%d.%d", $1,
rshift(and(ip,0x000000ff),00), rshift(and(ip,0x0000ff00),08),
rshift(and(ip,0x00ff0000),16), rshift(and(ip,0xff000000),24)) ; exit }' < /proc/net/route)
EOF
set -- $(ip addr show dev "$dev" | awk '($1 == "inet") { print $2 }')
ip=$@
# FIXME Not supported for "P2P" interfaces, such as venet, yet
if [ "$network" = "systemd-networkd" ]; then
cat > /etc/systemd/network/default.network <<-EOF
[Match]
Name=$dev
[Network]
Gateway=$gateway
EOF
for ip in $ip; do
echo "Address=$ip"
done >> /etc/systemd/network/default.network
systemctl enable systemd-networkd
elif [ "$network" = "netctl" ]; then
cat > /etc/netctl/default <<-EOF
Interface=$dev
Connection=ethernet
IP=static
Address=($ip)
EOF
if [ "$gateway" = "0.0.0.0" ]; then
echo 'Routes=(0.0.0.0/0)'
else
echo "Gateway=$gateway"
fi >> /etc/netctl/default
netctl enable default
fi
systemctl enable sshd
}
finalize() {
# OpenVZ hacks
if is_openvz; then
local kernelver
read -r _ _ kernelver _ < /proc/version
if [ "$kernelver" '>' '3.10' ]; then
# Virtuozzo 7 works with systemd, but it needs /etc/resolvconf/resolv.conf.d directory
mkdir -p /etc/resolvconf/resolv.conf.d
elif [ "$kernelver" '<' '2.6.32-042stab111.1' ]; then
# Use my repository for OpenVZ-patched systemd
sed -i 's;^#\[testing\]$;[tredaelli-systemd]\nServer = http://pkgbuild.com/~tredaelli/repo/systemd/$arch\n\n&;' /etc/pacman.conf
fi
fi
# Enable SSH login for user root (#3)
sed -i '/^#PermitRootLogin\s/s/.*/&\nPermitRootLogin yes/' /etc/ssh/sshd_config
# Run reflector to get updated mirrors
cat <<-EOF
Reflector: Rating the 35 most recently synced HTTPS servers, sorting them by download speed
EOF
reflector -l 35 -p https --sort rate --save /etc/pacman.d/mirrorlist
cat <<-EOF
Hi,
your VM has successfully been reimaged with Arch Linux.
This script configured $bootloader as bootloader and $network for networking.
When you are finished with your post-installation, you'll need to reboot the VM the rough way:
# sync ; reboot -f
Then you'll be able to connect to your VM using SSH and to login using your old root password (or "vps2arch" if you didn't have a root password).
EOF
}
bootloader=grub
network=systemd-networkd
mirrors=
while getopts ":b:m:n:h" opt; do
case $opt in
b)
if ! [ "$OPTARG" = "grub" -o "$OPTARG" = "syslinux" -o "$OPTARG" = "none" ]; then
echo "Invalid bootloader specified" >&2
exit 1
fi
bootloader="$OPTARG"
;;
m)
mirrors="${mirrors:+$mirrors }$OPTARG"
;;
n)
if ! [ "$OPTARG" = "systemd-networkd" -o "$OPTARG" = "netctl" -o "$OPTARG" = "none" ]; then
echo "Invalid networking configuration system specified" >&2
exit 1
fi
network="$OPTARG"
;;
h)
cat <<-EOF
usage: ${0##*/} [options]
Options:
-b (grub|syslinux) Use the specified bootloader. When this option is omitted, it defaults to grub.
-n (systemd-networkd|netctl) Use the specified networking configuration system. When this option is omitted, it defaults to systemd-networkd.
-m mirror Use the provided mirror (you can specify this option more than once).
-h Print this help message
Warning:
On OpenVZ containers the bootloader will be not installed and the networking configuration system will be enforced to netctl.
EOF
exit 0
;;
:)
printf "%s: option requires an argument -- '%s'\n" "${0##*/}" "$OPTARG" >&2
exit 1
;;
?)
printf "%s: invalid option -- '%s'\n" "${0##*/}" "$OPTARG" >&2
exit 1
;;
esac
done
shift $((OPTIND - 1))
[ -z "$mirrors" ] && mirrors=$(get_worldwide_mirrors)
if is_openvz; then
bootloader=none
network=netctl
elif is_lxc; then
bootloader=none
fi
cd /
download_and_extract_bootstrap
configure_chroot
save_root_pass
backup_old_files
delete_all
install_packages
restore_root_pass
cleanup
configure_bootloader
configure_network
finalize
@haruue
Copy link
Author

haruue commented Aug 14, 2021

此脚本已经很久没有维护, 有可能的话请尽可能使用原版 vps2arch 。
关于最初为 swas 修改 vps2arch 的原因请看 https://t.me/s/HaruueIcymoon/296

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment