Files
1Panel/agent/utils/firewall/sync/order.go

137 lines
4.0 KiB
Go

package sync
import (
"slices"
"strconv"
"strings"
"github.com/1Panel-dev/1Panel/agent/utils/firewall/filter"
)
func RuleOrder(snapshot filter.Snapshot, ordered []filter.InventoryItem) map[string]bool {
drifted := make(map[string]bool)
if snapshot.Scope.Provider == filter.ProviderFirewalld {
return drifted
}
markers := make([]string, 0, len(ordered))
projected := append([]filter.ObservedRule(nil), snapshot.Rules...)
markerSet := make(map[string]bool, len(ordered))
locations := make(map[string][]int, len(projected))
for index, rule := range projected {
key := locatorBucket(rule.Locator)
locations[key] = append(locations[key], index)
}
for _, item := range ordered {
if item.Desired == nil || item.Desired.Marker == "" {
continue
}
markers = append(markers, item.Desired.Marker)
markerSet[item.Desired.Marker] = true
if item.Observed != nil {
for _, index := range locations[locatorBucket(item.Observed.Locator)] {
if filter.SameLocator(projected[index].Locator, item.Observed.Locator) {
projected[index].Marker = item.Desired.Marker
break
}
}
}
}
actual := make([]string, 0, len(markers))
presentMarkers := make(map[string]bool, len(markers))
for _, rule := range projected {
if markerSet[rule.Marker] {
actual = append(actual, rule.Marker)
presentMarkers[rule.Marker] = true
}
}
present := make([]string, 0, len(actual))
for _, marker := range markers {
if presentMarkers[marker] {
present = append(present, marker)
}
}
for index, marker := range present {
if actual[index] != marker {
drifted[marker] = true
drifted[actual[index]] = true
}
}
return drifted
}
func InsertionPosition(snapshot filter.Snapshot, markers []string, target string) *int64 {
if snapshot.Scope.Provider == filter.ProviderFirewalld {
return nil
}
positions := make(map[string]int, len(snapshot.Rules))
for _, rule := range snapshot.Rules {
if _, exists := positions[rule.Marker]; !exists && rule.Locator.Position != nil {
positions[rule.Marker] = *rule.Locator.Position
}
}
targetIndex := slices.Index(markers, target)
for index := targetIndex - 1; index >= 0; index-- {
if previous, ok := positions[markers[index]]; ok {
position := int64(previous + 1)
return &position
}
}
if targetIndex >= 0 {
for _, marker := range markers[targetIndex+1:] {
if next, ok := positions[marker]; ok {
position := int64(next)
return &position
}
}
}
return nil
}
func DeleteChange(snapshot filter.Snapshot, previous filter.ObservedRule, desired filter.DesiredRule) (filter.DesiredChange, error) {
beforeKey, err := filter.RuleKey(previous.Rule)
if err != nil {
return filter.DesiredChange{}, err
}
matches := make([]filter.ObservedRule, 0, 1)
for _, current := range snapshot.Rules {
if previous.Marker != "" {
if current.Marker != previous.Marker {
continue
}
} else if current.Marker != "" || !filter.SameLocator(current.Locator, previous.Locator) {
continue
}
key, err := filter.RuleKey(current.Rule)
if err == nil && key == beforeKey {
matches = append(matches, current)
}
}
if len(matches) != 1 {
return filter.DesiredChange{}, filter.ErrRuleStale
}
current := matches[0]
if err := filter.GuardMutation(current); err != nil {
return filter.DesiredChange{}, err
}
before := ObservedRule(current)
if before.UUID == "" {
before.UUID = desired.Rule.UUID
}
return filter.DesiredChange{Operation: filter.ChangeDelete, Before: &before, Locator: &current.Locator, UnmarkedAdopted: current.Marker == "" && desired.Origin == filter.RuleOriginAdopted}, nil
}
func ObservedRule(observed filter.ObservedRule) filter.FirewallRule {
rule := observed.Rule
if rule.UUID == "" && strings.HasPrefix(observed.Marker, "1panel-rule:") {
rule.UUID = strings.TrimSpace(strings.TrimPrefix(observed.Marker, "1panel-rule:"))
}
return rule
}
func locatorBucket(locator filter.Locator) string {
if locator.Position != nil {
return locator.ScopeKey + "\x00position:" + strconv.Itoa(*locator.Position)
}
return locator.ScopeKey + "\x00canonical:" + locator.Canonical
}