Merge pull request #4581 from RolandMa1986/fix-istio
fix: the configuration of the Istio virtualservice is overwritten
This commit is contained in:
@@ -316,61 +316,12 @@ func (v *VirtualServiceController) syncService(key string) error {
|
||||
}
|
||||
vs := currentVirtualService.DeepCopy()
|
||||
|
||||
// create a whole new virtualservice
|
||||
|
||||
// TODO(jeff): use FQDN to replace service name
|
||||
vs.Spec.Hosts = []string{name}
|
||||
|
||||
vs.Spec.Http = []*apinetworkingv1alpha3.HTTPRoute{}
|
||||
vs.Spec.Tcp = []*apinetworkingv1alpha3.TCPRoute{}
|
||||
|
||||
// check if service has TCP protocol ports
|
||||
for _, port := range service.Spec.Ports {
|
||||
var route apinetworkingv1alpha3.HTTPRouteDestination
|
||||
var match apinetworkingv1alpha3.HTTPMatchRequest
|
||||
if port.Protocol == v1.ProtocolTCP {
|
||||
route = apinetworkingv1alpha3.HTTPRouteDestination{
|
||||
Destination: &apinetworkingv1alpha3.Destination{
|
||||
Host: name,
|
||||
Subset: subsets[0].Name,
|
||||
Port: &apinetworkingv1alpha3.PortSelector{
|
||||
Number: uint32(port.Port),
|
||||
},
|
||||
},
|
||||
Weight: 100,
|
||||
}
|
||||
|
||||
match = apinetworkingv1alpha3.HTTPMatchRequest{Port: uint32(port.Port)}
|
||||
|
||||
// a http port, add to HTTPRoute
|
||||
|
||||
if servicemesh.SupportHttpProtocol(port.Name) {
|
||||
httpRoute := apinetworkingv1alpha3.HTTPRoute{
|
||||
Route: []*apinetworkingv1alpha3.HTTPRouteDestination{&route},
|
||||
Match: []*apinetworkingv1alpha3.HTTPMatchRequest{&match},
|
||||
}
|
||||
vs.Spec.Http = append(vs.Spec.Http, &httpRoute)
|
||||
} else {
|
||||
// everything else treated as TCPRoute
|
||||
tcpRoute := apinetworkingv1alpha3.TCPRoute{
|
||||
Route: []*apinetworkingv1alpha3.RouteDestination{
|
||||
{
|
||||
Destination: route.Destination,
|
||||
Weight: route.Weight,
|
||||
},
|
||||
},
|
||||
Match: []*apinetworkingv1alpha3.L4MatchAttributes{{Port: match.Port}},
|
||||
}
|
||||
vs.Spec.Tcp = append(vs.Spec.Tcp, &tcpRoute)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(strategies) > 0 {
|
||||
// apply strategy spec to virtualservice
|
||||
|
||||
switch strategies[0].Spec.StrategyPolicy {
|
||||
case servicemeshv1alpha2.PolicyPause:
|
||||
vs.Spec = v.generateDefaultVirtualServiceSpec(name, subsets, service).Spec
|
||||
break
|
||||
case servicemeshv1alpha2.PolicyWaitForWorkloadReady:
|
||||
set := v.getSubsets(strategies[0])
|
||||
@@ -388,6 +339,7 @@ func (v *VirtualServiceController) syncService(key string) error {
|
||||
}
|
||||
// strategy has subset that are not ready
|
||||
if nonExist {
|
||||
vs.Spec = v.generateDefaultVirtualServiceSpec(name, subsets, service).Spec
|
||||
break
|
||||
} else {
|
||||
vs.Spec = v.generateVirtualServiceSpec(strategies[0], service).Spec
|
||||
@@ -397,8 +349,12 @@ func (v *VirtualServiceController) syncService(key string) error {
|
||||
default:
|
||||
vs.Spec = v.generateVirtualServiceSpec(strategies[0], service).Spec
|
||||
}
|
||||
} else {
|
||||
vs.Spec = v.generateDefaultVirtualServiceSpec(name, subsets, service).Spec
|
||||
}
|
||||
|
||||
v.patchHTTPRoute(currentVirtualService.Spec.Http, vs.Spec.Http)
|
||||
|
||||
createVirtualService := len(currentVirtualService.ResourceVersion) == 0
|
||||
|
||||
if !createVirtualService &&
|
||||
@@ -632,3 +588,72 @@ func (v *VirtualServiceController) generateVirtualServiceSpec(strategy *servicem
|
||||
servicemesh.FillDestinationPort(vs, service)
|
||||
return vs
|
||||
}
|
||||
|
||||
// create a whole new virtualservice
|
||||
func (v *VirtualServiceController) generateDefaultVirtualServiceSpec(name string, subsets []*apinetworkingv1alpha3.Subset, service *v1.Service) *clientgonetworkingv1alpha3.VirtualService {
|
||||
vs := &clientgonetworkingv1alpha3.VirtualService{}
|
||||
// TODO(jeff): use FQDN to replace service name
|
||||
vs.Spec.Hosts = []string{name}
|
||||
// check if service has TCP protocol ports
|
||||
for _, port := range service.Spec.Ports {
|
||||
var route apinetworkingv1alpha3.HTTPRouteDestination
|
||||
var match apinetworkingv1alpha3.HTTPMatchRequest
|
||||
if port.Protocol == v1.ProtocolTCP {
|
||||
route = apinetworkingv1alpha3.HTTPRouteDestination{
|
||||
Destination: &apinetworkingv1alpha3.Destination{
|
||||
Host: name,
|
||||
Subset: subsets[0].Name,
|
||||
Port: &apinetworkingv1alpha3.PortSelector{
|
||||
Number: uint32(port.Port),
|
||||
},
|
||||
},
|
||||
Weight: 100,
|
||||
}
|
||||
|
||||
match = apinetworkingv1alpha3.HTTPMatchRequest{Port: uint32(port.Port)}
|
||||
|
||||
// a http port, add to HTTPRoute
|
||||
|
||||
if servicemesh.SupportHttpProtocol(port.Name) {
|
||||
httpRoute := apinetworkingv1alpha3.HTTPRoute{
|
||||
Name: port.Name,
|
||||
Route: []*apinetworkingv1alpha3.HTTPRouteDestination{&route},
|
||||
Match: []*apinetworkingv1alpha3.HTTPMatchRequest{&match},
|
||||
}
|
||||
vs.Spec.Http = append(vs.Spec.Http, &httpRoute)
|
||||
} else {
|
||||
// everything else treated as TCPRoute
|
||||
tcpRoute := apinetworkingv1alpha3.TCPRoute{
|
||||
Route: []*apinetworkingv1alpha3.RouteDestination{
|
||||
{
|
||||
Destination: route.Destination,
|
||||
Weight: route.Weight,
|
||||
},
|
||||
},
|
||||
Match: []*apinetworkingv1alpha3.L4MatchAttributes{{Port: match.Port}},
|
||||
}
|
||||
vs.Spec.Tcp = append(vs.Spec.Tcp, &tcpRoute)
|
||||
}
|
||||
}
|
||||
}
|
||||
return vs
|
||||
}
|
||||
|
||||
// patchHTTPRoute copy all properties from origin to the target HTTPRoute except Match and Route
|
||||
func (v *VirtualServiceController) patchHTTPRoute(origin, target []*apinetworkingv1alpha3.HTTPRoute) []*apinetworkingv1alpha3.HTTPRoute {
|
||||
originMap := map[string]*apinetworkingv1alpha3.HTTPRoute{}
|
||||
for _, o := range origin {
|
||||
originMap[o.Name] = o
|
||||
}
|
||||
|
||||
for _, t := range target {
|
||||
if o, ok := originMap[t.Name]; ok {
|
||||
match := t.Match
|
||||
route := t.Route
|
||||
*t = *o
|
||||
t.Match = match
|
||||
t.Route = route
|
||||
}
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
@@ -19,8 +19,10 @@ package virtualservice
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
apinetworkingv1alpha3 "istio.io/api/networking/v1alpha3"
|
||||
apiv1alpha3 "istio.io/api/networking/v1alpha3"
|
||||
"istio.io/client-go/pkg/apis/networking/v1alpha3"
|
||||
istiofake "istio.io/client-go/pkg/clientset/versioned/fake"
|
||||
@@ -34,7 +36,6 @@ import (
|
||||
kubefake "k8s.io/client-go/kubernetes/fake"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/record"
|
||||
|
||||
"kubesphere.io/api/servicemesh/v1alpha2"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake"
|
||||
@@ -329,6 +330,7 @@ func TestInitialStrategyCreate(t *testing.T) {
|
||||
for _, port := range svc.Spec.Ports {
|
||||
if servicemesh.SupportHttpProtocol(port.Name) {
|
||||
httpRoute := apiv1alpha3.HTTPRoute{
|
||||
Name: port.Name,
|
||||
Route: []*apiv1alpha3.HTTPRouteDestination{
|
||||
{
|
||||
Destination: &apiv1alpha3.Destination{
|
||||
@@ -578,3 +580,126 @@ func TestStrategies(t *testing.T) {
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestVirtualServiceController_patchHTTPRoute(t *testing.T) {
|
||||
|
||||
target := []*apiv1alpha3.HTTPRoute{
|
||||
{
|
||||
Name: "http-1",
|
||||
Match: []*apiv1alpha3.HTTPMatchRequest{
|
||||
{
|
||||
Port: uint32(80),
|
||||
},
|
||||
},
|
||||
Route: []*apiv1alpha3.HTTPRouteDestination{
|
||||
{
|
||||
Destination: &apiv1alpha3.Destination{
|
||||
Host: "service1",
|
||||
Subset: "v1",
|
||||
Port: &apinetworkingv1alpha3.PortSelector{
|
||||
Number: uint32(80),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type args struct {
|
||||
origin []*apiv1alpha3.HTTPRoute
|
||||
target []*apiv1alpha3.HTTPRoute
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
args args
|
||||
want []*apiv1alpha3.HTTPRoute
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
args: args{
|
||||
origin: []*apiv1alpha3.HTTPRoute{},
|
||||
target: target,
|
||||
},
|
||||
want: []*apiv1alpha3.HTTPRoute{
|
||||
{
|
||||
Name: "http-1",
|
||||
Match: []*apiv1alpha3.HTTPMatchRequest{
|
||||
{
|
||||
Port: uint32(80),
|
||||
},
|
||||
},
|
||||
Route: []*apiv1alpha3.HTTPRouteDestination{
|
||||
{
|
||||
Destination: &apiv1alpha3.Destination{
|
||||
Host: "service1",
|
||||
Subset: "v1",
|
||||
Port: &apinetworkingv1alpha3.PortSelector{
|
||||
Number: uint32(80),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "override",
|
||||
args: args{
|
||||
origin: []*apiv1alpha3.HTTPRoute{
|
||||
{
|
||||
Name: "http-1",
|
||||
Match: []*apiv1alpha3.HTTPMatchRequest{
|
||||
{
|
||||
Port: uint32(80),
|
||||
},
|
||||
{
|
||||
Port: uint32(81),
|
||||
},
|
||||
},
|
||||
Fault: &apiv1alpha3.HTTPFaultInjection{
|
||||
Delay: &apiv1alpha3.HTTPFaultInjection_Delay{
|
||||
Percent: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
target: target,
|
||||
},
|
||||
want: []*apiv1alpha3.HTTPRoute{
|
||||
{
|
||||
Name: "http-1",
|
||||
Match: []*apiv1alpha3.HTTPMatchRequest{
|
||||
{
|
||||
Port: uint32(80),
|
||||
},
|
||||
},
|
||||
Route: []*apiv1alpha3.HTTPRouteDestination{
|
||||
{
|
||||
Destination: &apiv1alpha3.Destination{
|
||||
Host: "service1",
|
||||
Subset: "v1",
|
||||
Port: &apinetworkingv1alpha3.PortSelector{
|
||||
Number: uint32(80),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Fault: &apiv1alpha3.HTTPFaultInjection{
|
||||
Delay: &apiv1alpha3.HTTPFaultInjection_Delay{
|
||||
Percent: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
v := &VirtualServiceController{}
|
||||
if got := v.patchHTTPRoute(tt.args.origin, tt.args.target); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("VirtualServiceController.patchHTTPRoute() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user