diff --git a/agent/app/api/v2/firewall.go b/agent/app/api/v2/firewall.go index 62460970557e..d2b3b059af81 100644 --- a/agent/app/api/v2/firewall.go +++ b/agent/app/api/v2/firewall.go @@ -460,6 +460,8 @@ func handleFirewallRuleError(c *gin.Context, err error) { helper.ErrorWithBusinessCode(c, http.StatusConflict, "FW_RULE_STALE", "ErrInvalidParams", err) case errors.Is(err, repo.ErrFirewallRuleRevisionConflict): helper.ErrorWithBusinessCode(c, http.StatusConflict, "FW_RULE_REVISION_CONFLICT", "ErrInvalidParams", err) + case errors.Is(err, filter.ErrManagedScopeChange): + helper.ErrorWithBusinessCode(c, http.StatusBadRequest, "FW_SCOPE_UNSUPPORTED", "ErrFirewallRuleScopeChange", err) case errors.Is(err, filter.ErrUnsupportedScope), errors.Is(err, filter.ErrInvalidScope), errors.Is(err, filter.ErrProviderUnavailable), errors.Is(err, filter.ErrAdapterUnavailable): helper.ErrorWithBusinessCode(c, http.StatusBadRequest, "FW_SCOPE_UNSUPPORTED", "ErrInvalidParams", err) @@ -488,6 +490,29 @@ func (b *BaseApi) LoadFirewallSettings(c *gin.Context) { helper.SuccessWithData(c, data) } +// @Tags Firewall +// @Summary Queue firewall port whitelist update +// @Description Returns a taskID; configuration save and per-rule results are recorded in the task log. +// @Accept json +// @Param request body dto.FirewallPortWhitelistUpdate true "request" +// @Success 200 {object} dto.FilterChainOperationResponse +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /hosts/firewall/settings/whitelist [post] +// @x-panel-log {"bodyKeys":["value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新防火墙端口白名单 [value]","formatEN":"update firewall port whitelist [value]"} +func (b *BaseApi) UpdateFirewallPortWhitelist(c *gin.Context) { + var request dto.FirewallPortWhitelistUpdate + if err := helper.CheckBindAndValidate(&request, c); err != nil { + return + } + result, err := firewallSettingService.QueuePortWhitelist(request.Value) + if err != nil { + helper.InternalServer(c, err) + return + } + helper.SuccessWithData(c, result) +} + // @Tags Firewall // @Summary Operate firewall backend // @Accept json diff --git a/agent/app/dto/firewall.go b/agent/app/dto/firewall.go index 9cadc2571aa2..e1471c048b0d 100644 --- a/agent/app/dto/firewall.go +++ b/agent/app/dto/firewall.go @@ -62,6 +62,10 @@ type FirewallSettings struct { PortWhitelist string `json:"portWhiteList"` } +type FirewallPortWhitelistUpdate struct { + Value string `json:"value" validate:"required"` +} + type FirewallBackendOperation struct { Subsystem string `json:"subsystem" validate:"required,oneof=system forwarding docker"` Backend string `json:"backend" validate:"required,oneof=firewalld ufw iptables nftables"` diff --git a/agent/app/dto/setting.go b/agent/app/dto/setting.go index 9f9fa088f3b4..78c693fda02c 100644 --- a/agent/app/dto/setting.go +++ b/agent/app/dto/setting.go @@ -35,7 +35,7 @@ type SettingUpdate struct { } type AgentSettingUpdate struct { - Key string `json:"key" validate:"required,oneof=SystemIP DockerSockPath FileRecycleBin FirewallPortWhiteList"` + Key string `json:"key" validate:"required,oneof=SystemIP DockerSockPath FileRecycleBin"` Value string `json:"value"` } diff --git a/agent/app/service/firewall.go b/agent/app/service/firewall.go index e8c5a2d08017..5825ec93a792 100644 --- a/agent/app/service/firewall.go +++ b/agent/app/service/firewall.go @@ -1825,7 +1825,7 @@ func (s *FirewallService) prepareManagedUpdate( return preparedManagedUpdate{}, err } if after.Scope.Key() != before.Rule.Scope.Key() { - return preparedManagedUpdate{}, fmt.Errorf("%w: managed rule scope cannot be changed", filter.ErrUnsupportedScope) + return preparedManagedUpdate{}, filter.ErrManagedScopeChange } if !supportsManagedNativeKindTransition(before.Rule, after) { return preparedManagedUpdate{}, fmt.Errorf("%w: native rule conversion requires an explicit workflow", filter.ErrUnsupportedScope) @@ -2471,6 +2471,47 @@ func isFirewallPolicyIncompatible(err error) bool { errors.Is(err, filter.ErrInvalidScope) || errors.Is(err, filter.ErrCompositeRule) } +func (s *FirewallService) compileRestorableFirewallRules( + ctx context.Context, + stored model.FirewallRule, + provider filter.Provider, +) (restorable, preserved []filter.DesiredRule, err error) { + compiled, err := s.compileStoredFirewallRules(ctx, stored, provider) + if err != nil { + return nil, nil, err + } + if !supportsManagedFilterChains(string(provider)) || !isProtectedSystemFirewallRule(stored) { + return compiled, nil, nil + } + loadRequired := s.requiredPorts + if loadRequired == nil { + loadRequired = LoadRequiredFirewallPortWhiteList + } + required, err := loadRequired() + if err != nil { + return nil, nil, err + } + requiredPorts := systemPorts(required) + for _, desired := range compiled { + covered := false + for _, port := range requiredPorts { + covered, err = filter.SameRuleContent(desired.Rule, systemPortRule(provider, port)) + if err != nil { + return nil, nil, err + } + if covered { + break + } + } + if covered { + preserved = append(preserved, desired) + } else { + restorable = append(restorable, desired) + } + } + return restorable, preserved, nil +} + func (s *FirewallService) desiredFirewallRulesByScope( ctx context.Context, stored []model.FirewallRule, @@ -2480,7 +2521,7 @@ func (s *FirewallService) desiredFirewallRulesByScope( desired := make(map[string][]filter.DesiredRule) var failures []filter.InventoryItem for _, record := range stored { - compiled, err := s.compileStoredFirewallRules(ctx, record, provider) + compiled, _, err := s.compileRestorableFirewallRules(ctx, record, provider) if err != nil { rule := filter.FirewallRule{ UUID: record.UUID, @@ -2648,47 +2689,6 @@ func loadRequiredFirewallPorts(panelPort string) ([]firewall.PortWhitelist, erro return firewall.NormalizeRequiredPorts(ports) } -func (s *FirewallService) updatePortWhitelist(ctx context.Context, value string) error { - firewallRuleMutationMu.Lock() - defer firewallRuleMutationMu.Unlock() - - ports, err := firewall.ParsePortWhitelist(value) - if err != nil { - return err - } - oldValue, err := settingRepo.GetValueByKey(constant.FirewallPortWhiteList) - if errors.Is(err, gorm.ErrRecordNotFound) { - oldValue = constant.FirewallPortWhiteListValue - } else if err != nil { - return err - } - oldPorts, err := firewall.ParsePortWhitelist(oldValue) - if err != nil { - return err - } - required, err := s.requiredPorts() - if err != nil { - return err - } - ctx = context.WithValue(ctx, panelPortWhitelistKey{}, firewall.NormalizePortWhitelist(append(oldPorts, required...))) - added := excludeFirewallPorts(excludeFirewallPorts(ports, oldPorts), required) - for _, port := range systemPorts(added) { - if err := s.ensureSystemPortLocked(ctx, port); err != nil { - return err - } - } - removed := excludeFirewallPorts(excludeFirewallPorts(oldPorts, ports), required) - return global.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error { - txCtx := context.WithValue(ctx, constant.DB, tx) - if err := s.releaseSystemPorts(txCtx, systemPorts(removed)); err != nil { - return err - } - return tx.Where("key = ?", constant.FirewallPortWhiteList). - Assign(map[string]interface{}{"value": value}). - FirstOrCreate(&model.Setting{Key: constant.FirewallPortWhiteList}).Error - }) -} - func (s *FirewallService) releaseSystemPorts(ctx context.Context, ports []dto.FirewallSystemPort) error { portSet, err := normalizeSystemPorts(ports) if err != nil || len(portSet) == 0 { diff --git a/agent/app/service/firewall_setting.go b/agent/app/service/firewall_setting.go index 993f7b45d4c2..599c34cf674f 100644 --- a/agent/app/service/firewall_setting.go +++ b/agent/app/service/firewall_setting.go @@ -2,11 +2,18 @@ package service import ( "context" + "encoding/json" "errors" "fmt" + "sync" "github.com/1Panel-dev/1Panel/agent/app/dto" + "github.com/1Panel-dev/1Panel/agent/app/model" + "github.com/1Panel-dev/1Panel/agent/app/repo" + "github.com/1Panel-dev/1Panel/agent/app/task" "github.com/1Panel-dev/1Panel/agent/constant" + "github.com/1Panel-dev/1Panel/agent/global" + "github.com/1Panel-dev/1Panel/agent/i18n" "github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/1Panel-dev/1Panel/agent/utils/firewall" "github.com/1Panel-dev/1Panel/agent/utils/firewall/docker_guard" @@ -15,15 +22,19 @@ import ( "github.com/1Panel-dev/1Panel/agent/utils/firewall/lifecycle" "github.com/1Panel-dev/1Panel/agent/utils/firewall/nftables_helper" "github.com/1Panel-dev/1Panel/agent/utils/firewall/ping" + "gorm.io/gorm" ) type IFirewallSettingService interface { + QueuePortWhitelist(value string) (dto.FilterChainOperationResponse, error) Load(context.Context) (dto.FirewallSettings, error) Operate(context.Context, dto.FirewallBackendOperation) error } type FirewallSettingService struct{} +var firewallWhitelistTaskMu sync.Mutex + var ErrFirewallBackendCleanupRequired = errors.New("firewall backend cleanup required") func firewallBackendCleanupRequired(current, target string) error { @@ -39,6 +50,180 @@ func NewIFirewallSettingService() IFirewallSettingService { return &FirewallSettingService{} } +func (s *FirewallSettingService) QueuePortWhitelist(value string) (dto.FilterChainOperationResponse, error) { + return s.queuePortWhitelist(value, newFirewallService()) +} + +func (s *FirewallSettingService) queuePortWhitelist(value string, firewallService *FirewallService) (dto.FilterChainOperationResponse, error) { + firewallWhitelistTaskMu.Lock() + defer firewallWhitelistTaskMu.Unlock() + if err := task.CheckScopeTaskIsExecuting(task.TaskScopeFirewall, 0); err != nil { + return dto.FilterChainOperationResponse{}, err + } + taskItem, err := task.NewTask(i18n.GetMsgByKey("FirewallWhitelistTask"), task.TaskUpdate, task.TaskScopeFirewall, "", 0) + if err != nil { + return dto.FilterChainOperationResponse{}, err + } + taskItem.AddSubTaskWithOps(taskItem.Name, func(t *task.Task) error { + succeeded, failed := 0, 0 + err := s.applyPortWhitelist(t.TaskCtx, value, firewallService, func(status, label string, err error) { + switch status { + case "applied": + succeeded++ + t.LogSuccess(label) + case "failed": + failed++ + t.LogFailedWithErr(label, err) + default: + t.Log(i18n.GetWithName(status, label)) + } + }) + t.Log(i18n.GetMsgWithMap("FirewallRuleOperationResult", map[string]interface{}{ + "succeeded": succeeded, "failed": failed, + })) + return err + }, nil, 0, 0) + if err := repo.NewITaskRepo().Save(context.Background(), taskItem.Task); err != nil { + closeUnstartedFirewallTask(taskItem) + return dto.FilterChainOperationResponse{}, fmt.Errorf("save firewall whitelist task: %w", err) + } + go func() { _ = taskItem.Execute() }() + return dto.FilterChainOperationResponse{TaskID: taskItem.TaskID, Queued: true}, nil +} + +type whitelistReporter func(status, label string, err error) + +func (s *FirewallSettingService) applyPortWhitelist(ctx context.Context, value string, firewallService *FirewallService, report whitelistReporter) error { + firewallRuleMutationMu.Lock() + defer firewallRuleMutationMu.Unlock() + if err := ctx.Err(); err != nil { + return err + } + ports, err := firewall.ParsePortWhitelist(value) + if err != nil { + return err + } + required, err := firewallService.requiredPorts() + if err != nil { + return err + } + removed, err := s.savePortWhitelist(ctx, ports, required, firewallService) + if err != nil { + return err + } + report("FirewallWhitelistSaved", "", nil) + for _, port := range systemPorts(removed) { + report("FirewallWhitelistReleased", whitelistPortLabel(port), nil) + } + + ctx = context.WithValue(ctx, panelPortWhitelistKey{}, required) + provider, providerErr := firewallService.selectedProvider(ctx) + ready := s.portWhitelistReadiness(provider, providerErr, firewallService) + return syncPortWhitelist(ctx, ports, required, ready, firewallService.ensureSystemPortLocked, report) +} + +func (s *FirewallSettingService) savePortWhitelist(ctx context.Context, ports, required []firewall.PortWhitelist, firewallService *FirewallService) ([]firewall.PortWhitelist, error) { + var removed []firewall.PortWhitelist + err := global.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + var setting model.Setting + err := tx.Where("key = ?", constant.FirewallPortWhiteList).First(&setting).Error + if errors.Is(err, gorm.ErrRecordNotFound) { + setting.Value = constant.FirewallPortWhiteListValue + } else if err != nil { + return err + } + previous, err := firewall.ParsePortWhitelist(setting.Value) + if err != nil { + return err + } + removed = excludeFirewallPorts(excludeFirewallPorts(previous, ports), required) + txCtx := context.WithValue(ctx, constant.DB, tx) + if err := firewallService.releaseSystemPorts(txCtx, systemPorts(removed)); err != nil { + return err + } + value, err := json.Marshal(ports) + if err != nil { + return err + } + return tx.Where("key = ?", constant.FirewallPortWhiteList). + Assign(map[string]interface{}{"value": string(value)}). + FirstOrCreate(&model.Setting{Key: constant.FirewallPortWhiteList}).Error + }) + return removed, err +} + +func (s *FirewallSettingService) portWhitelistReadiness(provider filter.Provider, providerErr error, firewallService *FirewallService) func(dto.FirewallSystemPort) (bool, error) { + type state struct { + ready bool + err error + } + states := make(map[string]state) + return func(port dto.FirewallSystemPort) (bool, error) { + if providerErr != nil { + return false, providerErr + } + key := "service" + if isDirectFirewallProvider(provider) { + key = port.Family + } + if cached, ok := states[key]; ok { + return cached.ready, cached.err + } + var result state + if isDirectFirewallProvider(provider) { + initialized, bound, err := loadSystemFirewallFamilyStatus(string(provider), port.Family) + result = state{ready: initialized && bound, err: err} + } else { + client, err := firewallService.baseClient() + result.err = err + if err == nil { + result.ready, result.err = client.Status() + } + } + states[key] = result + return result.ready, result.err + } +} + +func syncPortWhitelist( + ctx context.Context, + ports, required []firewall.PortWhitelist, + ready func(dto.FirewallSystemPort) (bool, error), + ensure func(context.Context, dto.FirewallSystemPort) error, + report whitelistReporter, +) error { + var failures []error + for _, port := range systemPorts(ports) { + if err := ctx.Err(); err != nil { + return errors.Join(append(failures, err)...) + } + label := whitelistPortLabel(port) + if containsFirewallPort(required, firewall.PortWhitelist{Family: port.Family, Port: port.Port, Protocol: port.Protocol}) { + report("FirewallWhitelistRequired", label, nil) + continue + } + active, err := ready(port) + if err == nil && !active { + report("FirewallWhitelistDeferred", label, nil) + continue + } + if err == nil { + err = ensure(ctx, port) + } + if err != nil { + report("failed", label, err) + failures = append(failures, fmt.Errorf("%s: %w", label, err)) + continue + } + report("applied", label, nil) + } + return errors.Join(failures...) +} + +func whitelistPortLabel(port dto.FirewallSystemPort) string { + return fmt.Sprintf("%s %s/%s", port.Family, port.Port, port.Protocol) +} + func (s *FirewallSettingService) Load(ctx context.Context) (dto.FirewallSettings, error) { result := dto.FirewallSettings{PingStatus: ping.LoadStatus()} if ports, err := settingRepo.GetValueByKey(constant.FirewallPortWhiteList); err == nil { diff --git a/agent/app/service/firewall_sync.go b/agent/app/service/firewall_sync.go index 078f4b9505f2..26830dc9c0c4 100644 --- a/agent/app/service/firewall_sync.go +++ b/agent/app/service/firewall_sync.go @@ -83,14 +83,18 @@ func (s *FirewallService) loadFirewallSyncRules(ctx context.Context, request dto } model.SortFirewallRules(stored, request.TargetProvider) rules := make([]*firewallSyncRule, 0, len(stored)) + preservedMarkers := make(map[string]bool) compileFailed := false for _, record := range stored { - desired, err := s.compileStoredFirewallRules(ctx, record, request.TargetProvider) + desired, preserved, err := s.compileRestorableFirewallRules(ctx, record, request.TargetProvider) if err != nil { compileFailed = true rules = append(rules, &firewallSyncRule{FirewallRuleSyncItem: dto.FirewallRuleSyncItem{SourceUUID: record.UUID, Status: firewallsync.StatusBlocked, Reason: err.Error()}}) continue } + for _, rule := range preserved { + preservedMarkers[rule.Marker] = true + } for _, native := range desired { rule := native.Rule rules = append(rules, &firewallSyncRule{desired: native, FirewallRuleSyncItem: dto.FirewallRuleSyncItem{SourceUUID: record.UUID, Rule: &rule}}) @@ -129,7 +133,7 @@ func (s *FirewallService) loadFirewallSyncRules(ctx context.Context, request dto matched := make(map[string]filter.InventoryItem) for _, item := range inventory { if item.Desired == nil { - if compileFailed || item.Observed == nil || !strings.HasPrefix(item.Observed.Marker, "1panel-rule:") { + if compileFailed || item.Observed == nil || !strings.HasPrefix(item.Observed.Marker, "1panel-rule:") || preservedMarkers[item.Observed.Marker] { continue } observed := item.Observed diff --git a/agent/app/service/setting.go b/agent/app/service/setting.go index 85302bdc3605..9051b2263c0f 100644 --- a/agent/app/service/setting.go +++ b/agent/app/service/setting.go @@ -1,7 +1,6 @@ package service import ( - "context" "encoding/base64" "encoding/json" "errors" @@ -125,9 +124,6 @@ func (u *SettingService) GetWebsiteDir() string { } func (u *SettingService) Update(key, value string) error { - if key == constant.FirewallPortWhiteList { - return newFirewallService().updatePortWhitelist(context.Background(), value) - } return settingRepo.UpdateOrCreate(key, value) } diff --git a/agent/cmd/server/docs/x-log.json b/agent/cmd/server/docs/x-log.json index f48d7aa591a2..a5bbfaa907d7 100644 --- a/agent/cmd/server/docs/x-log.json +++ b/agent/cmd/server/docs/x-log.json @@ -116,6 +116,16 @@ "formatZH": "删除告警配置 [id]", "formatEN": "delete alert config [id]" }, + "/alert/config/status": { + "bodyKeys": [ + "id", + "status" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "更新告警配置状态 [id][status]", + "formatEN": "update alert config status [id][status]" + }, "/alert/config/update": { "bodyKeys": [ "id", @@ -1745,42 +1755,17 @@ "formatZH": "更新 [name]", "formatEN": "update user [name]" }, - "/core/xpack/vms": { - "bodyKeys": [ - "name" - ], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "创建虚拟机 [name]", - "formatEN": "create VM [name]" - }, - "/core/xpack/vms/del": { - "bodyKeys": [ - "name" - ], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "删除虚拟机 [name]", - "formatEN": "delete VM [name]" - }, - "/core/xpack/vms/environment/enable": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "启用虚拟机运行环境", - "formatEN": "enable VM runtime environment" - }, - "/core/xpack/vms/iso": { + "/core/groups": { "bodyKeys": [ "name", "type" ], "paramKeys": [], "beforeFunctions": [], - "formatZH": "创建虚拟机镜像 [name] [type]", - "formatEN": "create VM ISO [name] [type]" + "formatZH": "创建组 [name][type]", + "formatEN": "create group [name][type]" }, - "/core/xpack/vms/iso/del": { + "/core/groups/del": { "bodyKeys": [ "id" ], @@ -1790,191 +1775,125 @@ "input_column": "id", "input_value": "id", "isList": false, - "db": "vm_isos", + "db": "groups", "output_column": "name", "output_value": "name" + }, + { + "input_column": "id", + "input_value": "id", + "isList": false, + "db": "groups", + "output_column": "type", + "output_value": "type" } ], - "formatZH": "删除虚拟机镜像 [name]", - "formatEN": "delete VM ISO [name]" + "formatZH": "删除组 [type][name]", + "formatEN": "delete group [type][name]" }, - "/core/xpack/vms/iso/update": { + "/core/groups/update": { "bodyKeys": [ "name", "type" ], "paramKeys": [], "beforeFunctions": [], - "formatZH": "更新虚拟机镜像 [name] [type]", - "formatEN": "update VM ISO [name] [type]" + "formatZH": "更新组 [name][type]", + "formatEN": "update group [name][type]" }, - "/core/xpack/vms/networks": { - "bodyKeys": [ - "name", - "type" - ], + "/core/licenses/bind": { + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "创建虚拟机网络 [name] [type]", - "formatEN": "create VM network [name] [type]" - }, - "/core/xpack/vms/networks/del": { - "bodyKeys": [ - "id" - ], - "paramKeys": [], - "beforeFunctions": [ - { - "input_column": "id", - "input_value": "id", - "isList": false, - "db": "vm_networks", - "output_column": "name", - "output_value": "name" - } - ], - "formatZH": "删除虚拟机网络 [name]", - "formatEN": "delete VM network [name]" - }, - "/core/xpack/vms/networks/update": { - "bodyKeys": [ - "id" - ], - "paramKeys": [], - "beforeFunctions": [ - { - "input_column": "id", - "input_value": "id", - "isList": false, - "db": "vm_networks", - "output_column": "name", - "output_value": "name" - } - ], - "formatZH": "更新虚拟机网络 [name]", - "formatEN": "update VM network [name]" + "formatZH": "绑定许可证", + "formatEN": "bind license" }, - "/core/xpack/vms/operate": { - "bodyKeys": [ - "name", - "operate" - ], + "/core/licenses/bind/free": { + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "操作虚拟机 [name] [operate]", - "formatEN": "operate VM [name] [operate]" + "formatZH": "修改许可证免费节点绑定", + "formatEN": "change bind of free node for license" }, - "/core/xpack/vms/orphans/clean": { + "/core/licenses/del": { "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "清理虚拟机孤立数据", - "formatEN": "clean VM orphaned data" + "formatZH": "删除许可证", + "formatEN": "delete license" }, - "/core/xpack/vms/rename": { - "bodyKeys": [ - "name", - "newName" - ], + "/core/licenses/sync": { + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "重命名虚拟机 [name] 为 [newName]", - "formatEN": "rename VM [name] to [newName]" + "formatZH": "同步许可证信息", + "formatEN": "sync license info" }, - "/core/xpack/vms/snapshots": { - "bodyKeys": [ - "name", - "snapshotName" - ], + "/core/licenses/unbind": { + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "创建虚拟机 [name] 快照 [snapshotName]", - "formatEN": "create VM [name] snapshot [snapshotName]" + "formatZH": "解绑许可证", + "formatEN": "unbind license" }, - "/core/xpack/vms/snapshots/del": { - "bodyKeys": [ - "name", - "snapshotName" - ], + "/core/licenses/update": { + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "删除虚拟机 [name] 快照 [snapshotName]", - "formatEN": "delete VM [name] snapshot [snapshotName]" + "formatZH": "替换许可证", + "formatEN": "change license" }, - "/core/xpack/vms/snapshots/recover": { - "bodyKeys": [ - "name", - "snapshotName" - ], + "/core/licenses/upload": { + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "恢复虚拟机 [name] 快照 [snapshotName]", - "formatEN": "recover VM [name] snapshot [snapshotName]" + "formatZH": "添加许可证", + "formatEN": "import license" }, - "/core/xpack/vms/storages": { + "/core/logs/clean": { "bodyKeys": [ - "name", - "type" + "logType" ], "paramKeys": [], "beforeFunctions": [], - "formatZH": "创建虚拟机存储 [name] [type]", - "formatEN": "create VM storage [name] [type]" + "formatZH": "清空 [logType] 日志信息", + "formatEN": "Clean the [logType] log information" }, - "/core/xpack/vms/storages/del": { + "/core/script": { "bodyKeys": [ - "id" + "name" ], "paramKeys": [], - "beforeFunctions": [ - { - "input_column": "id", - "input_value": "id", - "isList": false, - "db": "vm_storages", - "output_column": "name", - "output_value": "name" - } - ], - "formatZH": "删除虚拟机存储 [name]", - "formatEN": "delete VM storage [name]" + "beforeFunctions": [], + "formatZH": "添加脚本库脚本 [name]", + "formatEN": "add script [name]" }, - "/core/xpack/vms/storages/update": { + "/core/script/del": { "bodyKeys": [ - "id" + "ids" ], "paramKeys": [], "beforeFunctions": [ { "input_column": "id", - "input_value": "id", - "isList": false, - "db": "vm_storages", + "input_value": "ids", + "isList": true, + "db": "script_librarys", "output_column": "name", - "output_value": "name" + "output_value": "names" } ], - "formatZH": "更新虚拟机存储 [name]", - "formatEN": "update VM storage [name]" + "formatZH": "删除脚本库脚本 [names]", + "formatEN": "delete script [names]" }, - "/core/xpack/vms/sync": { + "/core/script/sync": { "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "同步虚拟机", - "formatEN": "sync virtual machines" - }, - "/core/xpack/vms/templates": { - "bodyKeys": [ - "name", - "templateName" - ], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "创建虚拟机 [name] 模板 [templateName]", - "formatEN": "create VM [name] template [templateName]" + "formatZH": "同步脚本库脚本", + "formatEN": "sync scripts" }, - "/core/xpack/vms/templates/del": { + "/core/script/update": { "bodyKeys": [ "id" ], @@ -1984,195 +1903,30 @@ "input_column": "id", "input_value": "id", "isList": false, - "db": "vm_templates", + "db": "cronjobs", "output_column": "name", "output_value": "name" } ], - "formatZH": "删除虚拟机模板 [name]", - "formatEN": "delete VM template [name]" + "formatZH": "更新脚本库脚本 [name]", + "formatEN": "update script [name]" }, - "/core/xpack/vms/update": { + "/core/settings/bind/update": { "bodyKeys": [ - "name" + "ipv6", + "bindAddress" ], "paramKeys": [], "beforeFunctions": [], - "formatZH": "更新虚拟机 [name]", - "formatEN": "update VM [name]" + "formatZH": "修改系统监听信息 =\u003e ipv6: [ipv6], 监听 IP: [bindAddress]", + "formatEN": "update system bind info =\u003e ipv6: [ipv6], 监听 IP: [bindAddress]" }, - "/core/groups": { - "bodyKeys": [ - "name", - "type" - ], + "/core/settings/memo": { + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "创建组 [name][type]", - "formatEN": "create group [name][type]" - }, - "/core/groups/del": { - "bodyKeys": [ - "id" - ], - "paramKeys": [], - "beforeFunctions": [ - { - "input_column": "id", - "input_value": "id", - "isList": false, - "db": "groups", - "output_column": "name", - "output_value": "name" - }, - { - "input_column": "id", - "input_value": "id", - "isList": false, - "db": "groups", - "output_column": "type", - "output_value": "type" - } - ], - "formatZH": "删除组 [type][name]", - "formatEN": "delete group [type][name]" - }, - "/core/groups/update": { - "bodyKeys": [ - "name", - "type" - ], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "更新组 [name][type]", - "formatEN": "update group [name][type]" - }, - "/core/licenses/bind": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "绑定许可证", - "formatEN": "bind license" - }, - "/core/licenses/bind/free": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "修改许可证免费节点绑定", - "formatEN": "change bind of free node for license" - }, - "/core/licenses/del": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "删除许可证", - "formatEN": "delete license" - }, - "/core/licenses/sync": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "同步许可证信息", - "formatEN": "sync license info" - }, - "/core/licenses/unbind": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "解绑许可证", - "formatEN": "unbind license" - }, - "/core/licenses/update": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "替换许可证", - "formatEN": "change license" - }, - "/core/licenses/upload": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "添加许可证", - "formatEN": "import license" - }, - "/core/logs/clean": { - "bodyKeys": [ - "logType" - ], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "清空 [logType] 日志信息", - "formatEN": "Clean the [logType] log information" - }, - "/core/script": { - "bodyKeys": [ - "name" - ], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "添加脚本库脚本 [name]", - "formatEN": "add script [name]" - }, - "/core/script/del": { - "bodyKeys": [ - "ids" - ], - "paramKeys": [], - "beforeFunctions": [ - { - "input_column": "id", - "input_value": "ids", - "isList": true, - "db": "script_librarys", - "output_column": "name", - "output_value": "names" - } - ], - "formatZH": "删除脚本库脚本 [names]", - "formatEN": "delete script [names]" - }, - "/core/script/sync": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "同步脚本库脚本", - "formatEN": "sync scripts" - }, - "/core/script/update": { - "bodyKeys": [ - "id" - ], - "paramKeys": [], - "beforeFunctions": [ - { - "input_column": "id", - "input_value": "id", - "isList": false, - "db": "cronjobs", - "output_column": "name", - "output_value": "name" - } - ], - "formatZH": "更新脚本库脚本 [name]", - "formatEN": "update script [name]" - }, - "/core/settings/bind/update": { - "bodyKeys": [ - "ipv6", - "bindAddress" - ], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "修改系统监听信息 =\u003e ipv6: [ipv6], 监听 IP: [bindAddress]", - "formatEN": "update system bind info =\u003e ipv6: [ipv6], 监听 IP: [bindAddress]" - }, - "/core/settings/memo": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "更新仪表盘备忘录", - "formatEN": "update dashboard memo" + "formatZH": "更新仪表盘备忘录", + "formatEN": "update dashboard memo" }, "/core/settings/menu/default": { "bodyKeys": [], @@ -2705,6 +2459,262 @@ "formatZH": "同步 SSL 证书 [primaryDomain]", "formatEN": "sync SSL certificate [primaryDomain]" }, + "/core/xpack/vms": { + "bodyKeys": [ + "name" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "创建虚拟机 [name]", + "formatEN": "create VM [name]" + }, + "/core/xpack/vms/del": { + "bodyKeys": [ + "name" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "删除虚拟机 [name]", + "formatEN": "delete VM [name]" + }, + "/core/xpack/vms/environment/enable": { + "bodyKeys": [], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "启用虚拟机运行环境", + "formatEN": "enable VM runtime environment" + }, + "/core/xpack/vms/iso": { + "bodyKeys": [ + "name", + "type" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "创建虚拟机镜像 [name] [type]", + "formatEN": "create VM ISO [name] [type]" + }, + "/core/xpack/vms/iso/del": { + "bodyKeys": [ + "id" + ], + "paramKeys": [], + "beforeFunctions": [ + { + "input_column": "id", + "input_value": "id", + "isList": false, + "db": "vm_isos", + "output_column": "name", + "output_value": "name" + } + ], + "formatZH": "删除虚拟机镜像 [name]", + "formatEN": "delete VM ISO [name]" + }, + "/core/xpack/vms/iso/update": { + "bodyKeys": [ + "name", + "type" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "更新虚拟机镜像 [name] [type]", + "formatEN": "update VM ISO [name] [type]" + }, + "/core/xpack/vms/networks": { + "bodyKeys": [ + "name", + "type" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "创建虚拟机网络 [name] [type]", + "formatEN": "create VM network [name] [type]" + }, + "/core/xpack/vms/networks/del": { + "bodyKeys": [ + "id" + ], + "paramKeys": [], + "beforeFunctions": [ + { + "input_column": "id", + "input_value": "id", + "isList": false, + "db": "vm_networks", + "output_column": "name", + "output_value": "name" + } + ], + "formatZH": "删除虚拟机网络 [name]", + "formatEN": "delete VM network [name]" + }, + "/core/xpack/vms/networks/update": { + "bodyKeys": [ + "id" + ], + "paramKeys": [], + "beforeFunctions": [ + { + "input_column": "id", + "input_value": "id", + "isList": false, + "db": "vm_networks", + "output_column": "name", + "output_value": "name" + } + ], + "formatZH": "更新虚拟机网络 [name]", + "formatEN": "update VM network [name]" + }, + "/core/xpack/vms/operate": { + "bodyKeys": [ + "name", + "operate" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "操作虚拟机 [name] [operate]", + "formatEN": "operate VM [name] [operate]" + }, + "/core/xpack/vms/orphans/clean": { + "bodyKeys": [], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "清理虚拟机孤立数据", + "formatEN": "clean VM orphaned data" + }, + "/core/xpack/vms/rename": { + "bodyKeys": [ + "name", + "newName" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "重命名虚拟机 [name] 为 [newName]", + "formatEN": "rename VM [name] to [newName]" + }, + "/core/xpack/vms/snapshots": { + "bodyKeys": [ + "name", + "snapshotName" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "创建虚拟机 [name] 快照 [snapshotName]", + "formatEN": "create VM [name] snapshot [snapshotName]" + }, + "/core/xpack/vms/snapshots/del": { + "bodyKeys": [ + "name", + "snapshotName" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "删除虚拟机 [name] 快照 [snapshotName]", + "formatEN": "delete VM [name] snapshot [snapshotName]" + }, + "/core/xpack/vms/snapshots/recover": { + "bodyKeys": [ + "name", + "snapshotName" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "恢复虚拟机 [name] 快照 [snapshotName]", + "formatEN": "recover VM [name] snapshot [snapshotName]" + }, + "/core/xpack/vms/storages": { + "bodyKeys": [ + "name", + "type" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "创建虚拟机存储 [name] [type]", + "formatEN": "create VM storage [name] [type]" + }, + "/core/xpack/vms/storages/del": { + "bodyKeys": [ + "id" + ], + "paramKeys": [], + "beforeFunctions": [ + { + "input_column": "id", + "input_value": "id", + "isList": false, + "db": "vm_storages", + "output_column": "name", + "output_value": "name" + } + ], + "formatZH": "删除虚拟机存储 [name]", + "formatEN": "delete VM storage [name]" + }, + "/core/xpack/vms/storages/update": { + "bodyKeys": [ + "id" + ], + "paramKeys": [], + "beforeFunctions": [ + { + "input_column": "id", + "input_value": "id", + "isList": false, + "db": "vm_storages", + "output_column": "name", + "output_value": "name" + } + ], + "formatZH": "更新虚拟机存储 [name]", + "formatEN": "update VM storage [name]" + }, + "/core/xpack/vms/sync": { + "bodyKeys": [], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "同步虚拟机", + "formatEN": "sync virtual machines" + }, + "/core/xpack/vms/templates": { + "bodyKeys": [ + "name", + "templateName" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "创建虚拟机 [name] 模板 [templateName]", + "formatEN": "create VM [name] template [templateName]" + }, + "/core/xpack/vms/templates/del": { + "bodyKeys": [ + "id" + ], + "paramKeys": [], + "beforeFunctions": [ + { + "input_column": "id", + "input_value": "id", + "isList": false, + "db": "vm_templates", + "output_column": "name", + "output_value": "name" + } + ], + "formatZH": "删除虚拟机模板 [name]", + "formatEN": "delete VM template [name]" + }, + "/core/xpack/vms/update": { + "bodyKeys": [ + "name" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "更新虚拟机 [name]", + "formatEN": "update VM [name]" + }, "/cronjobs": { "bodyKeys": [ "type", @@ -3504,7 +3514,9 @@ "formatEN": "Download url =\u003e [path]/[name]" }, "/files/wget/process/remove": { - "bodyKeys": ["keys"], + "bodyKeys": [ + "keys" + ], "paramKeys": [], "beforeFunctions": [], "formatZH": "移除已结束下载记录 [keys]", @@ -3634,13 +3646,11 @@ "formatEN": "[operation] Docker port guard" }, "/hosts/firewall/docker/policies/batch": { - "bodyKeys": [ - "mode" - ], + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "批量更新 Docker 端口防护策略 [mode]", - "formatEN": "batch update Docker port guard policies [mode]" + "formatZH": "批量更新 Docker 端口防护策略", + "formatEN": "batch update Docker port guard policies" }, "/hosts/firewall/docker/policies/delete/batch": { "bodyKeys": [ @@ -3697,6 +3707,13 @@ "formatZH": "添加防火墙规则", "formatEN": "create firewall rules" }, + "/hosts/firewall/rules/adopt": { + "bodyKeys": [], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "纳管防火墙规则", + "formatEN": "adopt firewall rule" + }, "/hosts/firewall/rules/delete": { "bodyKeys": [], "paramKeys": [], @@ -3751,6 +3768,15 @@ "formatZH": "防火墙子系统 [subsystem] 后端 [operation] [backend]", "formatEN": "[operation] firewall [subsystem] backend [backend]" }, + "/hosts/firewall/settings/whitelist": { + "bodyKeys": [ + "value" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "更新防火墙端口白名单 [value]", + "formatEN": "update firewall port whitelist [value]" + }, "/hosts/monitor/clean": { "bodyKeys": [], "paramKeys": [], @@ -5794,4 +5820,4 @@ "formatZH": "从主节点同步设置", "formatEN": "sync settings from master" } -} +} \ No newline at end of file diff --git a/agent/i18n/lang/en.yaml b/agent/i18n/lang/en.yaml index 4af5b976bd6b..abefad70b867 100644 --- a/agent/i18n/lang/en.yaml +++ b/agent/i18n/lang/en.yaml @@ -705,3 +705,11 @@ AIProviderBailian: 'Alibaba Cloud Model Studio' AIProviderBailianCodingPlan: 'Alibaba Cloud Model Studio Coding Plan' AIProviderArk: 'Volcengine Ark' AIProviderArkCodingPlan: 'Volcengine Ark Coding Plan' + +# Firewall whitelist +ErrFirewallRuleScopeChange: "The current firewall does not support changing a rule's scope (such as its IPv4/IPv6 address family). Please create a new rule." +FirewallWhitelistTask: "Update firewall port whitelist" +FirewallWhitelistSaved: "Whitelist configuration saved" +FirewallWhitelistDeferred: "{{ .name }}: configuration saved; pending firewall activation" +FirewallWhitelistReleased: "{{ .name }}: whitelist protection released; allow rule retained. To close the port, delete the rule manually from the rule list" +FirewallWhitelistRequired: "{{ .name }}: protected by mandatory system port rules" diff --git a/agent/i18n/lang/es-ES.yaml b/agent/i18n/lang/es-ES.yaml index 01c446108bf1..9bcd4e5b990f 100644 --- a/agent/i18n/lang/es-ES.yaml +++ b/agent/i18n/lang/es-ES.yaml @@ -705,3 +705,11 @@ AIProviderBailian: 'Alibaba Cloud Model Studio' AIProviderBailianCodingPlan: 'Alibaba Cloud Model Studio Coding Plan' AIProviderArk: 'Volcengine Ark' AIProviderArkCodingPlan: 'Volcengine Ark Coding Plan' + +# Firewall whitelist +ErrFirewallRuleScopeChange: "El cortafuegos actual no permite cambiar el ámbito de una regla (como su familia de direcciones IPv4/IPv6). Cree una regla nueva." +FirewallWhitelistTask: "Actualizar la lista de puertos permitidos del cortafuegos" +FirewallWhitelistSaved: "Configuración de la lista de permitidos guardada" +FirewallWhitelistDeferred: "{{ .name }}: configuración guardada; pendiente de activar el cortafuegos" +FirewallWhitelistReleased: "{{ .name }}: protección de la lista de permitidos retirada; se conserva la regla de permiso. Para cerrar el puerto, elimine la regla manualmente de la lista" +FirewallWhitelistRequired: "{{ .name }}: protegido por las reglas de puertos obligatorios del sistema" diff --git a/agent/i18n/lang/fa.yaml b/agent/i18n/lang/fa.yaml index 6dedd72cecdd..80b4deec2c3a 100644 --- a/agent/i18n/lang/fa.yaml +++ b/agent/i18n/lang/fa.yaml @@ -705,3 +705,11 @@ AIProviderBailian: 'Alibaba Cloud Model Studio' AIProviderBailianCodingPlan: 'Alibaba Cloud Model Studio Coding Plan' AIProviderArk: 'Volcengine Ark' AIProviderArkCodingPlan: 'Volcengine Ark Coding Plan' + +# Firewall whitelist +ErrFirewallRuleScopeChange: "فایروال فعلی از تغییر محدودهٔ قانون (مانند خانوادهٔ آدرس IPv4/IPv6) پشتیبانی نمی‌کند. لطفاً یک قانون جدید ایجاد کنید." +FirewallWhitelistTask: "به‌روزرسانی فهرست پورت‌های مجاز فایروال" +FirewallWhitelistSaved: "پیکربندی فهرست مجاز ذخیره شد" +FirewallWhitelistDeferred: "{{ .name }}: پیکربندی ذخیره شد؛ در انتظار فعال‌سازی فایروال" +FirewallWhitelistReleased: "{{ .name }}: حفاظت فهرست مجاز برداشته شد؛ قانون اجازه حفظ می‌شود. برای بستن پورت، قانون را به‌صورت دستی از فهرست قوانین حذف کنید" +FirewallWhitelistRequired: "{{ .name }}: توسط قوانین پورت‌های ضروری سیستم محافظت می‌شود" diff --git a/agent/i18n/lang/ja.yaml b/agent/i18n/lang/ja.yaml index 9d41d050307e..e108c62e0261 100644 --- a/agent/i18n/lang/ja.yaml +++ b/agent/i18n/lang/ja.yaml @@ -705,3 +705,11 @@ AIProviderBailian: 'Alibaba Cloud Model Studio' AIProviderBailianCodingPlan: 'Alibaba Cloud Model Studio Coding Plan' AIProviderArk: 'Volcengine Ark' AIProviderArkCodingPlan: 'Volcengine Ark Coding Plan' + +# Firewall whitelist +ErrFirewallRuleScopeChange: "現在のファイアウォールでは、ルールの適用範囲(IPv4/IPv6 アドレスファミリーなど)を変更できません。新しいルールを作成してください。" +FirewallWhitelistTask: "ファイアウォールのポート許可リストを更新" +FirewallWhitelistSaved: "許可リストの設定を保存しました" +FirewallWhitelistDeferred: "{{ .name }}:設定を保存しました。ファイアウォールの有効化後に適用します" +FirewallWhitelistReleased: "{{ .name }}:許可リストの保護を解除しました。許可ルールは保持されます。ポートを閉じるには、ルール一覧から手動で削除してください" +FirewallWhitelistRequired: "{{ .name }}:システム必須ポートのルールで保護されています" diff --git a/agent/i18n/lang/ko.yaml b/agent/i18n/lang/ko.yaml index f5c57cf91251..646708085a65 100644 --- a/agent/i18n/lang/ko.yaml +++ b/agent/i18n/lang/ko.yaml @@ -705,3 +705,11 @@ AIProviderBailian: 'Alibaba Cloud Model Studio' AIProviderBailianCodingPlan: 'Alibaba Cloud Model Studio Coding Plan' AIProviderArk: 'Volcengine Ark' AIProviderArkCodingPlan: 'Volcengine Ark Coding Plan' + +# Firewall whitelist +ErrFirewallRuleScopeChange: "현재 방화벽에서는 규칙의 적용 범위(예: IPv4/IPv6 주소 패밀리)를 변경할 수 없습니다. 새 규칙을 생성하세요." +FirewallWhitelistTask: "방화벽 포트 허용 목록 업데이트" +FirewallWhitelistSaved: "허용 목록 설정이 저장되었습니다" +FirewallWhitelistDeferred: "{{ .name }}: 설정이 저장되었으며 방화벽 활성화 후 적용됩니다" +FirewallWhitelistReleased: "{{ .name }}: 허용 목록 보호가 해제되었으며 허용 규칙은 유지됩니다. 포트를 닫으려면 규칙 목록에서 수동으로 삭제하세요" +FirewallWhitelistRequired: "{{ .name }}: 시스템 필수 포트 규칙으로 보호됩니다" diff --git a/agent/i18n/lang/lo.yaml b/agent/i18n/lang/lo.yaml index 67a5c20ffd54..8ca123a02c38 100644 --- a/agent/i18n/lang/lo.yaml +++ b/agent/i18n/lang/lo.yaml @@ -696,3 +696,11 @@ AIProviderBailian: 'Alibaba Cloud Model Studio' AIProviderBailianCodingPlan: 'Alibaba Cloud Model Studio Coding Plan' AIProviderArk: 'Volcengine Ark' AIProviderArkCodingPlan: 'Volcengine Ark Coding Plan' + +# Firewall whitelist +ErrFirewallRuleScopeChange: "ໄຟວໍປັດຈຸບັນບໍ່ຮອງຮັບການປ່ຽນຂອບເຂດຂອງກົດ (ເຊັ່ນ ຕະກູນທີ່ຢູ່ IPv4/IPv6). ກະລຸນາສ້າງກົດໃໝ່." +FirewallWhitelistTask: "ອັບເດດລາຍຊື່ພອດທີ່ອະນຸຍາດຂອງໄຟວໍ" +FirewallWhitelistSaved: "ບັນທຶກການຕັ້ງຄ່າລາຍຊື່ທີ່ອະນຸຍາດແລ້ວ" +FirewallWhitelistDeferred: "{{ .name }}: ບັນທຶກການຕັ້ງຄ່າແລ້ວ; ລໍຖ້າເປີດໃຊ້ໄຟວໍ" +FirewallWhitelistReleased: "{{ .name }}: ຍົກເລີກການປ້ອງກັນລາຍຊື່ທີ່ອະນຸຍາດແລ້ວ; ຍັງຄົງກົດອະນຸຍາດໄວ້. ຫາກຕ້ອງການປິດພອດ ໃຫ້ລຶບກົດດ້ວຍຕົນເອງຈາກລາຍການກົດ" +FirewallWhitelistRequired: "{{ .name }}: ປ້ອງກັນໂດຍກົດພອດທີ່ຈຳເປັນຂອງລະບົບ" diff --git a/agent/i18n/lang/ms.yaml b/agent/i18n/lang/ms.yaml index 8b66fb31cd20..8b76e9440c17 100644 --- a/agent/i18n/lang/ms.yaml +++ b/agent/i18n/lang/ms.yaml @@ -705,3 +705,11 @@ AIProviderBailian: 'Alibaba Cloud Model Studio' AIProviderBailianCodingPlan: 'Alibaba Cloud Model Studio Coding Plan' AIProviderArk: 'Volcengine Ark' AIProviderArkCodingPlan: 'Volcengine Ark Coding Plan' + +# Firewall whitelist +ErrFirewallRuleScopeChange: "Tembok api semasa tidak menyokong perubahan skop peraturan (seperti keluarga alamat IPv4/IPv6). Sila cipta peraturan baharu." +FirewallWhitelistTask: "Kemas kini senarai port dibenarkan tembok api" +FirewallWhitelistSaved: "Konfigurasi senarai dibenarkan telah disimpan" +FirewallWhitelistDeferred: "{{ .name }}: konfigurasi disimpan; menunggu pengaktifan tembok api" +FirewallWhitelistReleased: "{{ .name }}: perlindungan senarai dibenarkan telah dilepaskan; peraturan izin dikekalkan. Untuk menutup port, padamkan peraturan secara manual daripada senarai peraturan" +FirewallWhitelistRequired: "{{ .name }}: dilindungi oleh peraturan port wajib sistem" diff --git a/agent/i18n/lang/pt-BR.yaml b/agent/i18n/lang/pt-BR.yaml index ff6a209ebda2..9160a629ef99 100644 --- a/agent/i18n/lang/pt-BR.yaml +++ b/agent/i18n/lang/pt-BR.yaml @@ -705,3 +705,11 @@ AIProviderBailian: 'Alibaba Cloud Model Studio' AIProviderBailianCodingPlan: 'Alibaba Cloud Model Studio Coding Plan' AIProviderArk: 'Volcengine Ark' AIProviderArkCodingPlan: 'Volcengine Ark Coding Plan' + +# Firewall whitelist +ErrFirewallRuleScopeChange: "O firewall atual não permite alterar o escopo de uma regra (como a família de endereços IPv4/IPv6). Crie uma nova regra." +FirewallWhitelistTask: "Atualizar a lista de portas permitidas do firewall" +FirewallWhitelistSaved: "Configuração da lista de permissões salva" +FirewallWhitelistDeferred: "{{ .name }}: configuração salva; aguardando a ativação do firewall" +FirewallWhitelistReleased: "{{ .name }}: proteção da lista de permissões removida; regra de permissão mantida. Para fechar a porta, exclua a regra manualmente da lista" +FirewallWhitelistRequired: "{{ .name }}: protegido pelas regras de portas obrigatórias do sistema" diff --git a/agent/i18n/lang/ru.yaml b/agent/i18n/lang/ru.yaml index 6651ea52873b..8023a73620b6 100644 --- a/agent/i18n/lang/ru.yaml +++ b/agent/i18n/lang/ru.yaml @@ -705,3 +705,11 @@ AIProviderBailian: 'Alibaba Cloud Model Studio' AIProviderBailianCodingPlan: 'Alibaba Cloud Model Studio Coding Plan' AIProviderArk: 'Volcengine Ark' AIProviderArkCodingPlan: 'Volcengine Ark Coding Plan' + +# Firewall whitelist +ErrFirewallRuleScopeChange: "Текущий межсетевой экран не поддерживает изменение области действия правила (например, семейства адресов IPv4/IPv6). Создайте новое правило." +FirewallWhitelistTask: "Обновить список разрешённых портов межсетевого экрана" +FirewallWhitelistSaved: "Настройки списка разрешённых портов сохранены" +FirewallWhitelistDeferred: "{{ .name }}: настройки сохранены; ожидается включение межсетевого экрана" +FirewallWhitelistReleased: "{{ .name }}: защита списка разрешённых портов снята; разрешающее правило сохранено. Чтобы закрыть порт, удалите правило вручную из списка правил" +FirewallWhitelistRequired: "{{ .name }}: защищён обязательными правилами системных портов" diff --git a/agent/i18n/lang/tr.yaml b/agent/i18n/lang/tr.yaml index 7eb0c3f90576..9877269fc678 100644 --- a/agent/i18n/lang/tr.yaml +++ b/agent/i18n/lang/tr.yaml @@ -705,3 +705,11 @@ AIProviderBailian: 'Alibaba Cloud Model Studio' AIProviderBailianCodingPlan: 'Alibaba Cloud Model Studio Coding Plan' AIProviderArk: 'Volcengine Ark' AIProviderArkCodingPlan: 'Volcengine Ark Coding Plan' + +# Firewall whitelist +ErrFirewallRuleScopeChange: "Mevcut güvenlik duvarı, kuralın kapsamını (IPv4/IPv6 adres ailesi gibi) değiştirmeyi desteklemiyor. Lütfen yeni bir kural oluşturun." +FirewallWhitelistTask: "Güvenlik duvarı izin verilen port listesini güncelle" +FirewallWhitelistSaved: "İzin verilenler listesi yapılandırması kaydedildi" +FirewallWhitelistDeferred: "{{ .name }}: yapılandırma kaydedildi; güvenlik duvarının etkinleştirilmesi bekleniyor" +FirewallWhitelistReleased: "{{ .name }}: izin listesi koruması kaldırıldı; izin kuralı korundu. Portu kapatmak için kuralı kural listesinden elle silin" +FirewallWhitelistRequired: "{{ .name }}: zorunlu sistem portu kuralları tarafından korunuyor" diff --git a/agent/i18n/lang/zh-Hant.yaml b/agent/i18n/lang/zh-Hant.yaml index 0a05dcdca8b8..65ba9e91e0cf 100644 --- a/agent/i18n/lang/zh-Hant.yaml +++ b/agent/i18n/lang/zh-Hant.yaml @@ -705,3 +705,11 @@ AIProviderBailian: '阿里雲百煉' AIProviderBailianCodingPlan: '阿里雲百煉 Coding Plan' AIProviderArk: '火山方舟' AIProviderArkCodingPlan: '火山方舟 Coding Plan' + +# Firewall whitelist +ErrFirewallRuleScopeChange: "目前的防火牆不支援修改規則的作用範圍(如 IPv4/IPv6 位址族),請建立新規則。" +FirewallWhitelistTask: "更新防火牆連接埠白名單" +FirewallWhitelistSaved: "白名單設定已儲存" +FirewallWhitelistDeferred: "{{ .name }}:設定已儲存,待防火牆啟用後套用" +FirewallWhitelistReleased: "{{ .name }}:已解除白名單保護,放行規則保留;如需關閉連接埠,請在規則清單手動刪除" +FirewallWhitelistRequired: "{{ .name }}:由系統必要連接埠規則保護" diff --git a/agent/i18n/lang/zh.yaml b/agent/i18n/lang/zh.yaml index 9e778895c81e..32e39285f0eb 100644 --- a/agent/i18n/lang/zh.yaml +++ b/agent/i18n/lang/zh.yaml @@ -705,3 +705,11 @@ AIProviderBailian: "阿里云百炼" AIProviderBailianCodingPlan: "阿里云百炼 Coding Plan" AIProviderArk: "火山方舟" AIProviderArkCodingPlan: "火山方舟 Coding Plan" + +# Firewall whitelist +ErrFirewallRuleScopeChange: "当前防火墙不支持修改规则的作用范围(如 IPv4/IPv6 地址族),请新建规则。" +FirewallWhitelistTask: "更新防火墙端口白名单" +FirewallWhitelistSaved: "白名单配置已保存" +FirewallWhitelistDeferred: "{{ .name }}:配置已保存,待防火墙启用后下发" +FirewallWhitelistReleased: "{{ .name }}:已解除白名单保护,放行规则保留;如需关闭端口,请在规则列表手动删除" +FirewallWhitelistRequired: "{{ .name }}:由系统必需端口规则保护" diff --git a/agent/router/ro_host.go b/agent/router/ro_host.go index 5b38adb8a47f..43d886624ef0 100644 --- a/agent/router/ro_host.go +++ b/agent/router/ro_host.go @@ -27,6 +27,7 @@ func (s *HostRouter) InitRouter(Router *gin.RouterGroup) { hostRouter.POST("/firewall/port", baseApi.UpdatePanelFirewallPort) hostRouter.GET("/firewall/settings", baseApi.LoadFirewallSettings) hostRouter.POST("/firewall/settings/operate", baseApi.OperateFirewallBackend) + hostRouter.POST("/firewall/settings/whitelist", baseApi.UpdateFirewallPortWhitelist) hostRouter.POST("/firewall/forward/base", baseApi.LoadForwardingBaseInfo) hostRouter.POST("/firewall/forward/search", baseApi.SearchForwardingRules) hostRouter.POST("/firewall/forward/operate", baseApi.OperateForwardingRules) diff --git a/agent/utils/firewall/filter/model.go b/agent/utils/firewall/filter/model.go index 4d0e3966caf6..464db9e24bb2 100644 --- a/agent/utils/firewall/filter/model.go +++ b/agent/utils/firewall/filter/model.go @@ -108,12 +108,13 @@ type ScopeNotice struct { } var ( - ErrInvalidScope = errors.New("invalid firewall scope") - ErrUnsupportedScope = errors.New("unsupported firewall scope") - ErrInvalidRule = errors.New("invalid firewall rule") - ErrProtectedRule = errors.New("protected firewall rule cannot be modified") - ErrCompositeRule = errors.New("firewall rule must be atomic") - ErrExpansionLimit = errors.New("firewall rule expansion limit exceeded") + ErrInvalidScope = errors.New("invalid firewall scope") + ErrUnsupportedScope = errors.New("unsupported firewall scope") + ErrManagedScopeChange = fmt.Errorf("%w: managed rule scope cannot be changed", ErrUnsupportedScope) + ErrInvalidRule = errors.New("invalid firewall rule") + ErrProtectedRule = errors.New("protected firewall rule cannot be modified") + ErrCompositeRule = errors.New("firewall rule must be atomic") + ErrExpansionLimit = errors.New("firewall rule expansion limit exceeded") ) type Scope struct { diff --git a/agent/utils/firewall/filter/providers/ufw/adapter.go b/agent/utils/firewall/filter/providers/ufw/adapter.go index 397fe4ee808e..911bdb73c6a4 100644 --- a/agent/utils/firewall/filter/providers/ufw/adapter.go +++ b/agent/utils/firewall/filter/providers/ufw/adapter.go @@ -336,7 +336,7 @@ func compileChange(snapshot filter.Snapshot, change filter.DesiredChange) (filte return filter.NativeRulePlan{}, fmt.Errorf("%w: create target is out of range", filter.ErrInvalidRule) } command := insertCommand(position, normalized, marker) - if change.Append { + if change.Append || position == maximumObservedPosition(snapshot)+1 { command = commentCommand(normalized, marker) plan.Expected.Locator.NativeID = "" plan.Expected.Locator.Position = nil diff --git a/core/cmd/server/docs/docs.go b/core/cmd/server/docs/docs.go index f6502b68124b..ac69159eeb30 100644 --- a/core/cmd/server/docs/docs.go +++ b/core/cmd/server/docs/docs.go @@ -19413,6 +19413,54 @@ const docTemplate = `{ } } }, + "/hosts/firewall/settings/whitelist": { + "post": { + "consumes": [ + "application/json" + ], + "description": "Returns a taskID; configuration save and per-rule results are recorded in the task log.", + "parameters": [ + { + "description": "request", + "in": "body", + "name": "request", + "required": true, + "schema": { + "$ref": "#/definitions/dto.FirewallPortWhitelistUpdate" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dto.FilterChainOperationResponse" + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "summary": "Queue firewall port whitelist update", + "tags": [ + "Firewall" + ], + "x-panel-log": { + "BeforeFunctions": [], + "bodyKeys": [ + "value" + ], + "formatEN": "update firewall port whitelist [value]", + "formatZH": "更新防火墙端口白名单 [value]", + "paramKeys": [] + } + } + }, "/hosts/info": { "post": { "consumes": [ @@ -31901,8 +31949,7 @@ const docTemplate = `{ "enum": [ "SystemIP", "DockerSockPath", - "FileRecycleBin", - "FirewallPortWhiteList" + "FileRecycleBin" ], "type": "string" }, @@ -36405,6 +36452,17 @@ const docTemplate = `{ ], "type": "object" }, + "dto.FirewallPortWhitelistUpdate": { + "properties": { + "value": { + "type": "string" + } + }, + "required": [ + "value" + ], + "type": "object" + }, "dto.FirewallSettings": { "properties": { "docker": { diff --git a/core/cmd/server/docs/swagger.json b/core/cmd/server/docs/swagger.json index 8ec6681ce51d..a92e151bf916 100644 --- a/core/cmd/server/docs/swagger.json +++ b/core/cmd/server/docs/swagger.json @@ -19409,6 +19409,54 @@ } } }, + "/hosts/firewall/settings/whitelist": { + "post": { + "consumes": [ + "application/json" + ], + "description": "Returns a taskID; configuration save and per-rule results are recorded in the task log.", + "parameters": [ + { + "description": "request", + "in": "body", + "name": "request", + "required": true, + "schema": { + "$ref": "#/definitions/dto.FirewallPortWhitelistUpdate" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dto.FilterChainOperationResponse" + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "Timestamp": [] + } + ], + "summary": "Queue firewall port whitelist update", + "tags": [ + "Firewall" + ], + "x-panel-log": { + "BeforeFunctions": [], + "bodyKeys": [ + "value" + ], + "formatEN": "update firewall port whitelist [value]", + "formatZH": "更新防火墙端口白名单 [value]", + "paramKeys": [] + } + } + }, "/hosts/info": { "post": { "consumes": [ @@ -31897,8 +31945,7 @@ "enum": [ "SystemIP", "DockerSockPath", - "FileRecycleBin", - "FirewallPortWhiteList" + "FileRecycleBin" ], "type": "string" }, @@ -36401,6 +36448,17 @@ ], "type": "object" }, + "dto.FirewallPortWhitelistUpdate": { + "properties": { + "value": { + "type": "string" + } + }, + "required": [ + "value" + ], + "type": "object" + }, "dto.FirewallSettings": { "properties": { "docker": { diff --git a/core/cmd/server/docs/x-log.json b/core/cmd/server/docs/x-log.json index f48d7aa591a2..a5bbfaa907d7 100644 --- a/core/cmd/server/docs/x-log.json +++ b/core/cmd/server/docs/x-log.json @@ -116,6 +116,16 @@ "formatZH": "删除告警配置 [id]", "formatEN": "delete alert config [id]" }, + "/alert/config/status": { + "bodyKeys": [ + "id", + "status" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "更新告警配置状态 [id][status]", + "formatEN": "update alert config status [id][status]" + }, "/alert/config/update": { "bodyKeys": [ "id", @@ -1745,42 +1755,17 @@ "formatZH": "更新 [name]", "formatEN": "update user [name]" }, - "/core/xpack/vms": { - "bodyKeys": [ - "name" - ], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "创建虚拟机 [name]", - "formatEN": "create VM [name]" - }, - "/core/xpack/vms/del": { - "bodyKeys": [ - "name" - ], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "删除虚拟机 [name]", - "formatEN": "delete VM [name]" - }, - "/core/xpack/vms/environment/enable": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "启用虚拟机运行环境", - "formatEN": "enable VM runtime environment" - }, - "/core/xpack/vms/iso": { + "/core/groups": { "bodyKeys": [ "name", "type" ], "paramKeys": [], "beforeFunctions": [], - "formatZH": "创建虚拟机镜像 [name] [type]", - "formatEN": "create VM ISO [name] [type]" + "formatZH": "创建组 [name][type]", + "formatEN": "create group [name][type]" }, - "/core/xpack/vms/iso/del": { + "/core/groups/del": { "bodyKeys": [ "id" ], @@ -1790,191 +1775,125 @@ "input_column": "id", "input_value": "id", "isList": false, - "db": "vm_isos", + "db": "groups", "output_column": "name", "output_value": "name" + }, + { + "input_column": "id", + "input_value": "id", + "isList": false, + "db": "groups", + "output_column": "type", + "output_value": "type" } ], - "formatZH": "删除虚拟机镜像 [name]", - "formatEN": "delete VM ISO [name]" + "formatZH": "删除组 [type][name]", + "formatEN": "delete group [type][name]" }, - "/core/xpack/vms/iso/update": { + "/core/groups/update": { "bodyKeys": [ "name", "type" ], "paramKeys": [], "beforeFunctions": [], - "formatZH": "更新虚拟机镜像 [name] [type]", - "formatEN": "update VM ISO [name] [type]" + "formatZH": "更新组 [name][type]", + "formatEN": "update group [name][type]" }, - "/core/xpack/vms/networks": { - "bodyKeys": [ - "name", - "type" - ], + "/core/licenses/bind": { + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "创建虚拟机网络 [name] [type]", - "formatEN": "create VM network [name] [type]" - }, - "/core/xpack/vms/networks/del": { - "bodyKeys": [ - "id" - ], - "paramKeys": [], - "beforeFunctions": [ - { - "input_column": "id", - "input_value": "id", - "isList": false, - "db": "vm_networks", - "output_column": "name", - "output_value": "name" - } - ], - "formatZH": "删除虚拟机网络 [name]", - "formatEN": "delete VM network [name]" - }, - "/core/xpack/vms/networks/update": { - "bodyKeys": [ - "id" - ], - "paramKeys": [], - "beforeFunctions": [ - { - "input_column": "id", - "input_value": "id", - "isList": false, - "db": "vm_networks", - "output_column": "name", - "output_value": "name" - } - ], - "formatZH": "更新虚拟机网络 [name]", - "formatEN": "update VM network [name]" + "formatZH": "绑定许可证", + "formatEN": "bind license" }, - "/core/xpack/vms/operate": { - "bodyKeys": [ - "name", - "operate" - ], + "/core/licenses/bind/free": { + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "操作虚拟机 [name] [operate]", - "formatEN": "operate VM [name] [operate]" + "formatZH": "修改许可证免费节点绑定", + "formatEN": "change bind of free node for license" }, - "/core/xpack/vms/orphans/clean": { + "/core/licenses/del": { "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "清理虚拟机孤立数据", - "formatEN": "clean VM orphaned data" + "formatZH": "删除许可证", + "formatEN": "delete license" }, - "/core/xpack/vms/rename": { - "bodyKeys": [ - "name", - "newName" - ], + "/core/licenses/sync": { + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "重命名虚拟机 [name] 为 [newName]", - "formatEN": "rename VM [name] to [newName]" + "formatZH": "同步许可证信息", + "formatEN": "sync license info" }, - "/core/xpack/vms/snapshots": { - "bodyKeys": [ - "name", - "snapshotName" - ], + "/core/licenses/unbind": { + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "创建虚拟机 [name] 快照 [snapshotName]", - "formatEN": "create VM [name] snapshot [snapshotName]" + "formatZH": "解绑许可证", + "formatEN": "unbind license" }, - "/core/xpack/vms/snapshots/del": { - "bodyKeys": [ - "name", - "snapshotName" - ], + "/core/licenses/update": { + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "删除虚拟机 [name] 快照 [snapshotName]", - "formatEN": "delete VM [name] snapshot [snapshotName]" + "formatZH": "替换许可证", + "formatEN": "change license" }, - "/core/xpack/vms/snapshots/recover": { - "bodyKeys": [ - "name", - "snapshotName" - ], + "/core/licenses/upload": { + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "恢复虚拟机 [name] 快照 [snapshotName]", - "formatEN": "recover VM [name] snapshot [snapshotName]" + "formatZH": "添加许可证", + "formatEN": "import license" }, - "/core/xpack/vms/storages": { + "/core/logs/clean": { "bodyKeys": [ - "name", - "type" + "logType" ], "paramKeys": [], "beforeFunctions": [], - "formatZH": "创建虚拟机存储 [name] [type]", - "formatEN": "create VM storage [name] [type]" + "formatZH": "清空 [logType] 日志信息", + "formatEN": "Clean the [logType] log information" }, - "/core/xpack/vms/storages/del": { + "/core/script": { "bodyKeys": [ - "id" + "name" ], "paramKeys": [], - "beforeFunctions": [ - { - "input_column": "id", - "input_value": "id", - "isList": false, - "db": "vm_storages", - "output_column": "name", - "output_value": "name" - } - ], - "formatZH": "删除虚拟机存储 [name]", - "formatEN": "delete VM storage [name]" + "beforeFunctions": [], + "formatZH": "添加脚本库脚本 [name]", + "formatEN": "add script [name]" }, - "/core/xpack/vms/storages/update": { + "/core/script/del": { "bodyKeys": [ - "id" + "ids" ], "paramKeys": [], "beforeFunctions": [ { "input_column": "id", - "input_value": "id", - "isList": false, - "db": "vm_storages", + "input_value": "ids", + "isList": true, + "db": "script_librarys", "output_column": "name", - "output_value": "name" + "output_value": "names" } ], - "formatZH": "更新虚拟机存储 [name]", - "formatEN": "update VM storage [name]" + "formatZH": "删除脚本库脚本 [names]", + "formatEN": "delete script [names]" }, - "/core/xpack/vms/sync": { + "/core/script/sync": { "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "同步虚拟机", - "formatEN": "sync virtual machines" - }, - "/core/xpack/vms/templates": { - "bodyKeys": [ - "name", - "templateName" - ], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "创建虚拟机 [name] 模板 [templateName]", - "formatEN": "create VM [name] template [templateName]" + "formatZH": "同步脚本库脚本", + "formatEN": "sync scripts" }, - "/core/xpack/vms/templates/del": { + "/core/script/update": { "bodyKeys": [ "id" ], @@ -1984,195 +1903,30 @@ "input_column": "id", "input_value": "id", "isList": false, - "db": "vm_templates", + "db": "cronjobs", "output_column": "name", "output_value": "name" } ], - "formatZH": "删除虚拟机模板 [name]", - "formatEN": "delete VM template [name]" + "formatZH": "更新脚本库脚本 [name]", + "formatEN": "update script [name]" }, - "/core/xpack/vms/update": { + "/core/settings/bind/update": { "bodyKeys": [ - "name" + "ipv6", + "bindAddress" ], "paramKeys": [], "beforeFunctions": [], - "formatZH": "更新虚拟机 [name]", - "formatEN": "update VM [name]" + "formatZH": "修改系统监听信息 =\u003e ipv6: [ipv6], 监听 IP: [bindAddress]", + "formatEN": "update system bind info =\u003e ipv6: [ipv6], 监听 IP: [bindAddress]" }, - "/core/groups": { - "bodyKeys": [ - "name", - "type" - ], + "/core/settings/memo": { + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "创建组 [name][type]", - "formatEN": "create group [name][type]" - }, - "/core/groups/del": { - "bodyKeys": [ - "id" - ], - "paramKeys": [], - "beforeFunctions": [ - { - "input_column": "id", - "input_value": "id", - "isList": false, - "db": "groups", - "output_column": "name", - "output_value": "name" - }, - { - "input_column": "id", - "input_value": "id", - "isList": false, - "db": "groups", - "output_column": "type", - "output_value": "type" - } - ], - "formatZH": "删除组 [type][name]", - "formatEN": "delete group [type][name]" - }, - "/core/groups/update": { - "bodyKeys": [ - "name", - "type" - ], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "更新组 [name][type]", - "formatEN": "update group [name][type]" - }, - "/core/licenses/bind": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "绑定许可证", - "formatEN": "bind license" - }, - "/core/licenses/bind/free": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "修改许可证免费节点绑定", - "formatEN": "change bind of free node for license" - }, - "/core/licenses/del": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "删除许可证", - "formatEN": "delete license" - }, - "/core/licenses/sync": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "同步许可证信息", - "formatEN": "sync license info" - }, - "/core/licenses/unbind": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "解绑许可证", - "formatEN": "unbind license" - }, - "/core/licenses/update": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "替换许可证", - "formatEN": "change license" - }, - "/core/licenses/upload": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "添加许可证", - "formatEN": "import license" - }, - "/core/logs/clean": { - "bodyKeys": [ - "logType" - ], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "清空 [logType] 日志信息", - "formatEN": "Clean the [logType] log information" - }, - "/core/script": { - "bodyKeys": [ - "name" - ], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "添加脚本库脚本 [name]", - "formatEN": "add script [name]" - }, - "/core/script/del": { - "bodyKeys": [ - "ids" - ], - "paramKeys": [], - "beforeFunctions": [ - { - "input_column": "id", - "input_value": "ids", - "isList": true, - "db": "script_librarys", - "output_column": "name", - "output_value": "names" - } - ], - "formatZH": "删除脚本库脚本 [names]", - "formatEN": "delete script [names]" - }, - "/core/script/sync": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "同步脚本库脚本", - "formatEN": "sync scripts" - }, - "/core/script/update": { - "bodyKeys": [ - "id" - ], - "paramKeys": [], - "beforeFunctions": [ - { - "input_column": "id", - "input_value": "id", - "isList": false, - "db": "cronjobs", - "output_column": "name", - "output_value": "name" - } - ], - "formatZH": "更新脚本库脚本 [name]", - "formatEN": "update script [name]" - }, - "/core/settings/bind/update": { - "bodyKeys": [ - "ipv6", - "bindAddress" - ], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "修改系统监听信息 =\u003e ipv6: [ipv6], 监听 IP: [bindAddress]", - "formatEN": "update system bind info =\u003e ipv6: [ipv6], 监听 IP: [bindAddress]" - }, - "/core/settings/memo": { - "bodyKeys": [], - "paramKeys": [], - "beforeFunctions": [], - "formatZH": "更新仪表盘备忘录", - "formatEN": "update dashboard memo" + "formatZH": "更新仪表盘备忘录", + "formatEN": "update dashboard memo" }, "/core/settings/menu/default": { "bodyKeys": [], @@ -2705,6 +2459,262 @@ "formatZH": "同步 SSL 证书 [primaryDomain]", "formatEN": "sync SSL certificate [primaryDomain]" }, + "/core/xpack/vms": { + "bodyKeys": [ + "name" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "创建虚拟机 [name]", + "formatEN": "create VM [name]" + }, + "/core/xpack/vms/del": { + "bodyKeys": [ + "name" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "删除虚拟机 [name]", + "formatEN": "delete VM [name]" + }, + "/core/xpack/vms/environment/enable": { + "bodyKeys": [], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "启用虚拟机运行环境", + "formatEN": "enable VM runtime environment" + }, + "/core/xpack/vms/iso": { + "bodyKeys": [ + "name", + "type" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "创建虚拟机镜像 [name] [type]", + "formatEN": "create VM ISO [name] [type]" + }, + "/core/xpack/vms/iso/del": { + "bodyKeys": [ + "id" + ], + "paramKeys": [], + "beforeFunctions": [ + { + "input_column": "id", + "input_value": "id", + "isList": false, + "db": "vm_isos", + "output_column": "name", + "output_value": "name" + } + ], + "formatZH": "删除虚拟机镜像 [name]", + "formatEN": "delete VM ISO [name]" + }, + "/core/xpack/vms/iso/update": { + "bodyKeys": [ + "name", + "type" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "更新虚拟机镜像 [name] [type]", + "formatEN": "update VM ISO [name] [type]" + }, + "/core/xpack/vms/networks": { + "bodyKeys": [ + "name", + "type" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "创建虚拟机网络 [name] [type]", + "formatEN": "create VM network [name] [type]" + }, + "/core/xpack/vms/networks/del": { + "bodyKeys": [ + "id" + ], + "paramKeys": [], + "beforeFunctions": [ + { + "input_column": "id", + "input_value": "id", + "isList": false, + "db": "vm_networks", + "output_column": "name", + "output_value": "name" + } + ], + "formatZH": "删除虚拟机网络 [name]", + "formatEN": "delete VM network [name]" + }, + "/core/xpack/vms/networks/update": { + "bodyKeys": [ + "id" + ], + "paramKeys": [], + "beforeFunctions": [ + { + "input_column": "id", + "input_value": "id", + "isList": false, + "db": "vm_networks", + "output_column": "name", + "output_value": "name" + } + ], + "formatZH": "更新虚拟机网络 [name]", + "formatEN": "update VM network [name]" + }, + "/core/xpack/vms/operate": { + "bodyKeys": [ + "name", + "operate" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "操作虚拟机 [name] [operate]", + "formatEN": "operate VM [name] [operate]" + }, + "/core/xpack/vms/orphans/clean": { + "bodyKeys": [], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "清理虚拟机孤立数据", + "formatEN": "clean VM orphaned data" + }, + "/core/xpack/vms/rename": { + "bodyKeys": [ + "name", + "newName" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "重命名虚拟机 [name] 为 [newName]", + "formatEN": "rename VM [name] to [newName]" + }, + "/core/xpack/vms/snapshots": { + "bodyKeys": [ + "name", + "snapshotName" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "创建虚拟机 [name] 快照 [snapshotName]", + "formatEN": "create VM [name] snapshot [snapshotName]" + }, + "/core/xpack/vms/snapshots/del": { + "bodyKeys": [ + "name", + "snapshotName" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "删除虚拟机 [name] 快照 [snapshotName]", + "formatEN": "delete VM [name] snapshot [snapshotName]" + }, + "/core/xpack/vms/snapshots/recover": { + "bodyKeys": [ + "name", + "snapshotName" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "恢复虚拟机 [name] 快照 [snapshotName]", + "formatEN": "recover VM [name] snapshot [snapshotName]" + }, + "/core/xpack/vms/storages": { + "bodyKeys": [ + "name", + "type" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "创建虚拟机存储 [name] [type]", + "formatEN": "create VM storage [name] [type]" + }, + "/core/xpack/vms/storages/del": { + "bodyKeys": [ + "id" + ], + "paramKeys": [], + "beforeFunctions": [ + { + "input_column": "id", + "input_value": "id", + "isList": false, + "db": "vm_storages", + "output_column": "name", + "output_value": "name" + } + ], + "formatZH": "删除虚拟机存储 [name]", + "formatEN": "delete VM storage [name]" + }, + "/core/xpack/vms/storages/update": { + "bodyKeys": [ + "id" + ], + "paramKeys": [], + "beforeFunctions": [ + { + "input_column": "id", + "input_value": "id", + "isList": false, + "db": "vm_storages", + "output_column": "name", + "output_value": "name" + } + ], + "formatZH": "更新虚拟机存储 [name]", + "formatEN": "update VM storage [name]" + }, + "/core/xpack/vms/sync": { + "bodyKeys": [], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "同步虚拟机", + "formatEN": "sync virtual machines" + }, + "/core/xpack/vms/templates": { + "bodyKeys": [ + "name", + "templateName" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "创建虚拟机 [name] 模板 [templateName]", + "formatEN": "create VM [name] template [templateName]" + }, + "/core/xpack/vms/templates/del": { + "bodyKeys": [ + "id" + ], + "paramKeys": [], + "beforeFunctions": [ + { + "input_column": "id", + "input_value": "id", + "isList": false, + "db": "vm_templates", + "output_column": "name", + "output_value": "name" + } + ], + "formatZH": "删除虚拟机模板 [name]", + "formatEN": "delete VM template [name]" + }, + "/core/xpack/vms/update": { + "bodyKeys": [ + "name" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "更新虚拟机 [name]", + "formatEN": "update VM [name]" + }, "/cronjobs": { "bodyKeys": [ "type", @@ -3504,7 +3514,9 @@ "formatEN": "Download url =\u003e [path]/[name]" }, "/files/wget/process/remove": { - "bodyKeys": ["keys"], + "bodyKeys": [ + "keys" + ], "paramKeys": [], "beforeFunctions": [], "formatZH": "移除已结束下载记录 [keys]", @@ -3634,13 +3646,11 @@ "formatEN": "[operation] Docker port guard" }, "/hosts/firewall/docker/policies/batch": { - "bodyKeys": [ - "mode" - ], + "bodyKeys": [], "paramKeys": [], "beforeFunctions": [], - "formatZH": "批量更新 Docker 端口防护策略 [mode]", - "formatEN": "batch update Docker port guard policies [mode]" + "formatZH": "批量更新 Docker 端口防护策略", + "formatEN": "batch update Docker port guard policies" }, "/hosts/firewall/docker/policies/delete/batch": { "bodyKeys": [ @@ -3697,6 +3707,13 @@ "formatZH": "添加防火墙规则", "formatEN": "create firewall rules" }, + "/hosts/firewall/rules/adopt": { + "bodyKeys": [], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "纳管防火墙规则", + "formatEN": "adopt firewall rule" + }, "/hosts/firewall/rules/delete": { "bodyKeys": [], "paramKeys": [], @@ -3751,6 +3768,15 @@ "formatZH": "防火墙子系统 [subsystem] 后端 [operation] [backend]", "formatEN": "[operation] firewall [subsystem] backend [backend]" }, + "/hosts/firewall/settings/whitelist": { + "bodyKeys": [ + "value" + ], + "paramKeys": [], + "beforeFunctions": [], + "formatZH": "更新防火墙端口白名单 [value]", + "formatEN": "update firewall port whitelist [value]" + }, "/hosts/monitor/clean": { "bodyKeys": [], "paramKeys": [], @@ -5794,4 +5820,4 @@ "formatZH": "从主节点同步设置", "formatEN": "sync settings from master" } -} +} \ No newline at end of file diff --git a/frontend/src/api/modules/firewall.ts b/frontend/src/api/modules/firewall.ts index 4d36225a46ae..47a7281ed7b0 100644 --- a/frontend/src/api/modules/firewall.ts +++ b/frontend/src/api/modules/firewall.ts @@ -3,6 +3,9 @@ import { ResPage } from '@/api/interface'; import { Firewall } from '@/api/interface/firewall'; import { TimeoutEnum } from '@/enums/http-enum'; +export const updateFirewallPortWhitelist = (value: string) => + http.post('/hosts/firewall/settings/whitelist', { value }); + export const loadFireBaseInfo = (tab: string) => http.post('/hosts/firewall/base', { name: tab }, TimeoutEnum.T_40S); diff --git a/frontend/src/views/host/firewall/rule/operate/index.vue b/frontend/src/views/host/firewall/rule/operate/index.vue index ae6e838fa2fd..b471845ec031 100644 --- a/frontend/src/views/host/firewall/rule/operate/index.vue +++ b/frontend/src/views/host/firewall/rule/operate/index.vue @@ -208,7 +208,10 @@ const showPriorityField = computed(() => { ); }); const selectedPositionRanges = computed(() => { - const families = [...new Set(form.sourceAddresses.map((item) => item.family))]; + const families = + mode.value === 'edit' && editingRule.value + ? [editingRule.value.scope.family] + : [...new Set(form.sourceAddresses.map((item) => item.family))]; if (families.length === 0) return [{ min: 1, max: 1 }]; return families.map((family) => positionRanges.value[family] || { min: 1, max: 1 }); }); diff --git a/frontend/src/views/host/firewall/setting/index.vue b/frontend/src/views/host/firewall/setting/index.vue index 1f470635e772..a8e9c98acc13 100644 --- a/frontend/src/views/host/firewall/setting/index.vue +++ b/frontend/src/views/host/firewall/setting/index.vue @@ -104,7 +104,8 @@ - + + @@ -114,6 +115,7 @@ import { Firewall } from '@/api/interface/firewall'; import { loadFirewallSettings, operateFire, operateFirewallBackend } from '@/api/modules/firewall'; import FireRouter from '@/views/host/firewall/index.vue'; import WhiteList from '@/views/host/firewall/setting/white-list/index.vue'; +import TaskLog from '@/components/log/task/index.vue'; import { whiteListRuleCount } from '@/views/host/firewall/setting/white-list/model'; import { useGlobalStore } from '@/composables/useGlobalStore'; import i18n from '@/lang'; @@ -132,6 +134,8 @@ const savedBackends = ref>({ const pingStatus = ref('Disable'); const oldPingStatus = ref('Disable'); const whiteListRef = ref(); +const whitelistTaskRef = ref>(); +const openWhitelistTask = (taskID: string) => whitelistTaskRef.value?.openWithTaskID(taskID, true); const providerOrder: Record = { iptables: 0, diff --git a/frontend/src/views/host/firewall/setting/white-list/index.vue b/frontend/src/views/host/firewall/setting/white-list/index.vue index 36cf6acd423c..55133259cf52 100644 --- a/frontend/src/views/host/firewall/setting/white-list/index.vue +++ b/frontend/src/views/host/firewall/setting/white-list/index.vue @@ -1,9 +1,7 @@