ok-1
This commit is contained in:
97
internal/system/hostname.go
Normal file
97
internal/system/hostname.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SetHostname 设置系统主机名
|
||||
// 参数: hostname - 目标主机名
|
||||
// 返回: error - 如果设置失败返回错误信息
|
||||
func SetHostname(hostname string) error {
|
||||
if hostname == "" {
|
||||
return nil // 空值跳过,不报错
|
||||
}
|
||||
|
||||
// 检查是否已有相同主机名
|
||||
current, err := os.Hostname()
|
||||
if err == nil && current == hostname {
|
||||
return nil // 已经设置正确,无需修改
|
||||
}
|
||||
|
||||
// 使用 hostnamectl 设置主机名(适用于 systemd 系统)
|
||||
if _, err := exec.LookPath("hostnamectl"); err == nil {
|
||||
cmd := exec.Command("hostnamectl", "set-hostname", hostname)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("hostnamectl 设置主机名失败: %v", err)
|
||||
}
|
||||
} else {
|
||||
// 传统方法:直接修改 /etc/hostname
|
||||
if err := os.WriteFile("/etc/hostname", []byte(hostname+"\n"), 0644); err != nil {
|
||||
return fmt.Errorf("写入 /etc/hostname 失败: %v", err)
|
||||
}
|
||||
|
||||
// 立即生效(需要内核支持)
|
||||
cmd := exec.Command("sysctl", "kernel.hostname="+hostname)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
// 不返回错误,因为重启后会生效
|
||||
fmt.Printf("警告: 主机名将在重启后完全生效\n")
|
||||
}
|
||||
}
|
||||
|
||||
// 更新 /etc/hosts,确保本机解析正确
|
||||
if err := updateHostsFile(hostname); err != nil {
|
||||
fmt.Printf("警告: 更新 /etc/hosts 失败: %v\n", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateHostsFile 更新 /etc/hosts 文件中的本机映射
|
||||
func updateHostsFile(hostname string) error {
|
||||
content, err := os.ReadFile("/etc/hosts")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lines := strings.Split(string(content), "\n")
|
||||
newLines := make([]string, 0, len(lines))
|
||||
hostnameSet := false
|
||||
|
||||
for _, line := range lines {
|
||||
// 跳过空行和注释
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
newLines = append(newLines, line)
|
||||
continue
|
||||
}
|
||||
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) >= 2 && fields[0] == "127.0.1.1" {
|
||||
// 替换 Ubuntu/Debian 风格的本地主机名
|
||||
newLines = append(newLines, "127.0.1.1\t"+hostname)
|
||||
hostnameSet = true
|
||||
} else if len(fields) >= 2 && fields[0] == "127.0.0.1" {
|
||||
// 保留原行,但检查是否包含主机名
|
||||
if !strings.Contains(line, hostname) {
|
||||
line = line + " " + hostname
|
||||
}
|
||||
newLines = append(newLines, line)
|
||||
hostnameSet = true
|
||||
} else {
|
||||
newLines = append(newLines, line)
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到合适的位置,添加一行
|
||||
if !hostnameSet {
|
||||
newLines = append(newLines, "127.0.1.1\t"+hostname)
|
||||
}
|
||||
|
||||
return os.WriteFile("/etc/hosts", []byte(strings.Join(newLines, "\n")), 0644)
|
||||
}
|
||||
47
internal/system/motd.go
Normal file
47
internal/system/motd.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SetMOTD 设置 /etc/motd 文件内容
|
||||
// 参数: content - MOTD 文本内容
|
||||
// 返回: error - 写入文件错误
|
||||
func SetMOTD(content string) error {
|
||||
if content == "" {
|
||||
// 如果内容为空,不清除现有 MOTD,避免误操作
|
||||
return nil
|
||||
}
|
||||
|
||||
// 添加时间和系统信息
|
||||
finalContent := "========================================\n"
|
||||
finalContent += "SunHPC 集群管理系统\n"
|
||||
finalContent += "时间: " + time.Now().Format("2006-01-02 15:04:05") + "\n"
|
||||
finalContent += "========================================\n\n"
|
||||
finalContent += content
|
||||
|
||||
// 确保行尾有换行
|
||||
if content[len(content)-1] != '\n' {
|
||||
finalContent += "\n"
|
||||
}
|
||||
|
||||
return os.WriteFile("/etc/motd", []byte(finalContent), 0644)
|
||||
}
|
||||
|
||||
// ClearMOTD 清空 MOTD
|
||||
func ClearMOTD() error {
|
||||
return os.WriteFile("/etc/motd", []byte{}, 0644)
|
||||
}
|
||||
|
||||
// AppendToMOTD 追加内容到 MOTD
|
||||
func AppendToMOTD(additional string) error {
|
||||
f, err := os.OpenFile("/etc/motd", os.O_APPEND|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.WriteString(additional + "\n")
|
||||
return err
|
||||
}
|
||||
97
internal/system/selinux.go
Normal file
97
internal/system/selinux.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ConfigureSELinux 设置 SELinux 模式
|
||||
// 参数: mode - enforcing, permissive, disabled
|
||||
// 返回: error - 配置错误
|
||||
func ConfigureSELinux(mode string) error {
|
||||
if mode == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 验证输入
|
||||
mode = strings.ToLower(strings.TrimSpace(mode))
|
||||
validModes := map[string]bool{
|
||||
"enforcing": true,
|
||||
"permissive": true,
|
||||
"disabled": true,
|
||||
}
|
||||
|
||||
if !validModes[mode] {
|
||||
return fmt.Errorf("无效的 SELinux 模式: %s (可选: enforcing, permissive, disabled)", mode)
|
||||
}
|
||||
|
||||
// 检查 SELinux 是否可用
|
||||
if _, err := os.Stat("/selinux/enforce"); os.IsNotExist(err) {
|
||||
if _, err := os.Stat("/sys/fs/selinux/enforce"); os.IsNotExist(err) {
|
||||
return fmt.Errorf("系统不支持 SELinux 或未启用")
|
||||
}
|
||||
}
|
||||
|
||||
// 临时生效
|
||||
if mode != "disabled" { // disabled 需要重启才能完全生效
|
||||
cmd := exec.Command("setenforce", mode)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("setenforce %s 失败: %v", mode, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 持久化配置
|
||||
return persistSELinuxMode(mode)
|
||||
}
|
||||
|
||||
// persistSELinuxMode 修改 /etc/selinux/config 实现持久化
|
||||
func persistSELinuxMode(mode string) error {
|
||||
const selinuxConfig = "/etc/selinux/config"
|
||||
|
||||
// 读取配置文件
|
||||
content, err := os.ReadFile(selinuxConfig)
|
||||
if err != nil {
|
||||
// 如果文件不存在,创建默认配置
|
||||
if os.IsNotExist(err) {
|
||||
defaultConfig := fmt.Sprintf(`# This file controls the state of SELinux on the system.
|
||||
# SELINUX= can take one of these three values:
|
||||
# enforcing - SELinux security policy is enforced.
|
||||
# permissive - SELinux prints warnings instead of enforcing.
|
||||
# disabled - No SELinux policy is loaded.
|
||||
SELINUX=%s
|
||||
# SELINUXTYPE= can take one of three two values:
|
||||
# targeted - Targeted processes are protected,
|
||||
# minimum - Modification of targeted policy. Only selected processes are protected.
|
||||
# mls - Multi Level Security protection.
|
||||
SELINUXTYPE=targeted
|
||||
`, mode)
|
||||
return os.WriteFile(selinuxConfig, []byte(defaultConfig), 0644)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 替换 SELINUX= 行
|
||||
lines := strings.Split(string(content), "\n")
|
||||
for i, line := range lines {
|
||||
if strings.HasPrefix(line, "SELINUX=") {
|
||||
lines[i] = fmt.Sprintf("SELINUX=%s", mode)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return os.WriteFile(selinuxConfig, []byte(strings.Join(lines, "\n")), 0644)
|
||||
}
|
||||
|
||||
// GetSELinuxMode 获取当前 SELinux 模式
|
||||
func GetSELinuxMode() (string, error) {
|
||||
cmd := exec.Command("getenforce")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.ToLower(strings.TrimSpace(string(output))), nil
|
||||
}
|
||||
187
internal/system/ssh.go
Normal file
187
internal/system/ssh.go
Normal file
@@ -0,0 +1,187 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"sunhpc/internal/config"
|
||||
)
|
||||
|
||||
// ConfigureSSH 配置 SSH 服务
|
||||
// 参数: cfg - config.SSHConfig 结构体
|
||||
// 返回: error - 配置错误
|
||||
func ConfigureSSH(cfg config.SSHConfig) error {
|
||||
const sshdConfig = "/etc/ssh/sshd_config"
|
||||
|
||||
// 读取现有配置
|
||||
content, err := os.ReadFile(sshdConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("读取 sshd_config 失败: %v", err)
|
||||
}
|
||||
|
||||
// 备份原始配置
|
||||
backupPath := sshdConfig + ".sunhpc.bak"
|
||||
if _, err := os.Stat(backupPath); os.IsNotExist(err) {
|
||||
if err := os.WriteFile(backupPath, content, 0644); err != nil {
|
||||
fmt.Printf("警告: 无法创建备份文件 %s: %v\n", backupPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析和修改配置
|
||||
lines := strings.Split(string(content), "\n")
|
||||
newLines := make([]string, 0, len(lines))
|
||||
configMap := make(map[string]bool)
|
||||
|
||||
// 处理每一行
|
||||
for _, line := range lines {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
if trimmed == "" || strings.HasPrefix(trimmed, "#") {
|
||||
newLines = append(newLines, line)
|
||||
continue
|
||||
}
|
||||
|
||||
parts := strings.Fields(trimmed)
|
||||
if len(parts) < 2 {
|
||||
newLines = append(newLines, line)
|
||||
continue
|
||||
}
|
||||
|
||||
key := parts[0]
|
||||
configMap[key] = true
|
||||
|
||||
// 根据配置更新
|
||||
switch key {
|
||||
case "PermitRootLogin":
|
||||
if cfg.PermitRootLogin != "" {
|
||||
newLines = append(newLines, fmt.Sprintf("PermitRootLogin %s", cfg.PermitRootLogin))
|
||||
} else {
|
||||
newLines = append(newLines, line)
|
||||
}
|
||||
case "PasswordAuthentication":
|
||||
if cfg.PasswordAuth != "" {
|
||||
newLines = append(newLines, fmt.Sprintf("PasswordAuthentication %s", cfg.PasswordAuth))
|
||||
} else {
|
||||
newLines = append(newLines, line)
|
||||
}
|
||||
default:
|
||||
newLines = append(newLines, line)
|
||||
}
|
||||
}
|
||||
|
||||
// 添加缺失的配置项
|
||||
if cfg.PermitRootLogin != "" && !configMap["PermitRootLogin"] {
|
||||
newLines = append(newLines, fmt.Sprintf("PermitRootLogin %s", cfg.PermitRootLogin))
|
||||
}
|
||||
if cfg.PasswordAuth != "" && !configMap["PasswordAuthentication"] {
|
||||
newLines = append(newLines, fmt.Sprintf("PasswordAuthentication %s", cfg.PasswordAuth))
|
||||
}
|
||||
|
||||
// 写入新配置
|
||||
newContent := strings.Join(newLines, "\n")
|
||||
if err := os.WriteFile(sshdConfig, []byte(newContent), 0644); err != nil {
|
||||
return fmt.Errorf("写入 sshd_config 失败: %v", err)
|
||||
}
|
||||
|
||||
// 测试配置语法
|
||||
if err := testSSHDConfig(); err != nil {
|
||||
// 恢复备份
|
||||
if backup, err := os.ReadFile(backupPath); err == nil {
|
||||
os.WriteFile(sshdConfig, backup, 0644)
|
||||
}
|
||||
return fmt.Errorf("SSH 配置语法错误: %v", err)
|
||||
}
|
||||
|
||||
// 重启 SSH 服务
|
||||
return restartSSHD()
|
||||
}
|
||||
|
||||
// testSSHDConfig 测试 sshd 配置语法
|
||||
func testSSHDConfig() error {
|
||||
cmd := exec.Command("sshd", "-t")
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
// restartSSHD 重启 SSH 服务
|
||||
func restartSSHD() error {
|
||||
// 尝试不同的服务管理器
|
||||
serviceMgrs := []struct {
|
||||
name string
|
||||
args []string
|
||||
}{
|
||||
{"systemctl", []string{"restart", "sshd"}},
|
||||
{"systemctl", []string{"restart", "ssh"}},
|
||||
{"service", []string{"sshd", "restart"}},
|
||||
{"service", []string{"ssh", "restart"}},
|
||||
}
|
||||
|
||||
for _, mgr := range serviceMgrs {
|
||||
if _, err := exec.LookPath(mgr.name); err == nil {
|
||||
cmd := exec.Command(mgr.name, mgr.args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("无法重启 SSH 服务,请手动重启")
|
||||
}
|
||||
|
||||
// AddSSHKey 添加 SSH 公钥到指定用户
|
||||
func AddSSHKey(username, pubkey string) error {
|
||||
// 获取用户主目录
|
||||
homeDir, err := getUserHomeDir(username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sshDir := homeDir + "/.ssh"
|
||||
authKeys := sshDir + "/authorized_keys"
|
||||
|
||||
// 创建 .ssh 目录
|
||||
if err := os.MkdirAll(sshDir, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 追加公钥
|
||||
f, err := os.OpenFile(authKeys, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.WriteString(pubkey + "\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 修改所有权
|
||||
return chownRecursive(sshDir, username)
|
||||
}
|
||||
|
||||
// getUserHomeDir 获取用户主目录
|
||||
func getUserHomeDir(username string) (string, error) {
|
||||
cmd := exec.Command("getent", "passwd", username)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("用户 %s 不存在", username)
|
||||
}
|
||||
|
||||
parts := strings.Split(strings.TrimSpace(string(output)), ":")
|
||||
if len(parts) >= 6 {
|
||||
return parts[5], nil
|
||||
}
|
||||
return "", fmt.Errorf("无法获取用户 %s 的主目录", username)
|
||||
}
|
||||
|
||||
// chownRecursive 递归修改文件所有者
|
||||
func chownRecursive(path, username string) error {
|
||||
cmd := exec.Command("chown", "-R", username+":"+username, path)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
87
internal/system/sysctl.go
Normal file
87
internal/system/sysctl.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ConfigureSysctl 设置内核参数
|
||||
// 参数: params - 键值对映射,如 {"net.ipv4.ip_forward": "1"}
|
||||
// 返回: error - 第一个失败的错误
|
||||
func ConfigureSysctl(params map[string]string) error {
|
||||
if len(params) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 首先应用临时配置
|
||||
for k, v := range params {
|
||||
cmd := exec.Command("sysctl", "-w", fmt.Sprintf("%s=%s", k, v))
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("设置 sysctl %s=%s 失败: %v", k, v, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 持久化配置到 /etc/sysctl.conf 或 /etc/sysctl.d/
|
||||
return appendToSysctlConf(params)
|
||||
}
|
||||
|
||||
// appendToSysctlConf 将参数写入持久化配置文件
|
||||
func appendToSysctlConf(params map[string]string) error {
|
||||
const sysctlFile = "/etc/sysctl.d/99-sunhpc.conf"
|
||||
|
||||
// 读取现有配置
|
||||
existing := make(map[string]bool)
|
||||
if data, err := os.ReadFile(sysctlFile); err == nil {
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(data)))
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
parts := strings.SplitN(line, "=", 2)
|
||||
if len(parts) == 2 {
|
||||
existing[strings.TrimSpace(parts[0])] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 构建新内容
|
||||
var content strings.Builder
|
||||
content.WriteString("# SunHPC 系统优化配置\n")
|
||||
content.WriteString("# 生成时间: " + time.Now().Format(time.RFC3339) + "\n\n")
|
||||
|
||||
for k, v := range params {
|
||||
// 跳过已存在的配置(避免重复)
|
||||
if existing[k] {
|
||||
continue
|
||||
}
|
||||
content.WriteString(fmt.Sprintf("%s = %s\n", k, v))
|
||||
}
|
||||
|
||||
// 如果有新配置才写入
|
||||
if content.Len() > 100 {
|
||||
if err := os.WriteFile(sysctlFile, []byte(content.String()), 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
// 应用持久化配置
|
||||
return exec.Command("sysctl", "--system").Run()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSysctl 获取当前内核参数值
|
||||
func GetSysctl(key string) (string, error) {
|
||||
cmd := exec.Command("sysctl", "-n", key)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(string(output)), nil
|
||||
}
|
||||
178
internal/system/system.go
Normal file
178
internal/system/system.go
Normal file
@@ -0,0 +1,178 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sunhpc/internal/config"
|
||||
"sunhpc/internal/log"
|
||||
)
|
||||
|
||||
// Context 系统配置上下文,包含所有命令行参数
|
||||
type Context struct {
|
||||
Force bool // 强制模式
|
||||
DryRun bool // 干运行模式
|
||||
Verbose bool // 详细输出
|
||||
Timeout int // 超时时间
|
||||
Backup string // 备份路径
|
||||
YesMode bool // 自动确认
|
||||
}
|
||||
|
||||
// ApplyAll 应用所有系统配置
|
||||
func ApplyAll(cfg *config.SunHPCConfig) error {
|
||||
log.Info("开始应用系统配置...")
|
||||
|
||||
if err := SetHostnameWithContext(cfg.Hostname, nil); err != nil {
|
||||
log.Warnf("设置主机名失败: %v", err)
|
||||
}
|
||||
|
||||
if err := SetMOTDWithContext(cfg.MOTD, nil); err != nil {
|
||||
log.Warnf("设置 MOTD 失败: %v", err)
|
||||
}
|
||||
|
||||
if err := ConfigureSysctlWithContext(cfg.Sysctl, nil); err != nil {
|
||||
log.Warnf("配置 sysctl 失败: %v", err)
|
||||
}
|
||||
|
||||
if err := ConfigureSELinuxWithContext(cfg.SELinux, nil); err != nil {
|
||||
log.Warnf("配置 SELinux 失败: %v", err)
|
||||
}
|
||||
|
||||
if err := ConfigureSSHWithContext(cfg.SSH, nil); err != nil {
|
||||
log.Warnf("配置 SSH 失败: %v", err)
|
||||
}
|
||||
|
||||
log.Info("系统配置应用完成")
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetHostnameWithContext 设置系统主机名,带上下文参数
|
||||
func SetHostnameWithContext(hostname string, ctx *Context) error {
|
||||
if ctx != nil && ctx.DryRun {
|
||||
log.Infof("[干运行] 设置主机名为: %s", hostname)
|
||||
return nil
|
||||
}
|
||||
|
||||
if hostname == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 检查是否需要强制设置
|
||||
current, _ := os.Hostname()
|
||||
if current == hostname && (ctx == nil || !ctx.Force) {
|
||||
log.Infof("主机名已是 '%s',跳过设置", hostname)
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Infof("设置主机名为: %s", hostname)
|
||||
return SetHostname(hostname)
|
||||
}
|
||||
|
||||
// SetMOTDWithContext 设置 MOTD,带上下文参数
|
||||
func SetMOTDWithContext(content string, ctx *Context) error {
|
||||
if ctx != nil && ctx.DryRun {
|
||||
log.Info("[干运行] 设置 MOTD")
|
||||
return nil
|
||||
}
|
||||
|
||||
if content == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 备份现有文件
|
||||
if ctx != nil && ctx.Backup != "" {
|
||||
backupMOTD(ctx.Backup)
|
||||
}
|
||||
|
||||
log.Info("更新 /etc/motd")
|
||||
return SetMOTD(content)
|
||||
}
|
||||
|
||||
// ConfigureSysctlWithContext 配置内核参数,带上下文参数
|
||||
func ConfigureSysctlWithContext(params map[string]string, ctx *Context) error {
|
||||
if ctx != nil && ctx.DryRun {
|
||||
log.Info("[干运行] 配置 sysctl 参数")
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(params) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 备份现有配置
|
||||
if ctx != nil && ctx.Backup != "" {
|
||||
backupSysctl(ctx.Backup)
|
||||
}
|
||||
|
||||
return ConfigureSysctl(params)
|
||||
}
|
||||
|
||||
// ConfigureSELinuxWithContext 配置 SELinux,带上下文参数
|
||||
func ConfigureSELinuxWithContext(mode string, ctx *Context) error {
|
||||
if ctx != nil && ctx.DryRun {
|
||||
log.Infof("[干运行] 设置 SELinux 模式为: %s", mode)
|
||||
return nil
|
||||
}
|
||||
|
||||
if mode == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 检查当前模式
|
||||
current, _ := GetSELinuxMode()
|
||||
if current == mode && (ctx == nil || !ctx.Force) {
|
||||
log.Infof("SELinux 已是 '%s' 模式,跳过设置", mode)
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Infof("设置 SELinux 模式为: %s", mode)
|
||||
return ConfigureSELinux(mode)
|
||||
}
|
||||
|
||||
// ConfigureSSHWithContext 配置 SSH,带上下文参数
|
||||
func ConfigureSSHWithContext(cfg config.SSHConfig, ctx *Context) error {
|
||||
if ctx != nil && ctx.DryRun {
|
||||
log.Info("[干运行] 配置 SSH 服务")
|
||||
return nil
|
||||
}
|
||||
|
||||
// 备份配置文件
|
||||
if ctx != nil && ctx.Backup != "" {
|
||||
backupSSHConfig(ctx.Backup)
|
||||
}
|
||||
|
||||
log.Info("配置 SSH 服务")
|
||||
return ConfigureSSH(cfg)
|
||||
}
|
||||
|
||||
// 备份函数
|
||||
func backupMOTD(backupDir string) error {
|
||||
backupPath := filepath.Join(backupDir, "motd."+filepath.Base(os.Args[0])+".bak")
|
||||
if err := os.MkdirAll(backupDir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
return copyFile("/etc/motd", backupPath)
|
||||
}
|
||||
|
||||
func backupSysctl(backupDir string) error {
|
||||
backupPath := filepath.Join(backupDir, "sysctl.conf.bak")
|
||||
if err := os.MkdirAll(backupDir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
return copyFile("/etc/sysctl.conf", backupPath)
|
||||
}
|
||||
|
||||
func backupSSHConfig(backupDir string) error {
|
||||
backupPath := filepath.Join(backupDir, "sshd_config.bak")
|
||||
if err := os.MkdirAll(backupDir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
return copyFile("/etc/ssh/sshd_config", backupPath)
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) error {
|
||||
data, err := os.ReadFile(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(dst, data, 0644)
|
||||
}
|
||||
Reference in New Issue
Block a user