* Copyright (c) 2025 Bocloud Technologies Co., Ltd.
* installer is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain n copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
******************************************************************/
package syscompat
import (
"errors"
"fmt"
"strings"
"time"
"github.com/shirou/gopsutil/v3/host"
"gopkg.openfuyao.cn/bkeadm/pkg/global"
"gopkg.openfuyao.cn/bkeadm/utils"
"gopkg.openfuyao.cn/bkeadm/utils/log"
)
func Compat() error {
h, _ := host.Info()
stopFirewall()
output, err := verifyAndInstallIptables(h.Platform)
if err != nil {
return err
}
if strings.Contains(output, "nf_tables") {
return switchToLegacyIptables(h.Platform)
}
return nil
}
func stopFirewall() {
_ = global.Command.ExecuteCommand("sudo", "systemctl", "stop", "firewalld")
_ = global.Command.ExecuteCommand("sudo", "systemctl", "disable", "firewalld")
_ = global.Command.ExecuteCommand("sudo", "ufw", "disable")
}
func verifyAndInstallIptables(platform string) (string, error) {
output, err := global.Command.ExecuteCommandWithOutput("iptables", "-V")
if err == nil {
log.Infof("iptables -V output: %s", output)
return output, nil
}
log.Warnf("iptables -V error: %v", err)
if !strings.Contains(err.Error(), "not found") {
return "", err
}
return installIptables(platform)
}
func installIptables(platform string) (string, error) {
log.Info("install iptables...")
switch strings.ToLower(platform) {
case "centos", "kylin", "openeuler", "uos":
return installIptablesYum()
case "ubuntu", "debian", "fedora":
return installIptablesApt()
default:
log.Error("Unsupported platform, only support centos, ubuntu, debian, fedora")
return "", nil
}
}
func verifyIptablesInstallation() (string, error) {
output, err := global.Command.ExecuteCommandWithOutput("iptables", "-V")
if err != nil {
log.Errorf("Failed to exec iptables -V, %v", err)
return "", nil
}
log.Infof("iptables -V output: %s", output)
return output, nil
}
func installIptablesYum() (string, error) {
if err := global.Command.ExecuteCommand("yum", "-y", "install", "iptables"); err != nil {
log.Errorf("Failed to install iptables, %v", err)
return "", nil
}
return verifyIptablesInstallation()
}
func installIptablesApt() (string, error) {
_ = global.Command.ExecuteCommand("apt", "-y", "clean")
_ = global.Command.ExecuteCommand("apt", "-y", "update")
if err := global.Command.ExecuteCommand("apt", "-y", "install", "iptables"); err != nil {
log.Errorf("Failed to install iptables, %v", err)
return "", nil
}
return verifyIptablesInstallation()
}
func switchToLegacyIptables(platform string) error {
switch strings.ToLower(platform) {
case "centos", "kylin", "openeuler", "uos":
return reinstallIptablesYum()
case "ubuntu", "debian":
return updateAlternativesDebian()
case "fedora":
return updateAlternativesFedora()
default:
return errors.New(fmt.Sprintf("%s is not supported", platform))
}
}
func reinstallIptablesYum() error {
if err := global.Command.ExecuteCommand("yum", "-y", "remove", "iptables"); err != nil {
log.Errorf("Failed to remove iptables, %v", err)
return err
}
if err := global.Command.ExecuteCommand("yum", "-y", "install", "iptables"); err != nil {
log.Errorf("Failed to install iptables, %v", err)
return err
}
return nil
}
func updateAlternativesDebian() error {
alternatives := [][]string{
{"iptables", "/usr/sbin/iptables-legacy"},
{"ip6tables", "/usr/sbin/ip6tables-legacy"},
{"arptables", "/usr/sbin/arptables-legacy"},
{"ebtables", "/usr/sbin/ebtables-legacy"},
}
for _, alt := range alternatives {
if err := global.Command.ExecuteCommand("update-alternatives", "--set", alt[0], alt[1]); err != nil {
log.Warnf("Failed to update %s, %v", alt[0], err)
return nil
}
}
return nil
}
func updateAlternativesFedora() error {
if err := global.Command.ExecuteCommand("update-alternatives",
"--set", "iptables", "/usr/sbin/iptables-legacy"); err != nil {
log.Warnf("Failed to update iptables, %v", err)
return nil
}
return nil
}
func RepoUpdate() error {
const repoUpdateTimeout = 120 * time.Second
packageManager := ""
h, _, _, err := host.PlatformInformation()
if err != nil {
log.Errorf("get host platform information failed, err: %v", err)
}
switch h {
case "ubuntu", "debian":
packageManager = "apt"
case "centos", "kylin", "redhat", "fedora", "openeuler", "hopeos", "uos":
packageManager = "yum"
default:
packageManager = "unknown"
}
switch packageManager {
case "apt":
output, err := global.Command.ExecuteCommandWithTimeout(
repoUpdateTimeout, "/bin/sh", "-c", fmt.Sprintf("%s -y clean", packageManager))
if err != nil {
log.Errorf("update packages failed, err: %v, out: %s", err, output)
return nil
}
aptCmd := fmt.Sprintf("%s -y -o Acquire::Retries=1 -o Acquire::http::Timeout=%d update",
packageManager, utils.DefaultTimeoutSeconds)
output, err = global.Command.ExecuteCommandWithTimeout(repoUpdateTimeout, "/bin/sh", "-c", aptCmd)
if err != nil {
log.Errorf("update packages failed, err: %v, out: %s", err, output)
return nil
}
case "yum":
yumCmd := fmt.Sprintf("%s -y makecache --timer --setopt=skip_if_unavailable=true --setopt=fastestmirror=true",
packageManager)
output, err := global.Command.ExecuteCommandWithTimeout(repoUpdateTimeout, "/bin/sh", "-c", yumCmd)
if err != nil {
log.Errorf("update packages failed, err: %v, out: %s", err, output)
return nil
}
default:
log.Errorf("package manager %q not supported", packageManager)
return nil
}
return nil
}