Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: istio dropping fields during removing of managed routes #2692

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions rollout/trafficrouting/istio/istio.go
Original file line number Diff line number Diff line change
Expand Up @@ -1391,8 +1391,8 @@ func (r *Reconciler) orderRoutes(istioVirtualService *unstructured.Unstructured)
// splitManagedRoutesAndNonManagedRoutes This splits the routes from an istio virtual service into two slices
// one slice contains all the routes that are also in the rollouts managedRoutes object and one that contains routes
// that where only in the virtual service (aka routes that where manually added by user)
func splitManagedRoutesAndNonManagedRoutes(managedRoutes []v1alpha1.MangedRoutes, httpRouteI []interface{}) (httpRoutesWithinManagedRoutes []VirtualServiceHTTPRoute, httpRoutesNotWithinManagedRoutes []VirtualServiceHTTPRoute, err error) {
var httpRoutes []VirtualServiceHTTPRoute
func splitManagedRoutesAndNonManagedRoutes(managedRoutes []v1alpha1.MangedRoutes, httpRouteI []interface{}) (httpRoutesWithinManagedRoutes []map[string]interface{}, httpRoutesNotWithinManagedRoutes []map[string]interface{}, err error) {
var httpRoutes []map[string]interface{}

jsonHttpRoutes, err := json.Marshal(httpRouteI)
if err != nil {
Expand All @@ -1406,7 +1406,10 @@ func splitManagedRoutesAndNonManagedRoutes(managedRoutes []v1alpha1.MangedRoutes
for _, route := range httpRoutes {
var found bool = false
for _, managedRoute := range managedRoutes {
if route.Name == managedRoute.Name {
// Not checking the cast success here is ok because it covers the case when the route has no name
// when there is no name the cast return an empty string and will just not match the managed route
name, _ := route["name"].(string)
if name == managedRoute.Name {
httpRoutesWithinManagedRoutes = append(httpRoutesWithinManagedRoutes, route)
found = true
break
Expand All @@ -1423,11 +1426,11 @@ func splitManagedRoutesAndNonManagedRoutes(managedRoutes []v1alpha1.MangedRoutes
// getOrderedVirtualServiceRoutes This returns an []interface{} of istio virtual routes where the routes are ordered based
// on the rollouts managedRoutes field. We take the routes from the rollouts managedRoutes field order them and place them on top
// of routes that are manually defined within the virtual service (aka. routes that users have defined manually)
func getOrderedVirtualServiceRoutes(httpRouteI []interface{}, managedRoutes []v1alpha1.MangedRoutes, httpRoutesWithinManagedRoutes []VirtualServiceHTTPRoute, httpRoutesNotWithinManagedRoutes []VirtualServiceHTTPRoute) ([]interface{}, error) {
var orderedManagedRoutes []VirtualServiceHTTPRoute
func getOrderedVirtualServiceRoutes(httpRouteI []interface{}, managedRoutes []v1alpha1.MangedRoutes, httpRoutesWithinManagedRoutes []map[string]interface{}, httpRoutesNotWithinManagedRoutes []map[string]interface{}) ([]interface{}, error) {
var orderedManagedRoutes []map[string]interface{}
for _, route := range managedRoutes {
for _, managedRoute := range httpRoutesWithinManagedRoutes {
if route.Name == managedRoute.Name {
if route.Name == managedRoute["name"] {
orderedManagedRoutes = append(orderedManagedRoutes, managedRoute)
}
}
Expand All @@ -1436,13 +1439,16 @@ func getOrderedVirtualServiceRoutes(httpRouteI []interface{}, managedRoutes []v1
orderedVirtualServiceHTTPRoutes := append(orderedManagedRoutes, httpRoutesNotWithinManagedRoutes...)

var orderedInterfaceVSVCHTTPRoutes []interface{}
for _, routeTyped := range orderedVirtualServiceHTTPRoutes {
for _, routeMap := range orderedVirtualServiceHTTPRoutes {
for _, route := range httpRouteI {
r := route.(map[string]interface{})

// No need to check if exist because the empty string returned on cast failure is good for this check
name, _ := r["name"].(string)
if name == routeTyped.Name {
// Not checking the cast success here is ok because it covers the case when the route has no name
name, rNameOK := r["name"].(string)
routeMapName, RMapNameOK := routeMap["name"].(string)
// The second or clause is for the case when we have a route that has no name set because this field
// is optional in istio virtual service if there is only one route
if name == routeMapName || (!rNameOK && !RMapNameOK) {
orderedInterfaceVSVCHTTPRoutes = append(orderedInterfaceVSVCHTTPRoutes, route)
}
}
Expand Down
21 changes: 21 additions & 0 deletions rollout/trafficrouting/istio/istio_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,27 @@ func TestHttpReconcileHeaderRouteWithExtra(t *testing.T) {
_, found = r2["corsPolicy"]
assert.True(t, found)

r.RemoveManagedRoutes()
iVirtualService, err = client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{})
assert.NoError(t, err)

routes, found, err = unstructured.NestedSlice(iVirtualService.Object, "spec", "http")
assert.NoError(t, err)
assert.True(t, found)

r0 = routes[0].(map[string]interface{})
route, found = r0["route"].([]interface{})
assert.True(t, found)

port1 = route[0].(map[string]interface{})["destination"].(map[string]interface{})["port"].(map[string]interface{})["number"]
assert.True(t, port1 == float64(8443))

r2 = routes[1].(map[string]interface{})
_, found = r2["retries"]
assert.True(t, found)
_, found = r2["corsPolicy"]
assert.True(t, found)

}

func TestReconcileUpdateHeader(t *testing.T) {
Expand Down