pkg/brownfield/targets.go (71 lines of code) (raw):

// ------------------------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. // -------------------------------------------------------------------------------------------- package brownfield import ( "encoding/json" "strings" "k8s.io/klog/v2" ptv1 "github.com/Azure/application-gateway-kubernetes-ingress/pkg/apis/azureingressprohibitedtarget/v1" ) // TargetBlacklist is a list of Targets, which AGIC is not allowed to apply configuration for. type TargetBlacklist *[]Target // TargetPath is a string type alias. type TargetPath string // Target uniquely identifies a subset of App Gateway configuration, which AGIC will manage or be prohibited from managing. type Target struct { Hostname string `json:"Hostname,omitempty"` Path TargetPath `json:"Path,omitempty"` } // IsBlacklisted figures out whether a given Target objects in a list of blacklisted targets. func (t Target) IsBlacklisted(blacklist TargetBlacklist) bool { jsonTarget, _ := json.Marshal(t) for _, blTarget := range *blacklist { // An empty blacklist hostname indicates that any hostname would be blacklisted. // If host names match - this target is in the blacklist. // AGIC is allowed to create and modify App Gwy config for blank host. hostIsBlacklisted := blTarget.Hostname == "" || strings.EqualFold(t.Hostname, blTarget.Hostname) pathIsBlacklisted := blTarget.Path == "" || blTarget.Path == "/*" || t.Path.lower() == blTarget.Path.lower() || blTarget.Path.contains(t.Path) // TODO(draychev): || t.Path.contains(blTarget.Path) // With this version we keep things as simple as possible: match host and exact path to determine // whether given target is in the blacklist. Ideally this would be URL Path set overlap operation, // which we deliberately leave for a later time. if hostIsBlacklisted && pathIsBlacklisted { klog.V(3).Infof("[brownfield] Target %s is blacklisted", jsonTarget) return true // Found it } } klog.V(3).Infof("[brownfield] Target %s is not blacklisted", jsonTarget) return false // Did not find it } // GetTargetBlacklist returns the list of Targets given a list ProhibitedTarget CRDs. func GetTargetBlacklist(prohibitedTargets []*ptv1.AzureIngressProhibitedTarget) TargetBlacklist { // TODO(draychev): make this a method of ExistingResources and memoize it. var target []Target for _, prohibitedTarget := range prohibitedTargets { if len(prohibitedTarget.Spec.Paths) == 0 { target = append(target, Target{ Hostname: prohibitedTarget.Spec.Hostname, }) } for _, path := range prohibitedTarget.Spec.Paths { target = append(target, Target{ Hostname: prohibitedTarget.Spec.Hostname, Path: TargetPath(strings.ToLower(path)), }) } } return &target } func (p TargetPath) lower() string { return strings.ToLower(string(p)) } func (p TargetPath) contains(otherPath TargetPath) bool { if p == "" || p == "*" || p == "/*" { return true } // For strings that do not end with a * - do exact match if !strings.HasSuffix(p.lower(), "*") { return p.lower() == otherPath.lower() } // "/x/*" contains "/x" if strings.TrimRight(p.lower(), "/*") == strings.TrimRight(otherPath.lower(), "/*") { return true } if len(p) > len(otherPath) { return false } thisPathChunks := strings.Split(p.lower(), "/") otherPathChunks := strings.Split(otherPath.lower(), "/") for idx := range thisPathChunks { if thisPathChunks[idx] == "*" { return true } if thisPathChunks[idx] != otherPathChunks[idx] { return false } } return false }