Files
elmprodvpn/selective-vpn-api/app/transport_snapshot_commit.go

163 lines
4.9 KiB
Go

package app
import "strings"
type transportInterfacesStateSnapshot struct {
ClientsUpdatedAt string
InterfacesUpdatedAt string
}
type transportInterfacesOnlySnapshot struct {
InterfacesUpdatedAt string
}
type transportPolicyPlanStateSnapshot struct {
PolicyRevision int64
PlanPolicyRevision int64
}
type transportOwnershipStateSnapshot struct {
PolicyRevision int64
OwnershipPolicyRevision int64
OwnershipUpdatedAt string
OwnershipPlanDigest string
}
func captureTransportInterfacesStateSnapshot(clients transportClientsState, ifaces transportInterfacesState) transportInterfacesStateSnapshot {
return transportInterfacesStateSnapshot{
ClientsUpdatedAt: clients.UpdatedAt,
InterfacesUpdatedAt: ifaces.UpdatedAt,
}
}
func captureTransportInterfacesOnlySnapshot(ifaces transportInterfacesState) transportInterfacesOnlySnapshot {
return transportInterfacesOnlySnapshot{InterfacesUpdatedAt: ifaces.UpdatedAt}
}
func captureTransportPolicyPlanStateSnapshot(policy TransportPolicyState, plan TransportPolicyCompilePlan) transportPolicyPlanStateSnapshot {
return transportPolicyPlanStateSnapshot{
PolicyRevision: policy.Revision,
PlanPolicyRevision: plan.PolicyRevision,
}
}
func captureTransportOwnershipStateSnapshot(policy TransportPolicyState, ownership TransportOwnershipState) transportOwnershipStateSnapshot {
return transportOwnershipStateSnapshot{
PolicyRevision: policy.Revision,
OwnershipPolicyRevision: ownership.PolicyRevision,
OwnershipUpdatedAt: ownership.UpdatedAt,
OwnershipPlanDigest: ownership.PlanDigest,
}
}
func compileTransportPolicyPlanForSnapshot(
policy TransportPolicyState,
clients []TransportClient,
plan TransportPolicyCompilePlan,
) (TransportPolicyCompilePlan, bool) {
if !transportPolicyPlanNeedsRecompile(policy, plan) {
return plan, false
}
compiled, _ := compileTransportPolicyPlan(policy.Intents, clients, policy.Revision)
return compiled, true
}
func transportPolicyPlanNeedsRecompile(policy TransportPolicyState, plan TransportPolicyCompilePlan) bool {
if plan.PolicyRevision != policy.Revision {
return true
}
for _, iface := range plan.Interfaces {
ifaceID := normalizeTransportIfaceID(iface.IfaceID)
for _, set := range iface.Sets {
ownerScope := strings.TrimSpace(set.OwnerScope)
if ownerScope == "" {
return true
}
expected := transportPolicyNftSetName(ownerScope, set.SelectorType)
if strings.TrimSpace(set.Name) != expected {
return true
}
}
for _, rule := range iface.Rules {
ownerScope := strings.TrimSpace(rule.OwnerScope)
expectedScope := transportPolicyNftOwnerScope(ifaceID, rule.ClientID)
if ownerScope == "" || ownerScope != expectedScope {
return true
}
expectedSet := transportPolicyNftSetName(ownerScope, rule.SelectorType)
if strings.TrimSpace(rule.NftSet) != expectedSet {
return true
}
}
}
return false
}
func saveTransportInterfacesIfSnapshotCurrent(snapshot transportInterfacesStateSnapshot, next transportInterfacesState) error {
transportMu.Lock()
defer transportMu.Unlock()
currentClients := loadTransportClientsState()
currentIfaces := loadTransportInterfacesState()
if snapshot.ClientsUpdatedAt != currentClients.UpdatedAt {
return nil
}
if snapshot.InterfacesUpdatedAt != currentIfaces.UpdatedAt {
return nil
}
return saveTransportInterfacesState(next)
}
func saveTransportInterfacesIfUnchanged(snapshot transportInterfacesOnlySnapshot, next transportInterfacesState) error {
transportMu.Lock()
defer transportMu.Unlock()
currentIfaces := loadTransportInterfacesState()
if snapshot.InterfacesUpdatedAt != currentIfaces.UpdatedAt {
return nil
}
return saveTransportInterfacesState(next)
}
func saveTransportPlanIfSnapshotCurrent(snapshot transportPolicyPlanStateSnapshot, next TransportPolicyCompilePlan) error {
transportMu.Lock()
defer transportMu.Unlock()
currentPolicy := loadTransportPolicyState()
if currentPolicy.Revision != snapshot.PolicyRevision {
return nil
}
currentPlan := loadTransportPolicyCompilePlan()
if currentPlan.PolicyRevision != snapshot.PlanPolicyRevision {
return nil
}
if next.PolicyRevision != currentPolicy.Revision {
return nil
}
return saveTransportPolicyCompilePlan(next)
}
func saveTransportOwnershipIfSnapshotCurrent(snapshot transportOwnershipStateSnapshot, next TransportOwnershipState) error {
transportMu.Lock()
defer transportMu.Unlock()
currentPolicy := loadTransportPolicyState()
if currentPolicy.Revision != snapshot.PolicyRevision {
return nil
}
currentOwnership := loadTransportOwnershipState()
if currentOwnership.PolicyRevision != snapshot.OwnershipPolicyRevision {
return nil
}
if currentOwnership.UpdatedAt != snapshot.OwnershipUpdatedAt {
return nil
}
if currentOwnership.PlanDigest != snapshot.OwnershipPlanDigest {
return nil
}
if next.PolicyRevision != currentPolicy.Revision {
return nil
}
return saveTransportOwnershipState(next)
}