From 520ae57329f0f8185cfc3eddbb33a8d027ca8b08 Mon Sep 17 00:00:00 2001 From: Kuromesi Date: Tue, 12 Sep 2023 16:53:45 +0800 Subject: [PATCH] make some logic changes Signed-off-by: Kuromesi --- pkg/trafficrouting/network/custom/custom.go | 126 ++++++++-- .../network/custom/custom_test.go | 236 ++++++++++++++---- .../LuaError/trafficRouting.lua | 3 + .../DestinationRule/trafficRouting.lua | 8 + .../VirtualService/trafficRouting.lua | 9 - 5 files changed, 312 insertions(+), 70 deletions(-) create mode 100644 pkg/trafficrouting/network/custom/lua_configuration/networking.error.io/LuaError/trafficRouting.lua create mode 100644 pkg/trafficrouting/network/custom/lua_configuration/networking.istio.io/DestinationRule/trafficRouting.lua diff --git a/pkg/trafficrouting/network/custom/custom.go b/pkg/trafficrouting/network/custom/custom.go index 04182dc1..dfeb90b0 100644 --- a/pkg/trafficrouting/network/custom/custom.go +++ b/pkg/trafficrouting/network/custom/custom.go @@ -85,7 +85,10 @@ func NewCustomController(client client.Client, conf Config) (network.NetworkProv return r, nil } +// when initializing, first check lua and get all custom providers, then store custom providers +// once fails to store a custom provider, roll back custom providers previously (assume error should not occur) func (r *customController) Initialize(ctx context.Context) error { + customNetworkRefList := make([]*unstructured.Unstructured, 0) for _, ref := range r.conf.TrafficConf { obj := &unstructured.Unstructured{} obj.SetAPIVersion(ref.APIVersion) @@ -100,16 +103,52 @@ func (r *customController) Initialize(ctx context.Context) error { klog.Errorf("failed to get lua script for custom network provider %s(%s/%s): %s", ref.Kind, r.conf.RolloutNs, ref.Name, err.Error()) return err } - if err := r.storeObject(obj); err != nil { + customNetworkRefList = append(customNetworkRefList, obj) + } + for i := 0; i < len(customNetworkRefList); i++ { + nObj := customNetworkRefList[i].DeepCopy() + err := r.storeObject(nObj) + if err != nil { + klog.Errorf("failed to store custom network provider %s(%s/%s): %s", customNetworkRefList[i].GetKind(), r.conf.RolloutNs, customNetworkRefList[i].GetName(), err.Error()) + klog.Errorf("roll back custom network providers previously") + r.rollBack(customNetworkRefList, i) return err } + customNetworkRefList[i] = nObj } return nil } +// when ensuring routes, first execute lua for all custom providers, then update +// once fails to update a custom provider, roll back custom providers previously (assume error should not occur) func (r *customController) EnsureRoutes(ctx context.Context, strategy *rolloutv1alpha1.TrafficRoutingStrategy) (bool, error) { + done := true + // *strategy.Weight == 0 indicates traffic routing is doing finalising and tries to route whole traffic to stable service + // then restore custom network provider directly + if strategy.Weight != nil && *strategy.Weight == 0 { + for _, ref := range r.conf.TrafficConf { + obj := &unstructured.Unstructured{} + obj.SetAPIVersion(ref.APIVersion) + obj.SetKind(ref.Kind) + if err := r.Get(ctx, types.NamespacedName{Namespace: r.conf.RolloutNs, Name: ref.Name}, obj); err != nil { + klog.Errorf("failed to get %s(%s/%s) when routing whole traffic to stable service", ref.Kind, r.conf.RolloutNs, ref.Name) + return false, err + } + changed, err := r.restoreObject(obj, true) + if err != nil { + klog.Errorf("failed to restore %s(%s/%s) when routing whole traffic to stable service", ref.Kind, r.conf.RolloutNs, ref.Name) + return false, err + } + if changed { + done = false + } + } + return done, nil + } var err error - var done = true + nSpecList := make([]Data, 0) + customNetworkRefList := make([]*unstructured.Unstructured, 0) + // first execute lua for new spec for _, ref := range r.conf.TrafficConf { obj := &unstructured.Unstructured{} obj.SetAPIVersion(ref.APIVersion) @@ -133,21 +172,32 @@ func (r *customController) EnsureRoutes(ctx context.Context, strategy *rolloutv1 klog.Errorf("failed to execute lua for %s(%s/%s): %s", ref.Kind, r.conf.RolloutNs, ref.Name, err.Error()) return false, err } - nObj := obj.DeepCopy() + nSpecList = append(nSpecList, nSpec) + customNetworkRefList = append(customNetworkRefList, obj) + } + // update CustomNetworkRefs then + for i := 0; i < len(nSpecList); i++ { + nObj := customNetworkRefList[i].DeepCopy() + nSpec := nSpecList[i] if compareAndSetObject(nSpec, nObj) { continue } if err = r.Update(context.TODO(), nObj); err != nil { - klog.Errorf("failed to update custom network provider %s(%s/%s) from (%s) to (%s)", ref.Kind, r.conf.RolloutNs, ref.Name, util.DumpJSON(obj), util.DumpJSON(nObj)) + klog.Errorf("failed to update custom network provider %s(%s/%s) from (%s) to (%s)", nObj.GetKind(), r.conf.RolloutNs, nObj.GetName(), util.DumpJSON(customNetworkRefList[i]), util.DumpJSON(nObj)) + // if fails to update, restore the previous CustomNetworkRefs + klog.Errorf("roll back custom network providers previously") + r.rollBack(customNetworkRefList, i) return false, err } - klog.Infof("update custom network provider %s(%s/%s) from (%s) to (%s) success", ref.Kind, r.conf.RolloutNs, ref.Name, util.DumpJSON(obj), util.DumpJSON(nObj)) + klog.Infof("update custom network provider %s(%s/%s) from (%s) to (%s) success", nObj.GetKind(), r.conf.RolloutNs, nObj.GetName(), util.DumpJSON(customNetworkRefList[i]), util.DumpJSON(nObj)) + customNetworkRefList[i] = nObj done = false } return done, nil } func (r *customController) Finalise(ctx context.Context) error { + done := true for _, ref := range r.conf.TrafficConf { obj := &unstructured.Unstructured{} obj.SetAPIVersion(ref.APIVersion) @@ -157,11 +207,29 @@ func (r *customController) Finalise(ctx context.Context) error { klog.Infof("custom network provider %s(%s/%s) not found when finalising", ref.Kind, r.conf.RolloutNs, ref.Name) continue } - return err + klog.Errorf("failed to get %s(%s/%s) when finalising, proccess next first", ref.Kind, r.conf.RolloutNs, ref.Name) + done = false + continue } - if err := r.restoreObject(obj); err != nil { - return err + if _, err := r.restoreObject(obj, false); err != nil { + done = false + klog.Errorf("failed to restore %s(%s/%s) when finalising: %s", ref.Kind, r.conf.RolloutNs, ref.Name, err.Error()) + } + } + if !done { + return fmt.Errorf("finalising work is not done") + } + return nil +} + +// roll back custom network provider previous to failedIdx +func (r *customController) rollBack(customNetworkRefList []*unstructured.Unstructured, failedIdx int) error { + for j := 0; j < failedIdx; j++ { + if _, err := r.restoreObject(customNetworkRefList[j].DeepCopy(), true); err != nil { + klog.Errorf("failed to roll back custom network provider %s(%s/%s): %s", customNetworkRefList[j].GetKind(), r.conf.RolloutNs, customNetworkRefList[j].GetName(), err.Error()) + continue } + klog.Infof("roll back custom network provider %s(%s/%s) success", customNetworkRefList[j].GetKind(), r.conf.RolloutNs, customNetworkRefList[j].GetName()) } return nil } @@ -173,18 +241,18 @@ func (r *customController) storeObject(obj *unstructured.Unstructured) error { annotations = make(map[string]string) } labels := obj.GetLabels() - oSpec := annotations[OriginalSpecAnnotation] + oSpecStr := annotations[OriginalSpecAnnotation] delete(annotations, OriginalSpecAnnotation) data := Data{ Spec: obj.Object["spec"], Labels: labels, Annotations: annotations, } - cSpec := util.DumpJSON(data) - if oSpec == cSpec { + cSpecStr := util.DumpJSON(data) + if oSpecStr == cSpecStr { return nil } - annotations[OriginalSpecAnnotation] = cSpec + annotations[OriginalSpecAnnotation] = cSpecStr obj.SetAnnotations(annotations) if err := r.Update(context.TODO(), obj); err != nil { klog.Errorf("failed to store custom network provider %s(%s/%s): %s", obj.GetKind(), r.conf.RolloutNs, obj.GetName(), err.Error()) @@ -194,24 +262,44 @@ func (r *customController) storeObject(obj *unstructured.Unstructured) error { return nil } -// restore an object from spec stored in OriginalSpecAnnotation -func (r *customController) restoreObject(obj *unstructured.Unstructured) error { +// restore an object from spec stored in OriginalSpecAnnotation, needStoreOriginalSpec indicates whether the original spec should be stored +// if needStoreOriginalSpec is false, indicates traffic routing is doing finalising +// if needStoreOriginalSpec is true, indicates traffic routing failed when ensuring routes and is rolling back or in finalising +func (r *customController) restoreObject(obj *unstructured.Unstructured, needStoreOriginalSpec bool) (bool, error) { + changed := false annotations := obj.GetAnnotations() if annotations == nil || annotations[OriginalSpecAnnotation] == "" { - return nil + klog.Infof("OriginalSpecAnnotation not found in custom network provider %s(%s/%s)") + return changed, nil } - specStr := annotations[OriginalSpecAnnotation] + oSpecStr := annotations[OriginalSpecAnnotation] var oSpec Data - _ = json.Unmarshal([]byte(specStr), &oSpec) + _ = json.Unmarshal([]byte(oSpecStr), &oSpec) + if needStoreOriginalSpec { + // when the traffic routing is rolling back, first check whether current spec equals to original spec, if equals, then just return + // this is not a concern when traffic routing is doing finalising, since the OriginalSpecAnnotation should be removed and network provider always need to be updated + delete(annotations, OriginalSpecAnnotation) + data := Data{ + Spec: obj.Object["spec"], + Labels: obj.GetLabels(), + Annotations: annotations, + } + cSpecStr := util.DumpJSON(data) + if oSpecStr == cSpecStr { + return changed, nil + } + oSpec.Annotations[OriginalSpecAnnotation] = oSpecStr + } obj.Object["spec"] = oSpec.Spec obj.SetAnnotations(oSpec.Annotations) obj.SetLabels(oSpec.Labels) if err := r.Update(context.TODO(), obj); err != nil { klog.Errorf("failed to restore object %s(%s/%s) from annotation(%s): %s", obj.GetKind(), r.conf.RolloutNs, obj.GetName(), OriginalSpecAnnotation, err.Error()) - return err + return changed, err } + changed = true klog.Infof("restore custom network provider %s(%s/%s) from annotation(%s) success", obj.GetKind(), obj.GetNamespace(), obj.GetName(), OriginalSpecAnnotation) - return nil + return changed, nil } func (r *customController) executeLuaForCanary(spec Data, strategy *rolloutv1alpha1.TrafficRoutingStrategy, luaScript string) (Data, error) { diff --git a/pkg/trafficrouting/network/custom/custom_test.go b/pkg/trafficrouting/network/custom/custom_test.go index f4f812b9..a6f3b608 100644 --- a/pkg/trafficrouting/network/custom/custom_test.go +++ b/pkg/trafficrouting/network/custom/custom_test.go @@ -39,8 +39,8 @@ import ( ) var ( - scheme *runtime.Scheme - networkDemo = ` + scheme *runtime.Scheme + virtualServiceDemo = ` { "apiVersion": "networking.istio.io/v1alpha3", "kind": "VirtualService", @@ -68,6 +68,44 @@ var ( } } ` + destinationRuleDemo = ` + { + "apiVersion": "networking.istio.io/v1alpha3", + "kind": "DestinationRule", + "metadata": { + "name": "dr-demo" + }, + "spec": { + "host": "mockb", + "subsets": [ + { + "labels": { + "version": "base" + }, + "name": "version-base" + } + ], + "trafficPolicy": { + "loadBalancer": { + "simple": "ROUND_ROBIN" + } + } + } + } + ` + // lua script for this resource contains error and cannot be executed + luaErrorDemo = ` + { + "apiVersion": "networking.error.io/v1alpha3", + "kind": "LuaError", + "metadata": { + "name": "error-demo" + }, + "spec": { + "error": true + } + } + ` ) func init() { @@ -88,7 +126,7 @@ func TestInitialize(t *testing.T) { name: "test1, find lua script locally", getUnstructured: func() *unstructured.Unstructured { u := &unstructured.Unstructured{} - _ = u.UnmarshalJSON([]byte(networkDemo)) + _ = u.UnmarshalJSON([]byte(virtualServiceDemo)) return u }, getConfig: func() Config { @@ -117,7 +155,7 @@ func TestInitialize(t *testing.T) { }, expectUnstructured: func() *unstructured.Unstructured { u := &unstructured.Unstructured{} - _ = u.UnmarshalJSON([]byte(networkDemo)) + _ = u.UnmarshalJSON([]byte(virtualServiceDemo)) annotations := map[string]string{ OriginalSpecAnnotation: `{"spec":{"hosts":["echoserver.example.com"],"http":[{"route":[{"destination":{"host":"echoserver"}}]}]},"annotations":{"virtual":"test"}}`, "virtual": "test", @@ -130,7 +168,7 @@ func TestInitialize(t *testing.T) { name: "test2, find lua script in ConfigMap", getUnstructured: func() *unstructured.Unstructured { u := &unstructured.Unstructured{} - _ = u.UnmarshalJSON([]byte(networkDemo)) + _ = u.UnmarshalJSON([]byte(virtualServiceDemo)) u.SetAPIVersion("networking.istio.io/v1alpha3") return u }, @@ -160,7 +198,7 @@ func TestInitialize(t *testing.T) { }, expectUnstructured: func() *unstructured.Unstructured { u := &unstructured.Unstructured{} - _ = u.UnmarshalJSON([]byte(networkDemo)) + _ = u.UnmarshalJSON([]byte(virtualServiceDemo)) u.SetAPIVersion("networking.istio.io/v1alpha3") annotations := map[string]string{ OriginalSpecAnnotation: `{"spec":{"hosts":["echoserver.example.com"],"http":[{"route":[{"destination":{"host":"echoserver"}}]}]},"annotations":{"virtual":"test"}}`, @@ -211,28 +249,57 @@ func checkEqual(cli client.Client, t *testing.T, expect *unstructured.Unstructur func TestEnsureRoutes(t *testing.T) { cases := []struct { - name string - getLua func() map[string]string - getRoutes func() *rolloutsv1alpha1.TrafficRoutingStrategy - getUnstructured func() *unstructured.Unstructured - expectInfo func() (bool, *unstructured.Unstructured) + name string + getLua func() map[string]string + getRoutes func() *rolloutsv1alpha1.TrafficRoutingStrategy + getUnstructureds func() []*unstructured.Unstructured + getConfig func() Config + expectState func() (bool, bool) + expectUnstructureds func() []*unstructured.Unstructured }{ { - name: "test1", + name: "test1, do traffic routing for VirtualService and DestinationRule", getRoutes: func() *rolloutsv1alpha1.TrafficRoutingStrategy { return &rolloutsv1alpha1.TrafficRoutingStrategy{ Weight: utilpointer.Int32(5), } }, - getUnstructured: func() *unstructured.Unstructured { + getUnstructureds: func() []*unstructured.Unstructured { + objects := make([]*unstructured.Unstructured, 0) u := &unstructured.Unstructured{} - _ = u.UnmarshalJSON([]byte(networkDemo)) + _ = u.UnmarshalJSON([]byte(virtualServiceDemo)) u.SetAPIVersion("networking.istio.io/v1alpha3") - return u + objects = append(objects, u) + + u = &unstructured.Unstructured{} + _ = u.UnmarshalJSON([]byte(destinationRuleDemo)) + u.SetAPIVersion("networking.istio.io/v1alpha3") + objects = append(objects, u) + return objects }, - expectInfo: func() (bool, *unstructured.Unstructured) { + getConfig: func() Config { + return Config{ + Key: "rollout-demo", + StableService: "echoserver", + CanaryService: "echoserver-canary", + TrafficConf: []rolloutsv1alpha1.CustomNetworkRef{ + { + APIVersion: "networking.istio.io/v1alpha3", + Kind: "VirtualService", + Name: "echoserver", + }, + { + APIVersion: "networking.istio.io/v1alpha3", + Kind: "DestinationRule", + Name: "dr-demo", + }, + }, + } + }, + expectUnstructureds: func() []*unstructured.Unstructured { + objects := make([]*unstructured.Unstructured, 0) u := &unstructured.Unstructured{} - _ = u.UnmarshalJSON([]byte(networkDemo)) + _ = u.UnmarshalJSON([]byte(virtualServiceDemo)) annotations := map[string]string{ OriginalSpecAnnotation: `{"spec":{"hosts":["echoserver.example.com"],"http":[{"route":[{"destination":{"host":"echoserver"}}]}]},"annotations":{"virtual":"test"}}`, "virtual": "test", @@ -242,41 +309,126 @@ func TestEnsureRoutes(t *testing.T) { var spec interface{} _ = json.Unmarshal([]byte(specStr), &spec) u.Object["spec"] = spec - return false, u + objects = append(objects, u) + + u = &unstructured.Unstructured{} + _ = u.UnmarshalJSON([]byte(destinationRuleDemo)) + annotations = map[string]string{ + OriginalSpecAnnotation: `{"spec":{"host":"mockb","subsets":[{"labels":{"version":"base"},"name":"version-base"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}}`, + } + u.SetAnnotations(annotations) + specStr = `{"host":"mockb","subsets":[{"labels":{"version":"base"},"name":"version-base"},{"labels":{"istio.service.tag":"gray"},"name":"canary"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}` + _ = json.Unmarshal([]byte(specStr), &spec) + u.Object["spec"] = spec + objects = append(objects, u) + return objects + }, + expectState: func() (bool, bool) { + done := false + hasError := false + return done, hasError }, }, - } - config := Config{ - Key: "rollout-demo", - StableService: "echoserver", - CanaryService: "echoserver-canary", - TrafficConf: []rolloutsv1alpha1.CustomNetworkRef{ - { - APIVersion: "networking.istio.io/v1alpha3", - Kind: "VirtualService", - Name: "echoserver", + { + name: "test2, do traffic routing but failed to execute lua", + getRoutes: func() *rolloutsv1alpha1.TrafficRoutingStrategy { + return &rolloutsv1alpha1.TrafficRoutingStrategy{ + Weight: utilpointer.Int32(5), + } + }, + getUnstructureds: func() []*unstructured.Unstructured { + objects := make([]*unstructured.Unstructured, 0) + u := &unstructured.Unstructured{} + _ = u.UnmarshalJSON([]byte(virtualServiceDemo)) + u.SetAPIVersion("networking.istio.io/v1alpha3") + objects = append(objects, u) + + u = &unstructured.Unstructured{} + _ = u.UnmarshalJSON([]byte(luaErrorDemo)) + u.SetAPIVersion("networking.error.io/v1alpha3") + objects = append(objects, u) + return objects + }, + getConfig: func() Config { + return Config{ + Key: "rollout-demo", + StableService: "echoserver", + CanaryService: "echoserver-canary", + TrafficConf: []rolloutsv1alpha1.CustomNetworkRef{ + { + APIVersion: "networking.istio.io/v1alpha3", + Kind: "VirtualService", + Name: "echoserver", + }, + { + APIVersion: "networking.error.io/v1alpha3", + Kind: "LuaError", + Name: "error-demo", + }, + }, + } + }, + expectUnstructureds: func() []*unstructured.Unstructured { + objects := make([]*unstructured.Unstructured, 0) + u := &unstructured.Unstructured{} + _ = u.UnmarshalJSON([]byte(virtualServiceDemo)) + annotations := map[string]string{ + OriginalSpecAnnotation: `{"spec":{"hosts":["echoserver.example.com"],"http":[{"route":[{"destination":{"host":"echoserver"}}]}]},"annotations":{"virtual":"test"}}`, + "virtual": "test", + } + u.SetAnnotations(annotations) + specStr := `{"hosts":["echoserver.example.com"],"http":[{"route":[{"destination":{"host":"echoserver"}}]}]}` + var spec interface{} + _ = json.Unmarshal([]byte(specStr), &spec) + u.Object["spec"] = spec + objects = append(objects, u) + + u = &unstructured.Unstructured{} + _ = u.UnmarshalJSON([]byte(luaErrorDemo)) + annotations = map[string]string{ + OriginalSpecAnnotation: `{"spec":{"error":true}}`, + } + u.SetAnnotations(annotations) + specStr = `{"error":true}` + _ = json.Unmarshal([]byte(specStr), &spec) + u.Object["spec"] = spec + objects = append(objects, u) + return objects + }, + expectState: func() (bool, bool) { + done := false + hasError := true + return done, hasError }, }, } for _, cs := range cases { t.Run(cs.name, func(t *testing.T) { fakeCli := fake.NewClientBuilder().WithScheme(scheme).Build() - err := fakeCli.Create(context.TODO(), cs.getUnstructured()) - if err != nil { - klog.Errorf(err.Error()) - return + for _, obj := range cs.getUnstructureds() { + err := fakeCli.Create(context.TODO(), obj) + if err != nil { + t.Fatalf("failed to create objects: %s", err.Error()) + } } - c, _ := NewCustomController(fakeCli, config) + c, _ := NewCustomController(fakeCli, cs.getConfig()) strategy := cs.getRoutes() - expect1, expect2 := cs.expectInfo() - c.Initialize(context.TODO()) - done, err := c.EnsureRoutes(context.TODO(), strategy) + expectDone, expectHasError := cs.expectState() + err := c.Initialize(context.TODO()) if err != nil { + t.Fatalf("failed to initialize custom controller") + } + done, err := c.EnsureRoutes(context.TODO(), strategy) + if !expectHasError && err != nil { t.Fatalf("EnsureRoutes failed: %s", err.Error()) - } else if done != expect1 { - t.Fatalf("expect(%v), but get(%v)", expect1, done) + } else if expectHasError && err == nil { + t.Fatalf("expect error occured but not") + } else if done != expectDone { + t.Fatalf("expect(%v), but get(%v)", expectDone, done) + } + for _, expectUnstructured := range cs.expectUnstructureds() { + checkEqual(fakeCli, t, expectUnstructured) } - checkEqual(fakeCli, t, expect2) }) } } @@ -289,10 +441,10 @@ func TestFinalise(t *testing.T) { expectUnstructured func() *unstructured.Unstructured }{ { - name: "test1", + name: "test1, finalise VirtualService", getUnstructured: func() *unstructured.Unstructured { u := &unstructured.Unstructured{} - _ = u.UnmarshalJSON([]byte(networkDemo)) + _ = u.UnmarshalJSON([]byte(virtualServiceDemo)) annotations := map[string]string{ OriginalSpecAnnotation: `{"spec":{"hosts":["echoserver.example.com"],"http":[{"route":[{"destination":{"host":"echoserver"}}]}]},"annotations":{"virtual":"test"}}`, "virtual": "test", @@ -319,7 +471,7 @@ func TestFinalise(t *testing.T) { }, expectUnstructured: func() *unstructured.Unstructured { u := &unstructured.Unstructured{} - _ = u.UnmarshalJSON([]byte(networkDemo)) + _ = u.UnmarshalJSON([]byte(virtualServiceDemo)) return u }, }, diff --git a/pkg/trafficrouting/network/custom/lua_configuration/networking.error.io/LuaError/trafficRouting.lua b/pkg/trafficrouting/network/custom/lua_configuration/networking.error.io/LuaError/trafficRouting.lua new file mode 100644 index 00000000..59282070 --- /dev/null +++ b/pkg/trafficrouting/network/custom/lua_configuration/networking.error.io/LuaError/trafficRouting.lua @@ -0,0 +1,3 @@ +-- the lua script contains error +local spec = obj.error +return sepc.error \ No newline at end of file diff --git a/pkg/trafficrouting/network/custom/lua_configuration/networking.istio.io/DestinationRule/trafficRouting.lua b/pkg/trafficrouting/network/custom/lua_configuration/networking.istio.io/DestinationRule/trafficRouting.lua new file mode 100644 index 00000000..3df3aace --- /dev/null +++ b/pkg/trafficrouting/network/custom/lua_configuration/networking.istio.io/DestinationRule/trafficRouting.lua @@ -0,0 +1,8 @@ +local spec = obj.data.spec +local canary = {} +canary.labels = {} +canary.name = "canary" +local podLabelKey = "istio.service.tag" +canary.labels[podLabelKey] = "gray" +table.insert(spec.subsets, canary) +return obj.data \ No newline at end of file diff --git a/pkg/trafficrouting/network/custom/lua_configuration/networking.istio.io/VirtualService/trafficRouting.lua b/pkg/trafficrouting/network/custom/lua_configuration/networking.istio.io/VirtualService/trafficRouting.lua index 37ff292c..d4d52c23 100644 --- a/pkg/trafficrouting/network/custom/lua_configuration/networking.istio.io/VirtualService/trafficRouting.lua +++ b/pkg/trafficrouting/network/custom/lua_configuration/networking.istio.io/VirtualService/trafficRouting.lua @@ -1,12 +1,3 @@ --- obj = { canaryWeight = 20, stableWeight = 80, --- matches = { --- { headers = { { name = "user-agent", value = "pc", type = "Exact", }, --- { type = "RegularExpression", name = "name", value = ".*demo", }, }, }, }, --- canaryService = "nginx-service-canary", stableService = "nginx-service", --- data = { --- spec = { hosts = { "*", }, http = { { route = { { destination = { host = "nginx-service", subset = "v1"}, }, { destination = { host = "nginx-service", subset = "v2"}, } }, }, }, --- gateways = { "nginx-gateway", }, }, }, } - spec = obj.data.spec if obj.canaryWeight == -1 then