Skip to content

Commit

Permalink
fix after review: sort http paths
Browse files Browse the repository at this point in the history
Signed-off-by: Andrii Perenesenko <andrii.perenesenko@gmail.com>
  • Loading branch information
perenesenko committed Aug 31, 2022
1 parent f542ed2 commit 58e26b4
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 0 deletions.
1 change: 1 addition & 0 deletions rollout/trafficrouting/alb/alb.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ func (r *Reconciler) SetHeaderRoute(headerRoute *v1alpha1.SetHeaderRoute) error
if !hasRule && headerRoute.Match != nil {
desiredIngress.CreateAnnotationBasedPath(action)
}
desiredIngress.SortHttpPaths(rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes)
patch, modified, err := ingressutil.BuildIngressPatch(ingress.Mode(), ingress, desiredIngress, ingressutil.WithAnnotations(), ingressutil.WithSpec())
if err != nil {
return nil
Expand Down
35 changes: 35 additions & 0 deletions utils/ingress/wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ingress
import (
"context"
"errors"
"sort"
"sync"

corev1 "k8s.io/api/core/v1"
Expand All @@ -16,6 +17,8 @@ import (
networkingv1 "k8s.io/client-go/informers/networking/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"

"github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
)

// Ingress defines an Ingress resource abstraction used to allow Rollouts to
Expand Down Expand Up @@ -234,6 +237,38 @@ func (i *Ingress) RemovePathByServiceName(actionName string) {
}
}

func (i *Ingress) SortHttpPaths(routes []v1alpha1.MangedRoutes) {
var routeWeight = make(map[string]int) // map of route name for ordering
for j, route := range routes {
routeWeight[route.Name] = j
}

i.mux.Lock()
defer i.mux.Unlock()
switch i.mode {
case IngressModeNetworking:
for _, rule := range i.ingress.Spec.Rules {
sort.SliceStable(rule.HTTP.Paths, func(i, j int) bool {
return getKeyWeight(routeWeight, rule.HTTP.Paths[i].Backend.Service.Name) < getKeyWeight(routeWeight, rule.HTTP.Paths[j].Backend.Service.Name)
})
}
case IngressModeExtensions:
for _, rule := range i.legacyIngress.Spec.Rules {
sort.SliceStable(rule.HTTP.Paths, func(i, j int) bool {
return getKeyWeight(routeWeight, rule.HTTP.Paths[i].Backend.ServiceName) < getKeyWeight(routeWeight, rule.HTTP.Paths[j].Backend.ServiceName)
})
}
}
}

func getKeyWeight(weight map[string]int, key string) int {
if val, ok := weight[key]; ok {
return val
} else {
return len(weight)
}
}

func indexPathByService(rule v1.IngressRule, name string) int {
for i, path := range rule.HTTP.Paths {
if path.Backend.Service.Name == name {
Expand Down
99 changes: 99 additions & 0 deletions utils/ingress/wrapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
k8sfake "k8s.io/client-go/kubernetes/fake"
"k8s.io/utils/pointer"

"github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
"github.com/argoproj/argo-rollouts/utils/ingress"
)

Expand Down Expand Up @@ -396,6 +397,32 @@ func TestRemoveAnnotationBasedPath(t *testing.T) {
})
}

func TestSortHttpPaths(t *testing.T) {
managedRoutes := []v1alpha1.MangedRoutes{{Name: "route1"}, {Name: "route2"}, {Name: "route3"}}
t.Run("v1 ingress, sort path", func(t *testing.T) {
ing := networkingIngressWithPath("action1", "route3", "route1", "route2")
ing.SortHttpPaths(managedRoutes)
ni, _ := ing.GetNetworkingIngress()

assert.Equal(t, 4, len(ni.Spec.Rules[0].HTTP.Paths))
assert.Equal(t, "route1", ni.Spec.Rules[0].HTTP.Paths[0].Backend.Service.Name)
assert.Equal(t, "route2", ni.Spec.Rules[0].HTTP.Paths[1].Backend.Service.Name)
assert.Equal(t, "route3", ni.Spec.Rules[0].HTTP.Paths[2].Backend.Service.Name)
assert.Equal(t, "action1", ni.Spec.Rules[0].HTTP.Paths[3].Backend.Service.Name)
})
t.Run("v1beta1 ingress, sort path", func(t *testing.T) {
ing := extensionsIngressWithPath("action1", "route3", "route1", "route2")
ing.SortHttpPaths(managedRoutes)
ni, _ := ing.GetExtensionsIngress()

assert.Equal(t, 4, len(ni.Spec.Rules[0].HTTP.Paths))
assert.Equal(t, "route1", ni.Spec.Rules[0].HTTP.Paths[0].Backend.ServiceName)
assert.Equal(t, "route2", ni.Spec.Rules[0].HTTP.Paths[1].Backend.ServiceName)
assert.Equal(t, "route3", ni.Spec.Rules[0].HTTP.Paths[2].Backend.ServiceName)
assert.Equal(t, "action1", ni.Spec.Rules[0].HTTP.Paths[3].Backend.ServiceName)
})
}

func TestDeepCopy(t *testing.T) {
t.Run("will deepcopy ingress wrapped with networking.Ingress", func(t *testing.T) {
// given
Expand Down Expand Up @@ -976,6 +1003,43 @@ func networkingIngress() *ingress.Ingress {
return ingress.NewIngress(&res)
}

func networkingIngressWithPath(paths ...string) *ingress.Ingress {
var ingressPaths []v1.HTTPIngressPath
for _, path := range paths {
ingressPaths = append(ingressPaths, v1IngressPath(path))
}
res := v1.Ingress{
Spec: v1.IngressSpec{
IngressClassName: pointer.String("v1ingress"),
Rules: []v1.IngressRule{
{
Host: "v1host",
IngressRuleValue: v1.IngressRuleValue{
HTTP: &v1.HTTPIngressRuleValue{
Paths: ingressPaths,
},
},
},
},
},
}
return ingress.NewIngress(&res)
}

func v1IngressPath(serviceName string) v1.HTTPIngressPath {
pathType := v1.PathTypeImplementationSpecific
return v1.HTTPIngressPath{
Backend: v1.IngressBackend{
Service: &v1.IngressServiceBackend{
Name: serviceName,
Port: v1.ServiceBackendPort{Name: "use-annotation"},
},
},
Path: "/*",
PathType: &pathType,
}
}

func extensionsIngress() *ingress.Ingress {
pathType := v1beta1.PathTypeImplementationSpecific
res := v1beta1.Ingress{
Expand Down Expand Up @@ -1004,3 +1068,38 @@ func extensionsIngress() *ingress.Ingress {
}
return ingress.NewLegacyIngress(&res)
}

func extensionsIngressWithPath(paths ...string) *ingress.Ingress {
var ingressPaths []v1beta1.HTTPIngressPath
for _, path := range paths {
ingressPaths = append(ingressPaths, extensionIngressPath(path))
}
res := v1beta1.Ingress{
Spec: v1beta1.IngressSpec{
IngressClassName: pointer.String("v1beta1ingress"),
Rules: []v1beta1.IngressRule{
{
Host: "v1beta1host",
IngressRuleValue: v1beta1.IngressRuleValue{
HTTP: &v1beta1.HTTPIngressRuleValue{
Paths: ingressPaths,
},
},
},
},
},
}
return ingress.NewLegacyIngress(&res)
}

func extensionIngressPath(serviceName string) v1beta1.HTTPIngressPath {
pathType := v1beta1.PathTypeImplementationSpecific
return v1beta1.HTTPIngressPath{
Backend: v1beta1.IngressBackend{
ServiceName: serviceName,
ServicePort: intstr.FromString("use-annotation"),
},
Path: "/*",
PathType: &pathType,
}
}

0 comments on commit 58e26b4

Please sign in to comment.