From 1df3226e8cd0bbb6506965f6adeffccb8cc88923 Mon Sep 17 00:00:00 2001 From: Kuromesi Date: Tue, 26 Sep 2023 09:39:37 +0800 Subject: [PATCH] add lua scripts for istio Signed-off-by: Kuromesi --- .../traffic_routing_with_a_match.yaml | 49 ++++++ .../DestinationRule/trafficRouting.lua | 8 + .../testdata/rollout_with_three_steps.yaml | 122 +++++++++++++ .../traffic_routing_with_a_match.yaml | 61 +++++++ .../traffic_routing_with_matches.yaml | 68 ++++++++ .../testdata/traffic_routing_with_weight.yaml | 50 ++++++ .../VirtualService/trafficRouting.lua | 164 ++++++++++++++++++ 7 files changed, 522 insertions(+) create mode 100644 lua_configuration/networking.istio.io/DestinationRule/testdata/traffic_routing_with_a_match.yaml create mode 100644 lua_configuration/networking.istio.io/DestinationRule/trafficRouting.lua create mode 100644 lua_configuration/networking.istio.io/VirtualService/testdata/rollout_with_three_steps.yaml create mode 100644 lua_configuration/networking.istio.io/VirtualService/testdata/traffic_routing_with_a_match.yaml create mode 100644 lua_configuration/networking.istio.io/VirtualService/testdata/traffic_routing_with_matches.yaml create mode 100644 lua_configuration/networking.istio.io/VirtualService/testdata/traffic_routing_with_weight.yaml create mode 100644 lua_configuration/networking.istio.io/VirtualService/trafficRouting.lua diff --git a/lua_configuration/networking.istio.io/DestinationRule/testdata/traffic_routing_with_a_match.yaml b/lua_configuration/networking.istio.io/DestinationRule/testdata/traffic_routing_with_a_match.yaml new file mode 100644 index 00000000..3d5e3be4 --- /dev/null +++ b/lua_configuration/networking.istio.io/DestinationRule/testdata/traffic_routing_with_a_match.yaml @@ -0,0 +1,49 @@ +trafficRouting: + apiVersion: rollouts.kruise.io/v1alpha1 + kind: TrafficRouting + metadata: + name: tr-demo + spec: + strategy: + matches: + - headers: + - type: Exact + name: version + value: canary + objectRef: + - service: svc-demo + customNetworkRefs: + - apiVersion: networking.istio.io/v1beta1 + kind: DestinationRule + name: ds-demo +original: + apiVersion: networking.istio.io/v1beta1 + kind: DestinationRule + metadata: + name: ds-demo + spec: + host: svc-demo + trafficPolicy: + loadBalancer: + simple: ROUND_ROBIN + subsets: + - labels: + version: base + name: version-base +expected: + - apiVersion: networking.istio.io/v1beta1 + kind: DestinationRule + metadata: + name: ds-demo + spec: + host: svc-demo + trafficPolicy: + loadBalancer: + simple: ROUND_ROBIN + subsets: + - labels: + version: base + name: version-base + - labels: + istio.service.tag: gray + name: canary \ No newline at end of file diff --git a/lua_configuration/networking.istio.io/DestinationRule/trafficRouting.lua b/lua_configuration/networking.istio.io/DestinationRule/trafficRouting.lua new file mode 100644 index 00000000..3df3aace --- /dev/null +++ b/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/lua_configuration/networking.istio.io/VirtualService/testdata/rollout_with_three_steps.yaml b/lua_configuration/networking.istio.io/VirtualService/testdata/rollout_with_three_steps.yaml new file mode 100644 index 00000000..0a9eb98b --- /dev/null +++ b/lua_configuration/networking.istio.io/VirtualService/testdata/rollout_with_three_steps.yaml @@ -0,0 +1,122 @@ +rollout: + apiVersion: rollouts.kruise.io/v1alpha1 + kind: Rollout + metadata: + name: rollouts-demo + annotations: + rollouts.kruise.io/rolling-style: canary + spec: + disabled: false + objectRef: + workloadRef: + apiVersion: apps/v1 + kind: Deployment + name: deploy-demo + strategy: + canary: + steps: + - matches: + - headers: + - type: Exact + name: user-agent + value: pc + - type: RegularExpression + name: name + value: ".*demo" + - matches: + - headers: + - type: Exact + name: user-agent + value: pc + - headers: + - type: RegularExpression + name: name + value: ".*demo" + - weight: 50 + trafficRoutings: + - service: svc-demo + customNetworkRefs: + - apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + name: vs-demo +original: + apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + metadata: + name: vs-demo + spec: + hosts: + - "*" + gateways: + - nginx-gateway + http: + - route: + - destination: + host: svc-demo +expected: + - apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + metadata: + name: vs-demo + spec: + hosts: + - "*" + gateways: + - nginx-gateway + http: + - match: + - headers: + user-agent: + exact: pc + name: + regex: .*demo + route: + - destination: + host: svc-demo-canary + - route: + - destination: + host: svc-demo + - apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + metadata: + name: vs-demo + spec: + hosts: + - "*" + gateways: + - nginx-gateway + http: + - match: + - headers: + name: + regex: .*demo + route: + - destination: + host: svc-demo-canary + - match: + - headers: + user-agent: + exact: pc + route: + - destination: + host: svc-demo-canary + - route: + - destination: + host: svc-demo + - apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + metadata: + name: vs-demo + spec: + hosts: + - "*" + gateways: + - nginx-gateway + http: + - route: + - destination: + host: svc-demo + weight: 50 + - destination: + host: svc-demo-canary + weight: 50 diff --git a/lua_configuration/networking.istio.io/VirtualService/testdata/traffic_routing_with_a_match.yaml b/lua_configuration/networking.istio.io/VirtualService/testdata/traffic_routing_with_a_match.yaml new file mode 100644 index 00000000..cd5b99cd --- /dev/null +++ b/lua_configuration/networking.istio.io/VirtualService/testdata/traffic_routing_with_a_match.yaml @@ -0,0 +1,61 @@ +trafficRouting: + apiVersion: rollouts.kruise.io/v1alpha1 + kind: TrafficRouting + metadata: + name: tr-demo + spec: + strategy: + matches: + - headers: + - type: Exact + name: user-agent + value: pc + - type: RegularExpression + name: name + value: ".*demo" + objectRef: + - service: svc-demo + customNetworkRefs: + - apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + name: vs-demo +original: + apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + metadata: + name: vs-demo + spec: + hosts: + - "*" + gateways: + - nginx-gateway + http: + - route: + - destination: + host: svc-demo + subset: base +expected: + - apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + metadata: + name: vs-demo + spec: + hosts: + - "*" + gateways: + - nginx-gateway + http: + - match: + - headers: + user-agent: + exact: pc + name: + regex: .*demo + route: + - destination: + host: svc-demo + subset: canary + - route: + - destination: + host: svc-demo + subset: base diff --git a/lua_configuration/networking.istio.io/VirtualService/testdata/traffic_routing_with_matches.yaml b/lua_configuration/networking.istio.io/VirtualService/testdata/traffic_routing_with_matches.yaml new file mode 100644 index 00000000..26c7d7db --- /dev/null +++ b/lua_configuration/networking.istio.io/VirtualService/testdata/traffic_routing_with_matches.yaml @@ -0,0 +1,68 @@ +trafficRouting: + apiVersion: rollouts.kruise.io/v1alpha1 + kind: TrafficRouting + metadata: + name: tr-demo + spec: + strategy: + matches: + - headers: + - type: Exact + name: user-agent + value: pc + - headers: + - type: RegularExpression + name: name + value: ".*demo" + objectRef: + - service: svc-demo + customNetworkRefs: + - apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + name: vs-demo +original: + apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + metadata: + name: vs-demo + spec: + hosts: + - "*" + gateways: + - nginx-gateway + http: + - route: + - destination: + host: svc-demo + subset: base +expected: + - apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + metadata: + name: vs-demo + spec: + hosts: + - "*" + gateways: + - nginx-gateway + http: + - match: + - headers: + name: + regex: .*demo + route: + - destination: + host: svc-demo + subset: canary + - match: + - headers: + user-agent: + exact: pc + route: + - destination: + host: svc-demo + subset: canary + - route: + - destination: + host: svc-demo + subset: base \ No newline at end of file diff --git a/lua_configuration/networking.istio.io/VirtualService/testdata/traffic_routing_with_weight.yaml b/lua_configuration/networking.istio.io/VirtualService/testdata/traffic_routing_with_weight.yaml new file mode 100644 index 00000000..9ab4bbb8 --- /dev/null +++ b/lua_configuration/networking.istio.io/VirtualService/testdata/traffic_routing_with_weight.yaml @@ -0,0 +1,50 @@ +trafficRouting: + apiVersion: rollouts.kruise.io/v1alpha1 + kind: TrafficRouting + metadata: + name: tr-demo + spec: + strategy: + weight: 50 + objectRef: + - service: svc-demo + customNetworkRefs: + - apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + name: vs-demo +original: + apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + metadata: + name: vs-demo + spec: + hosts: + - "*" + gateways: + - nginx-gateway + http: + - route: + - destination: + host: svc-demo + subset: base +expected: + - apiVersion: networking.istio.io/v1alpha3 + kind: VirtualService + metadata: + name: nginx-vs + namespace: demo + spec: + hosts: + - "*" + gateways: + - nginx-gateway + http: + - route: + - destination: + host: svc-demo + subset: base + weight: 50 + - destination: + host: svc-demo + subset: canary + weight: 50 diff --git a/lua_configuration/networking.istio.io/VirtualService/trafficRouting.lua b/lua_configuration/networking.istio.io/VirtualService/trafficRouting.lua new file mode 100644 index 00000000..7645056f --- /dev/null +++ b/lua_configuration/networking.istio.io/VirtualService/trafficRouting.lua @@ -0,0 +1,164 @@ +spec = obj.data.spec + +if obj.canaryWeight == -1 then + obj.canaryWeight = 100 + obj.stableWeight = 0 +end + +function FindAllRules(spec, protocol) + local rules = {} + if (spec[protocol] ~= nil) then + for _, proto in ipairs(spec[protocol]) do + table.insert(rules, proto) + end + end + return rules +end + +-- find matched route of VirtualService spec with stable svc +function FindMatchedRules(spec, stableService, protocol) + local matchedRoutes = {} + local rules = FindAllRules(spec, protocol) + -- a rule contains 'match' and 'route' + for _, rule in ipairs(rules) do + -- skip routes with matches + if (rule.match == nil) then + for _, route in ipairs(rule.route) do + if route.destination.host == stableService then + table.insert(matchedRoutes, rule) + break + end + end + end + end + return matchedRoutes +end + +function HasMatchedRule(spec, stableService, protocol) + local rules = FindAllRules(spec, protocol) + -- a rule contains 'match' and 'route' + for _, rule in ipairs(rules) do + for _, route in ipairs(rule.route) do + if route.destination.host == stableService then + return true + end + end + end + return false +end + +function DeepCopy(original) + local copy + if type(original) == 'table' then + copy = {} + for key, value in pairs(original) do + copy[key] = DeepCopy(value) + end + else + copy = original + end + return copy +end + +function CalculateWeight(route, stableWeight, n) + local weight + if (route.weight) then + weight = math.floor(route.weight * stableWeight / 100) + else + weight = math.floor(stableWeight / n) + end + return weight +end + +-- generate routes with matches, insert a rule before other rules +function GenerateMatchedRoutes(spec, matches, stableService, canaryService, stableWeight, canaryWeight, protocol) + for _, match in ipairs(matches) do + local route = {} + route["match"] = {} + if (not HasMatchedRule(spec, stableService, protocol)) then + return + end + for key, value in pairs(match) do + local vsMatch = {} + vsMatch[key] = {} + for _, rule in ipairs(value) do + if rule["type"] == "RegularExpression" then + matchType = "regex" + elseif rule["type"] == "Exact" then + matchType = "exact" + elseif rule["type"] == "Prefix" then + matchType = "prefix" + end + if key == "headers" then + vsMatch[key][rule["name"]] = {} + vsMatch[key][rule["name"]][matchType] = rule.value + else + vsMatch[key][matchType] = rule.value + end + end + table.insert(route["match"], vsMatch) + end + route.route = { + { + destination = {} + } + } + -- if stableService == canaryService, then do e2e release + if stableService == canaryService then + route.route[1].destination.host = stableService + route.route[1].destination.subset = "canary" + else + route.route[1].destination.host = canaryService + end + if (protocol == "http") then + table.insert(spec.http, 1, route) + elseif (protocol == "tls") then + table.insert(spec.tls, 1, route) + elseif (protocol == "tcp") then + table.insert(spec.tcp, 1, route) + end + end +end + +-- generate routes without matches, change every rule +function GenerateRoutes(spec, stableService, canaryService, stableWeight, canaryWeight, protocol) + local matchedRules = FindMatchedRules(spec, stableService, protocol) + for _, rule in ipairs(matchedRules) do + local canary + if stableService ~= canaryService then + canary = { + destination = { + host = canaryService, + }, + weight = canaryWeight, + } + else + canary = { + destination = { + host = stableService, + subset = "canary", + }, + weight = canaryWeight, + } + end + + -- incase there are multiple versions traffic already, do a for-loop + for _, route in ipairs(rule.route) do + -- update stable service weight + route.weight = CalculateWeight(route, stableWeight, #rule.route) + end + table.insert(rule.route, canary) + end +end + +if (obj.matches) +then + GenerateMatchedRoutes(spec, obj.matches, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "http") + GenerateMatchedRoutes(spec, obj.matches, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "tcp") + GenerateMatchedRoutes(spec, obj.matches, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "tls") +else + GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "http") + GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "tcp") + GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "tls") +end +return obj.data