From 4149cf2e6e6e912dc782f8d2d3f7d805a15c6ee8 Mon Sep 17 00:00:00 2001 From: bin456789 Date: Fri, 10 Jan 2025 00:43:26 +0800 Subject: [PATCH] =?UTF-8?q?core:=20=E4=B8=8D=E4=BD=BF=E7=94=A8=20cloud-ini?= =?UTF-8?q?t=20=E5=88=9D=E5=A7=8B=E5=8C=96=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cloud-init-fix-onlink.sh | 45 +++- debian.cfg | 6 +- fix-eth-name.initd | 26 ++ fix-eth-name.service | 27 ++ fix-eth-name.sh | 239 +++++++++++++++++ reinstall.sh | 15 +- trans.sh | 536 +++++++++++++++++++++++++++++++-------- 7 files changed, 770 insertions(+), 124 deletions(-) create mode 100644 fix-eth-name.initd create mode 100644 fix-eth-name.service create mode 100644 fix-eth-name.sh diff --git a/cloud-init-fix-onlink.sh b/cloud-init-fix-onlink.sh index 55ea03f..6376618 100644 --- a/cloud-init-fix-onlink.sh +++ b/cloud-init-fix-onlink.sh @@ -2,6 +2,23 @@ # 修复 cloud-init 没有正确渲染 onlink 网关 set -eE +os_dir=$1 + +# 该脚本也会在 alpine live 下调用 +# 防止在 alpine live 下运行 systemctl netplan 报错 +systemctl() { + if systemd-detect-virt --chroot; then + return + fi + command systemctl "$@" +} + +netplan() { + if systemd-detect-virt --chroot; then + return + fi + command netplan "$@" +} insert_into_file() { file=$1 @@ -44,24 +61,24 @@ fix_netplan_conf() { # - to: ::/0 # via: ::1 # on-link: true - conf=/etc/netplan/50-cloud-init.yaml - if ! [ -f $conf ]; then + conf=$os_dir/etc/netplan/50-cloud-init.yaml + if ! [ -f "$conf" ]; then return fi # 判断 bug 是否已经修复 - if grep 'on-link:' "$conf"; then + if grep -q 'on-link:' "$conf"; then return fi # 获取网关 - gateways=$(grep 'gateway[4|6]:' $conf | awk '{print $2}') + gateways=$(grep 'gateway[4|6]:' "$conf" | awk '{print $2}') if [ -z "$gateways" ]; then return fi # 获取缩进 - spaces=$(grep 'gateway[4|6]:' $conf | head -1 | grep -o '^[[:space:]]*') + spaces=$(grep 'gateway[4|6]:' "$conf" | head -1 | grep -o '^[[:space:]]*') { # 网关头部 @@ -82,14 +99,14 @@ ${spaces} via: $gateway ${spaces} on-link: true EOF done - } | insert_into_file $conf before 'match:' + } | insert_into_file "$conf" before 'match:' # 删除原来的条目 - sed -i '/gateway[4|6]:/d' $conf + sed -i '/gateway[4|6]:/d' "$conf" # 重新应用配置 if command -v netplan && { - systemctl is-enabled systemd-networkd || systemctl is-enabled NetworkManager + systemctl -q is-enabled systemd-networkd || systemctl -q is-enabled NetworkManager }; then netplan apply fi @@ -117,13 +134,13 @@ fix_networkd_conf() { # Gateway=2602::1 # GatewayOnLink=yes - if ! confs=$(ls /etc/systemd/network/10-cloud-init-*.network 2>/dev/null); then + if ! confs=$(ls "$os_dir"/etc/systemd/network/10-cloud-init-*.network 2>/dev/null); then return fi for conf in $confs; do # 判断 bug 是否已经修复 - if grep '^GatewayOnLink=' "$conf"; then + if grep -q '^GatewayOnLink=' "$conf"; then return fi @@ -148,7 +165,7 @@ GatewayOnLink=yes # 重新应用配置 # networkctl reload 不起作用 - if systemctl is-enabled systemd-networkd; then + if systemctl -q is-enabled systemd-networkd; then systemctl restart systemd-networkd fi } @@ -166,13 +183,13 @@ fix_wicked_conf() { # default 1.1.1.1 - - # default 2602::1 - - - if ! confs=$(ls /etc/sysconfig/network/ifroute-* 2>/dev/null); then + if ! confs=$(ls "$os_dir/etc/sysconfig/network/ifroute-"* 2>/dev/null); then return fi for conf in $confs; do # 判断 bug 是否已经修复 - if grep -v 'default' "$conf" | grep '-'; then + if grep -v 'default' "$conf" | grep -q '-'; then return fi @@ -189,7 +206,7 @@ fix_wicked_conf() { done # 重新应用配置 - if systemctl is-enabled wicked; then + if systemctl -q is-enabled wicked; then systemctl restart wicked fi } diff --git a/debian.cfg b/debian.cfg index b0d9b14..0731e65 100644 --- a/debian.cfg +++ b/debian.cfg @@ -177,4 +177,8 @@ d-i preseed/late_command string true; \ if [ -n "$ssh_port" ] && ! [ "$ssh_port" = 22 ]; then \ echo "Port $ssh_port" >/target/etc/ssh/sshd_config.d/01-change-ssh-port.conf || \ echo "Port $ssh_port" >>/target/etc/ssh/sshd_config; \ - fi + fi; \ + + cp /fix-eth-name.sh /target/; \ + cp /fix-eth-name.service /target/etc/systemd/system/; \ + in-target systemctl enable fix-eth-name diff --git a/fix-eth-name.initd b/fix-eth-name.initd new file mode 100644 index 0000000..b70adbe --- /dev/null +++ b/fix-eth-name.initd @@ -0,0 +1,26 @@ +#!/sbin/openrc-run + +Description="Fix Eth Name" + +# https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/main/openrc/networking.initd +# https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/main/dhcpcd/dhcpcd.initd +depend() { + need localmount + want dev-settle + + after bootmisc hwdrivers modules + before net networking dhcpcd +} + +start() { + ebegin "Fix Eth Name" + ash /fix-eth-name.sh + eend $? +} + +start_post() { + rc-service fix-eth-name zap + rc-update del fix-eth-name boot + rm -f /etc/init.d/fix-eth-name + rm -f /fix-eth-name.sh +} diff --git a/fix-eth-name.service b/fix-eth-name.service new file mode 100644 index 0000000..56838b1 --- /dev/null +++ b/fix-eth-name.service @@ -0,0 +1,27 @@ +[Unit] +Description=Fix Eth Name +ConditionPathExists=/fix-eth-name.sh + +After=dbus.service + +Before=cloud-init-local.service +Before=network.service +Before=networking.service +Before=systemd-networkd.service +Before=NetworkManager.service +Before=wickedd-auto4.service +Before=wickedd-dhcp4.service +Before=wickedd-dhcp6.service +Before=wickedd.service + +Before=network.target + +[Service] +Type=oneshot +ExecStart=/usr/bin/env bash /fix-eth-name.sh +ExecStart=/usr/bin/env rm -f /fix-eth-name.sh +ExecStart=/usr/bin/env rm -f /etc/systemd/system/fix-eth-name.service +ExecStart=/usr/bin/env rm -f /etc/systemd/system/multi-user.target.wants/fix-eth-name.service + +[Install] +WantedBy=multi-user.target diff --git a/fix-eth-name.sh b/fix-eth-name.sh new file mode 100644 index 0000000..aa13398 --- /dev/null +++ b/fix-eth-name.sh @@ -0,0 +1,239 @@ +#!/usr/bin/env bash +# shellcheck shell=dash +# shellcheck disable=SC3001,SC3010 +# alpine 使用 busybox ash + +set -eE + +# 本脚本在首次进入新系统后运行 +# 将 trans 阶段生成的网络配置中的网卡名(eth0) 改为正确的网卡名,也适用于以下情况 +# 1. alpine 要运行此脚本,因为安装后的内核可能有 netboot 没有的驱动 +# 2. dmit debian 普通内核(安装时)和云内核网卡名不一致 +# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=928923 + +# todo: 删除 cloud-init + +to_lower() { + tr '[:upper:]' '[:lower:]' +} + +retry() { + local max_try=$1 + local interval=$2 + shift 2 + + for i in $(seq "$max_try"); do + if "$@"; then + return + else + ret=$? + if [ "$i" -ge "$max_try" ]; then + return $ret + fi + sleep "$interval" + fi + done +} + +# openeuler 本脚本运行一秒后才有 enp3s0 +# 用 systemd-analyze plot >a.svg 发现 sys-subsystem-net-devices-enp3s0.device 也是出现在 NetworkManager 之后 +# 因此需要等待网卡出现 +get_ethx_by_mac() { + mac=$(echo "$1" | to_lower) + retry 10 0.5 _get_ethx_by_mac "$mac" +} + +_get_ethx_by_mac() { + if true; then + # 过滤 azure vf (带 master ethx) + ip -o link | grep -i "$mac" | grep -v master | awk '{print $2}' | cut -d: -f1 | grep . + return + else + for i in $(cd /sys/class/net && echo *); do + if [ "$(cat "/sys/class/net/$i/address")" = "$mac" ]; then + echo "$i" + return + fi + done + return 1 + fi +} + +fix_rh_sysconfig() { + for file in /etc/sysconfig/network-scripts/ifcfg-eth*; do + # 没有 ifcfg-eth* 也会执行一次,因此要判断文件是否存在 + [ -f "$file" ] || continue + mac=$(grep ^HWADDR= "$file" | cut -d= -f2 | grep .) || continue + ethx=$(get_ethx_by_mac "$mac") || continue + + proper_file=/etc/sysconfig/network-scripts/ifcfg-$ethx + if [ "$file" != "$proper_file" ]; then + # 更改文件内容 + sed -i "s/^DEVICE=.*/DEVICE=$ethx/" "$file" + + # 不要直接更改文件名,因为可能覆盖已有文件 + mv "$file" "$proper_file.tmp" + fi + done + + # 更改文件名 + for tmp_file in /etc/sysconfig/network-scripts/ifcfg-e*.tmp; do + if [ -f "$tmp_file" ]; then + mv "$tmp_file" "${tmp_file%.tmp}" + fi + done +} + +fix_suse_sysconfig() { + for file in /etc/sysconfig/network/ifcfg-eth*; do + [ -f "$file" ] || continue + + # 可能两边有引号 + mac=$(grep ^LLADDR= "$file" | cut -d= -f2 | sed "s/'//g" | grep .) || continue + ethx=$(get_ethx_by_mac "$mac") || continue + + old_ethx=${file##*-} + if ! [ "$old_ethx" = "$ethx" ]; then + # 不要直接更改文件名,因为可能覆盖已有文件 + for type in ifcfg ifroute; do + old_file=/etc/sysconfig/network/$type-$old_ethx + new_file=/etc/sysconfig/network/$type-$ethx.tmp + # 防止没有 ifroute-eth* 导致中断脚本 + if [ -f "$old_file" ]; then + mv "$old_file" "$new_file" + fi + done + fi + done + + # 上面的循环结束后,再将 tmp 改成正式文件 + for tmp_file in \ + /etc/sysconfig/network/ifcfg-e*.tmp \ + /etc/sysconfig/network/ifroute-e*.tmp; do + if [ -f "$tmp_file" ]; then + mv "$tmp_file" "${tmp_file%.tmp}" + fi + done +} + +fix_network_manager() { + for file in /etc/NetworkManager/system-connections/cloud-init-eth*.nmconnection; do + [ -f "$file" ] || continue + mac=$(grep ^mac-address= "$file" | cut -d= -f2 | grep .) || continue + ethx=$(get_ethx_by_mac "$mac") || continue + + proper_file=/etc/NetworkManager/system-connections/$ethx.nmconnection + + # 更改文件内容 + sed -i "s/^id=.*/id=$ethx/" "$file" + + # 更改文件名 + mv "$file" "$proper_file" + done +} + +# auto lo +# iface lo inet loopback + +# # mac 11:22:33:44:55:66 # 用此行匹配网卡 +# auto eth0 +# iface eth0 inet static +# address 1.1.1.1/25 +# gateway 1.1.1.1 +# dns-nameservers 1.1.1.1 +# dns-nameservers 8.8.8.8 +# iface eth0 inet6 static +# address 2602:1:0:80::100/64 +# gateway 2602:1:0:80::1 +# dns-nameserver 2606:4700:4700::1111 +# dns-nameserver 2001:4860:4860::8888 + +fix_ifupdown() { + file=/etc/network/interfaces + tmp_file=$file.tmp + + rm -f "$tmp_file" + + if [ -f "$file" ]; then + while IFS= read -r line; do + del_this_line=false + if [[ "$line" = "# mac "* ]]; then + ethx= + if mac=$(echo "$line" | awk '{print $NF}'); then + ethx=$(get_ethx_by_mac "$mac") || true + fi + del_this_line=true + elif [[ "$line" = "iface e"* ]] || + [[ "$line" = "auto e"* ]] || + [[ "$line" = "allow-hotplug e"* ]]; then + if [ -n "$ethx" ]; then + line=$(echo "$line" | awk "{\$2=\"$ethx\"; print \$0}") + fi + fi + if ! $del_this_line; then + echo "$line" >>"$tmp_file" + fi + done <"$file" + + mv "$tmp_file" "$file" + fi +} + +fix_netplan() { + file=/etc/netplan/50-cloud-init.yaml + tmp_file=$file.tmp + + rm -f "$tmp_file" + + if [ -f "$file" ]; then + while IFS= read -r line; do + if echo "$line" | grep -Eq '^[[:space:]]+macaddress:'; then + # 得到正确的网卡名 + mac=$(echo "$line" | awk '{print $NF}' | sed 's/"//g') + ethx=$(get_ethx_by_mac "$mac") || true + elif echo "$line" | grep -Eq '^[[:space:]]+eth[0-9]+:'; then + # 改成正确的网卡名 + if [ -n "$ethx" ]; then + line=$(echo "$line" | sed -E "s/[^[:space:]]+/$ethx:/") + fi + fi + echo "$line" >>"$tmp_file" + + # 删除 set-name 不过这一步在 trans 已完成 + # 因为 netplan-generator 会在 systemd generator 阶段就根据 netplan 配置重命名网卡 + # systemd generator 阶段比本脚本和 systemd-networkd 更早运行 + + # 倒序 + done < <(grep -Ev "^[[:space:]]+set-name:" "$file" | tac) + + # 再倒序回来 + tac "$tmp_file" >"$file" + rm -f "$tmp_file" + + # 通过 systemd netplan generator 生成 /run/systemd/network/10-netplan-enp3s0.network + systemctl daemon-reload + fi +} + +fix_systemd_networkd() { + for file in /etc/systemd/network/10-cloud-init-eth*.network; do + [ -f "$file" ] || continue + mac=$(grep ^MACAddress= $file | cut -d= -f2 | grep .) || continue + ethx=$(get_ethx_by_mac "$mac") || continue + + proper_file=/etc/systemd/network/10-$ethx.network + + # 更改文件内容 + sed -Ei "s/^Name=eth[0-9]+/Name=$ethx/" "$file" + + # 更改文件名 + mv "$file" "$proper_file" + done +} + +fix_rh_sysconfig +fix_suse_sysconfig +fix_network_manager +fix_ifupdown +fix_netplan +fix_systemd_networkd diff --git a/reinstall.sh b/reinstall.sh index 8c3433b..9b19085 100644 --- a/reinstall.sh +++ b/reinstall.sh @@ -1059,8 +1059,17 @@ setos() { # debian --ci 用此标记要是否要换 elts 源 # shellcheck disable=SC2034 is_debian_elts && elts=1 || elts=0 - is_virt && ci_type=genericcloud || ci_type=generic + + # https://salsa.debian.org/cloud-team/debian-cloud-images/-/tree/master/config_space/bookworm/files/etc/default/grub.d + # cloud 包括各种奇怪的优化,例如不显示 grub 菜单 + # 因此使用 nocloud + if false; then + is_virt && ci_type=genericcloud || ci_type=generic + else + ci_type=nocloud + fi eval ${step}_img=$cdimage_mirror/cloud/$codename/latest/debian-$releasever-$ci_type-$basearch_alt.qcow2 + eval ${step}_kernel=linux-image$flavour-$basearch_alt else # 传统安装 if is_debian_elts; then @@ -2976,6 +2985,10 @@ EOF # 在 debian installer 中判断能否用云内核 create_can_use_cloud_kernel_sh can_use_cloud_kernel.sh + # 下载 fix-eth-name 脚本 + curl -LO "$confhome/fix-eth-name.sh" + curl -LO "$confhome/fix-eth-name.service" + # 最近 kali initrd 删除了原版 wget # 但 initrd 的 busybox wget 又不支持 https # 因此改成在这里下载 diff --git a/trans.sh b/trans.sh index 2742d9f..6ddea31 100644 --- a/trans.sh +++ b/trans.sh @@ -879,15 +879,14 @@ EOF # ethx for ethx in $(get_eths); do mode=auto - enpx= if is_distro_like_debian; then if [ -f /etc/network/devhotplug ] && grep -wo "$ethx" /etc/network/devhotplug; then mode=allow-hotplug fi - if is_have_cmd udevadm; then - enpx=$(udevadm test-builtin net_id /sys/class/net/$ethx 2>&1 | grep ID_NET_NAME_PATH= | cut -d= -f2) - fi + # if is_have_cmd udevadm; then + # enpx=$(udevadm test-builtin net_id /sys/class/net/$ethx 2>&1 | grep ID_NET_NAME_PATH= | cut -d= -f2) + # fi fi # dmit debian 普通内核和云内核网卡名不一致,因此需要 rename @@ -897,11 +896,12 @@ EOF # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=928923 # 头部 + get_netconf_to mac_addr { echo - if [ -n "$enpx" ] && [ "$enpx" != "$ethx" ]; then - echo rename $enpx=$ethx - fi + # 这是标记,fix-eth-name 要用,不要删除 + # shellcheck disable=SC2154 + echo "# mac $mac_addr" echo $mode $ethx } >>$conf_file @@ -1256,6 +1256,12 @@ install_alpine() { chroot /os setup-timezone -i Asia/Shanghai chroot /os setup-ntp chrony || true + # 下载 fix-eth-name + download "$confhome/fix-eth-name.sh" /os/fix-eth-name.sh + download "$confhome/fix-eth-name.initd" /os/etc/init.d/fix-eth-name + chmod +x /os/etc/init.d/fix-eth-name + chroot /os rc-update add fix-eth-name boot + # 安装固件微码会触发 grub-probe # 如果没挂载会报错 # Executing grub-2.12-r5.trigger @@ -1540,6 +1546,64 @@ EOF show_nixos_config } +basic_init() { + os_dir=$1 + + # 此时不能用 + # chroot $os_dir timedatectl set-timezone Asia/Shanghai + # Failed to create bus connection: No such file or directory + + # debian 11 没有 systemd-firstboot + if is_have_cmd_on_disk $os_dir systemd-firstboot; then + if chroot $os_dir systemd-firstboot --help | grep -wq '\--force'; then + chroot $os_dir systemd-firstboot --timezone=Asia/Shanghai --force + else + chroot $os_dir systemd-firstboot --timezone=Asia/Shanghai + fi + fi + + # gentoo 不会自动创建 machine-id + clear_machine_id $os_dir + + # sshd + chroot $os_dir ssh-keygen -A + + sshd_enabled=false + sshs="sshd.service ssh.service sshd.socket ssh.socket" + for i in $sshs; do + if chroot $os_dir systemctl -q is-enabled $i; then + sshd_enabled=true + break + fi + done + if ! $sshd_enabled; then + for i in $sshs; do + if chroot $os_dir systemctl -q enable $i; then + break + fi + done + fi + + allow_root_password_login $os_dir + allow_password_login $os_dir + if is_need_change_ssh_port; then + change_ssh_port $os_dir $ssh_port + fi + + # 修改密码 + change_root_password $os_dir + + # 下载 fix-eth-name.service + # 即使开了 net.ifnames=0 也需要 + # 因为 alpine 和目标系统的网卡顺序可能不同 + + # 无需执行 systemctl daemon-reload + # 因为 chroot 下执行会提示 Running in chroot, ignoring command 'daemon-reload' + download "$confhome/fix-eth-name.sh" "$os_dir/fix-eth-name.sh" + download "$confhome/fix-eth-name.service" "$os_dir/etc/systemd/system/fix-eth-name.service" + chroot "$os_dir" systemctl enable fix-eth-name +} + install_arch_gentoo() { info "install $distro" @@ -1777,15 +1841,24 @@ EOF # 第二次运行会报错 useradd systemd-network || true create_cloud_init_network_config net.cfg + cat -n net.cfg # 正常应该是 -D gentoo,但 alpine 的 cloud-init 包缺少 gentoo 配置 cloud-init devel net-convert -p net.cfg -k yaml -d out -D alpine -O networkd cp out/etc/systemd/network/10-cloud-init-eth*.network $os_dir/etc/systemd/network/ - rm -rf out + + # 删除 cloud-init + rm -rf net.cfg out + apk del cloud-init # 删除网卡名匹配 sed -i '/^Name=/d' $os_dir/etc/systemd/network/10-cloud-init-eth*.network - rm -rf net.cfg - apk del cloud-init + + # 下载 fix-eth-name.service + # chroot 下执行 systemctl daemon-reload + # 会提示 Running in chroot, ignoring command 'daemon-reload' + download "$confhome/fix-eth-name.sh" "$os_dir/fix-eth-name.sh" + download "$confhome/fix-eth-name.service" "$os_dir/etc/systemd/system/fix-eth-name.service" + chroot "$os_dir" systemctl enable fix-eth-name # arch gentoo 网络配置是用 alpine cloud-init 生成的 # cloud-init 版本够新,因此无需修复 onlink 网关 @@ -2270,6 +2343,10 @@ create_cloud_init_network_config() { fi apk del "$(get_yq_name)" + + # 查看文件 + info "Cloud-init network config" + cat -n $ci_file >&2 } # 实测没用,生成的 machine-id 是固定的 @@ -2470,6 +2547,11 @@ restore_resolv_conf() { fi } +keep_now_resolv_conf() { + os_dir=$1 + rm -f $os_dir/etc/resolv.conf.orig +} + # 抄 https://github.com/alpinelinux/alpine-conf/blob/3.18.1/setup-disk.in#L421 get_alpine_firmware_pkgs() { # 需要有 modloop,不然 modinfo 会报错 @@ -2539,6 +2621,63 @@ get_ucode_firmware_pkgs() { esac } +chroot_systemctl_disable() { + os_dir=$1 + shift + + for unit in "$@"; do + # 如果传进来的是x(没有.) 则改成 x.service + if ! [[ "$unit" = "*.*" ]]; then + unit=$i.service + fi + + # debian 10 返回值始终是 0 + if ! chroot $os_dir systemctl list-unit-files "$unit" 2>&1 | grep -Eq '^0 unit'; then + chroot $os_dir systemctl disable "$unit" + fi + done +} + +disable_cloud_init() { + os_dir=$1 + info "Disable Cloud-Init" + + # 两种方法都可以 + + if [ -d $os_dir/etc/cloud ]; then + touch $os_dir/etc/cloud/cloud-init.disabled + fi + + for name in cloud-init-local cloud-init cloud-config cloud-final; do + for type in service socket; do + # 服务不存在时会报错 + chroot $os_dir systemctl disable "$name.$type" 2>/dev/null || true + done + done +} + +create_network_manager_config() { + source_cfg=$1 + os_dir=$2 + info "Create Network-Manager config" + + # 可以直接用 alpine 的 cloud-init 生成 Network Manager 配置 + apk add cloud-init + cloud-init devel net-convert -p "$source_cfg" -k yaml -d /out -D alpine -O network-manager + sed -i -e '/^may-fail=/d' -e 's/^method=dhcp/method=auto/' \ + /out/etc/NetworkManager/system-connections/cloud-init-eth*.nmconnection + + cp /out/etc/NetworkManager/system-connections/cloud-init-eth*.nmconnection $os_dir/etc/NetworkManager/system-connections/ + + rm -rf /out + apk del cloud-init + + # 最终显示文件 + for file in "$os_dir"/etc/NetworkManager/system-connections/cloud-init-eth*.nmconnection; do + cat -n "$file" >&2 + done +} + modify_linux() { os_dir=$1 info "Modify Linux" @@ -2565,11 +2704,10 @@ EOF done } - download_cloud_init_config $os_dir + # 部分镜像有默认配置,例如 centos + del_exist_sysconfig_NetworkManager_config $os_dir - clear_machine_id $os_dir - - # el/ol/fedora/国产fork + # 仅 fedora (el/ol/国产fork 用的是复制文件方法) # 1. 禁用 selinux kdump # 2. 添加微码+固件 if [ -f $os_dir/etc/redhat-release ]; then @@ -2578,7 +2716,15 @@ EOF mount_pseudo_fs $os_dir cp_resolv_conf $os_dir + disable_cloud_init $os_dir + + # 可以直接用 alpine 的 cloud-init 生成 Network Manager 配置 + create_cloud_init_network_config /net.cfg + create_network_manager_config /net.cfg "$os_dir" + rm /net.cfg + disable_selinux_kdump $os_dir + if fw_pkgs=$(get_ucode_firmware_pkgs) && [ -n "$fw_pkgs" ]; then is_have_cmd_on_disk $os_dir dnf && mgr=dnf || mgr=yum chroot $os_dir $mgr install -y $fw_pkgs @@ -2594,13 +2740,15 @@ EOF # 注意 ubuntu 也有 /etc/debian_version if [ "$distro" = debian ]; then # 修复 onlink 网关 - add_onlink_script_if_need + # add_onlink_script_if_need mount_pseudo_fs $os_dir cp_resolv_conf $os_dir find_and_mount /boot find_and_mount /boot/efi + disable_cloud_init $os_dir + # 获取当前开启的 Components, 后面要用 if [ -f $os_dir/etc/apt/sources.list.d/debian.sources ]; then comps=$(grep ^Components: $os_dir/etc/apt/sources.list.d/debian.sources | head -1 | cut -d' ' -f2-) @@ -2674,32 +2822,73 @@ EOF chroot_apt_install $os_dir $fw_pkgs fi - if [ "$releasever" -le 11 ]; then - chroot $os_dir apt-get update + # genericcloud 删除以下文件开机时才会显示 grub 菜单 + # https://salsa.debian.org/cloud-team/debian-cloud-images/-/tree/master/config_space/bookworm/files/etc/default/grub.d + rm -f $os_dir/etc/default/grub.d/10_cloud.cfg + rm -f $os_dir/etc/default/grub.d/15_timeout.cfg + chroot $os_dir update-grub - if true; then - # 将 debian 11 设置为 12 一样的网络管理器 - # 可解决 ifupdown dhcp 不支持 24位掩码+不规则网关的问题 - chroot_apt_install $os_dir netplan.io - chroot $os_dir systemctl disable networking resolvconf - chroot $os_dir systemctl enable systemd-networkd systemd-resolved - rm_resolv_conf $os_dir - ln -sf ../run/systemd/resolve/stub-resolv.conf $os_dir/etc/resolv.conf + if true; then + # 如果使用 nocloud 镜像 + chroot_apt_install $os_dir openssh-server + else + # 如果使用 genericcloud 镜像 + + # 还原默认配置并创建 key + # cat $os_dir/usr/share/openssh/sshd_config $os_dir/etc/ssh/sshd_config + # chroot $os_dir ssh-keygen -A + rm -rf $os_dir/etc/ssh/sshd_config + UCF_FORCE_CONFFMISS=1 chroot $os_dir dpkg-reconfigure openssh-server + fi + + # 镜像自带的网络管理器 + # debian 11 ifupdown + # debian 12 netplan + networkd + resolved + # ifupdown dhcp 不支持 24位掩码+不规则网关? + + # 强制使用 netplan + if false && is_have_cmd_on_disk $os_dir netplan; then + chroot_apt_install $os_dir netplan.io + # 服务不存在时会报错 + chroot $os_dir systemctl disable networking resolvconf 2>/dev/null || true + chroot $os_dir systemctl enable systemd-networkd systemd-resolved + rm_resolv_conf $os_dir + ln -sf ../run/systemd/resolve/stub-resolv.conf $os_dir/etc/resolv.conf + if [ -f "$os_dir/etc/cloud/cloud.cfg.d/99_fallback.cfg" ]; then insert_into_file $os_dir/etc/cloud/cloud.cfg.d/99_fallback.cfg after '#cloud-config' </dev/null || true + + chroot_apt_install $os_dir ifupdown + chroot_apt_remove $os_dir resolvconf netplan.io systemd-resolved + chroot_apt_autoremove $os_dir + chroot $os_dir systemctl enable networking + + # 静态时 networking 服务不会根据 /etc/network/interfaces 更新 resolv.conf + # 动态时使用了 isc-dhcp-client 支持自动更新 resolv.conf + # 另外 debian iso 不会安装 rdnssd + keep_now_resolv_conf $os_dir fi # opensuse @@ -2713,16 +2902,53 @@ EOF find_and_mount /boot find_and_mount /boot/efi + disable_cloud_init $os_dir + # opensuse leap if grep opensuse-leap $os_dir/etc/os-release; then - # 修复 onlink 网关 - add_onlink_script_if_need + + # sysconfig ifcfg + create_cloud_init_network_config $os_dir/net.cfg + chroot $os_dir cloud-init devel net-convert \ + -p /net.cfg -k yaml -d out -D opensuse -O sysconfig + + # sysconfig ifroute + # 包括了修复 onlink 网关 + for ethx in $(get_eths); do + for prefix in '' 'default '; do + if is_staticv4; then + get_netconf_to ipv4_gateway + echo "${prefix}${ipv4_gateway} - -" >>$os_dir/out/etc/sysconfig/network/ifroute-$ethx + fi + if is_staticv6; then + get_netconf_to ipv6_gateway + echo "${prefix}${ipv6_gateway} - -" >>$os_dir/out/etc/sysconfig/network/ifroute-$ethx + fi + done + done + + for file in \ + "$os_dir/out/etc/sysconfig/network/ifcfg-eth"* \ + "$os_dir/out/etc/sysconfig/network/ifroute-eth"*; do + # 动态 ip 没有 ifroute-eth* + if [ -f $file ]; then + cp $file $os_dir/etc/sysconfig/network/ + fi + done + rm -rf $os_dir/net.cfg $os_dir/out fi # opensuse tumbleweed - # 更新到 cloud-init 24.1 后删除 + # network-manager if grep opensuse-tumbleweed $os_dir/etc/os-release; then - touch $os_dir/etc/NetworkManager/NetworkManager.conf + # 如果使用 cloud-init 则需要 touch NetworkManager.conf + # 更新到 cloud-init 24.1 后删除 + # touch $os_dir/etc/NetworkManager/NetworkManager.conf + + # 可以直接用 alpine 的 cloud-init 生成 Network Manager 配置 + create_cloud_init_network_config /net.cfg + create_network_manager_config /net.cfg "$os_dir" + rm /net.cfg fi # 不能同时装 kernel-default-base 和 kernel-default @@ -2810,10 +3036,10 @@ EOF add_onlink_script_if_need fi - # 修复 cloud-init + sysconfig / NetworkManager 的各种网络问题 - if [ -d "$os_dir/etc/sysconfig" ] || [ -d "$os_dir/etc/NetworkManager" ]; then - fix_sysconfig_NetworkManager $os_dir - fi + basic_init $os_dir + + # 应该在这里是否运行了 basic_init 和创建了网络配置文件 + # 如果没有,则使用 cloud-init # 查看 cloud-init 最终配置 if [ -f "$ci_file" ]; then @@ -3226,9 +3452,8 @@ is_el7_family() { ! is_have_cmd_on_disk "$1" dnf } -fix_sysconfig_NetworkManager() { +del_exist_sysconfig_NetworkManager_config() { os_dir=$1 - ci_file=$os_dir/etc/cloud/cloud.cfg.d/99_fallback.cfg # 删除云镜像自带的 dhcp 配置,防止歧义 rm -rf $os_dir/etc/NetworkManager/system-connections/*.nmconnection @@ -3238,14 +3463,17 @@ fix_sysconfig_NetworkManager() { # 甲骨文 dhcpv6 获取不到 IP 将视为 fatal,原有的 ipv4 地址也会被删除 # 2. 修复 dhcpv6 下,ifcfg 添加了 IPV6_AUTOCONF=no 导致无法获取网关 # 3. 修复 dhcpv6 下,NM method=dhcp 导致无法获取网关 + if false; then + ci_file=$os_dir/etc/cloud/cloud.cfg.d/99_fallback.cfg - insert_into_file $ci_file after '^runcmd:' </dev/null && + ! grep -q static6 $os_dir/usr/lib/python*/*-packages/cloudinit/net/sysconfig.py; then + recognize_static6=false + fi + + # cloud-init 20.1 才支持以下配置 + # https://cloudinit.readthedocs.io/en/20.4/topics/network-config-format-v1.html#subnet-ip + # https://cloudinit.readthedocs.io/en/21.1/topics/network-config-format-v1.html#subnet-ip + # ipv6_dhcpv6-stateful: Configure this interface with dhcp6 + # ipv6_dhcpv6-stateless: Configure this interface with SLAAC and DHCP + # ipv6_slaac: Configure address with SLAAC + + # el7 最新 cloud-init 版本 + # centos 7 19.4-7.0.5.el7_9.6 backport 了 ipv6_xxx + # openeuler 20.03 19.4-15.oe2003sp4 backport 了 ipv6_xxx + # anolis 7 19.1.17-1.0.1.an7 没有更新到 centos7 相同版本,也没 backport ipv6_xxx,坑 + + # 最好还修改 ifcfg-eth* 的 IPV6_AUTOCONF + # 但实测 anolis7 cloud-init dhcp6 不会生成 IPV6_AUTOCONF,因此暂时不管 + # https://www.redhat.com/zh/blog/configuring-ipv6-rhel-7-8 + recognize_ipv6_types=true + if ls -d $os_dir/usr/lib/python*/*-packages/cloudinit/net/ 2>/dev/null && + ! grep -qr ipv6_slaac $os_dir/usr/lib/python*/*-packages/cloudinit/net/; then + recognize_ipv6_types=false + fi + + # 生成 cloud-init 网络配置 + create_cloud_init_network_config $os_dir/net.cfg "$recognize_static6" "$recognize_ipv6_types" + + # 转换成目标系统的网络配置 + chroot $os_dir cloud-init devel net-convert \ + -p /net.cfg -k yaml -d out -D rhel -O sysconfig + cp $os_dir/out/etc/sysconfig/network-scripts/ifcfg-eth* $os_dir/etc/sysconfig/network-scripts/ + rm -rf $os_dir/net.cfg $os_dir/out + + # 修正网络配置问题并显示文件 + sed -i '/^IPV[46]_FAILURE_FATAL=/d' $os_dir/etc/sysconfig/network-scripts/ifcfg-* + for file in "$os_dir/etc/sysconfig/network-scripts/ifcfg-"*; do + if grep -q '^DHCPV6C=yes' "$file"; then + sed -i '/^IPV6_AUTOCONF=no/d' "$file" + fi + + cat -n "$file" + done + else + # Network Manager + info 'Network Manager' + + create_cloud_init_network_config /net.cfg + create_network_manager_config /net.cfg "$os_dir" + rm /net.cfg + fi + # 不删除可能网络管理器不会写入dns rm_resolv_conf /os } @@ -3622,11 +3955,44 @@ EOF chroot_apt_install $os_dir $fw_pkgs fi - # 16.04 镜像用 ifupdown/networking 管理网络 - # 要安装 resolveconf,不然 /etc/resolv.conf 为空 - if [ "$releasever" = 16.04 ]; then + # 网络配置 + # 18.04+ netplan + if is_have_cmd_on_disk $os_dir netplan; then + # 生成 cloud-init 网络配置 + create_cloud_init_network_config $os_dir/net.cfg + + # ubuntu 18.04 cloud-init 版本 23.1.2,因此不用处理 onlink + + # 如果不是输出到 / 则不会生成 50-cloud-init.yaml + # 注意比较多了什么东西 + if false; then + chroot $os_dir cloud-init devel net-convert \ + -p /net.cfg -k yaml -d /out -D ubuntu -O netplan + sed -Ei "/^[[:space:]]+set-name:/d" $os_dir/out/etc/netplan/50-cloud-init.yaml + cp $os_dir/out/etc/netplan/50-cloud-init.yaml $os_dir/etc/netplan/ + rm -rf $os_dir/net.cfg $os_dir/out + else + chroot $os_dir cloud-init devel net-convert \ + -p /net.cfg -k yaml -d / -D ubuntu -O netplan + sed -Ei "/^[[:space:]]+set-name:/d" $os_dir/etc/netplan/50-cloud-init.yaml + rm -rf $os_dir/net.cfg + fi + else + # 16.04 镜像用 ifupdown/networking 管理网络 + # 要安装 resolveconf,不然 /etc/resolv.conf 为空 chroot_apt_install $os_dir resolvconf ln -sf /run/resolvconf/resolv.conf $os_dir/etc/resolv.conf.orig + + create_ifupdown_config $os_dir/etc/network/interfaces + fi + + # 自带的 60-cloudimg-settings.conf 禁止了 PasswordAuthentication + file=$os_dir/etc/ssh/sshd_config.d/60-cloudimg-settings.conf + if [ -f $file ]; then + sed -i '/^PasswordAuthentication/d' $file + if [ -z "$(cat $file)" ]; then + rm -f $file + fi fi # 安装 bios 引导 @@ -3679,64 +4045,18 @@ EOF restore_resolv_conf $os_dir } - # anolis/openeuler/opencloudos 可能要安装 cloud-init - # opencloudos 无法使用 chroot $os_dir command -v xxx - # chroot: failed to run command ‘command’: No such file or directory - if is_have_cmd_on_disk $os_dir rpm && - ! is_have_cmd_on_disk $os_dir cloud-init; then - - cp_resolv_conf $os_dir - chroot_dnf install cloud-init - restore_resolv_conf $os_dir - fi - - # cloud-init 路径 - # /usr/lib/python2.7/site-packages/cloudinit/net/ - # /usr/lib/python3/dist-packages/cloudinit/net/ - # /usr/lib/python3.9/site-packages/cloudinit/net/ - - # el7 不认识 static6,但可改成 static,作用相同 - recognize_static6=true - if ls $os_dir/usr/lib/python*/*-packages/cloudinit/net/sysconfig.py 2>/dev/null && - ! grep -q static6 $os_dir/usr/lib/python*/*-packages/cloudinit/net/sysconfig.py; then - recognize_static6=false - fi - - # cloud-init 20.1 才支持以下配置 - # https://cloudinit.readthedocs.io/en/20.4/topics/network-config-format-v1.html#subnet-ip - # https://cloudinit.readthedocs.io/en/21.1/topics/network-config-format-v1.html#subnet-ip - # ipv6_dhcpv6-stateful: Configure this interface with dhcp6 - # ipv6_dhcpv6-stateless: Configure this interface with SLAAC and DHCP - # ipv6_slaac: Configure address with SLAAC - - # el7 最新 cloud-init 版本 - # centos 7 19.4-7.0.5.el7_9.6 backport 了 ipv6_xxx - # openeuler 20.03 19.4-15.oe2003sp4 backport 了 ipv6_xxx - # anolis 7 19.1.17-1.0.1.an7 没有更新到 centos7 相同版本,也没 backport ipv6_xxx,坑 - - # 最好还修改 ifcfg-eth* 的 IPV6_AUTOCONF - # 但实测 anolis7 cloud-init dhcp6 不会生成 IPV6_AUTOCONF,因此暂时不管 - # https://www.redhat.com/zh/blog/configuring-ipv6-rhel-7-8 - recognize_ipv6_types=true - if ls -d $os_dir/usr/lib/python*/*-packages/cloudinit/net/ 2>/dev/null && - ! grep -qr ipv6_slaac $os_dir/usr/lib/python*/*-packages/cloudinit/net/; then - recognize_ipv6_types=false - fi - - # cloud-init - download_cloud_init_config "$os_dir" "$recognize_static6" "$recognize_ipv6_types" - case "$distro" in ubuntu) modify_ubuntu ;; *) modify_el_ol ;; esac - # 查看最终的 cloud-init 配置 - cat /os/etc/cloud/cloud.cfg.d/99_*.cfg + # 基本配置 + disable_cloud_init /os + basic_init /os - # 删除installer分区,重启后cloud init会自动扩容 + # 删除 swapfile swapoff -a - parted /dev/$xda -s rm 3 + rm -f /os/swapfile } get_partition_table_format() {