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: ¤t.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 }