generate istio destinationRule subset from pod-template-hash && add fields to allow user set canary/stable subset name
Signed-off-by: yunbo <yunbo10124scut@gmail.com>
This commit is contained in:
parent
07c1731e8a
commit
86c32e4941
|
|
@ -126,6 +126,7 @@ func (src *Rollout) ConvertTo(dst conversion.Hub) error {
|
||||||
func ConversionToV1beta1TrafficRoutingRef(src TrafficRoutingRef) (dst v1beta1.TrafficRoutingRef) {
|
func ConversionToV1beta1TrafficRoutingRef(src TrafficRoutingRef) (dst v1beta1.TrafficRoutingRef) {
|
||||||
dst.Service = src.Service
|
dst.Service = src.Service
|
||||||
dst.GracePeriodSeconds = src.GracePeriodSeconds
|
dst.GracePeriodSeconds = src.GracePeriodSeconds
|
||||||
|
dst.AdditionalParams = src.AdditionalParams
|
||||||
if src.Ingress != nil {
|
if src.Ingress != nil {
|
||||||
dst.Ingress = &v1beta1.IngressTrafficRouting{
|
dst.Ingress = &v1beta1.IngressTrafficRouting{
|
||||||
ClassType: src.Ingress.ClassType,
|
ClassType: src.Ingress.ClassType,
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ProgressingRolloutFinalizerPrefix = "progressing.rollouts.kruise.io"
|
ProgressingRolloutFinalizerPrefix = "progressing.rollouts.kruise.io"
|
||||||
|
IstioStableSubsetName = "istio.destinationRule.stableSubsetName"
|
||||||
|
IstioCanarySubsetName = "istio.destinationRule.canarySubsetName"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TrafficRoutingRef hosts all the different configuration for supported service meshes to enable more fine-grained traffic routing
|
// TrafficRoutingRef hosts all the different configuration for supported service meshes to enable more fine-grained traffic routing
|
||||||
|
|
@ -38,6 +40,10 @@ type TrafficRoutingRef struct {
|
||||||
Gateway *GatewayTrafficRouting `json:"gateway,omitempty"`
|
Gateway *GatewayTrafficRouting `json:"gateway,omitempty"`
|
||||||
// CustomNetworkRefs hold a list of custom providers to route traffic
|
// CustomNetworkRefs hold a list of custom providers to route traffic
|
||||||
CustomNetworkRefs []CustomNetworkRef `json:"customNetworkRefs,omitempty"`
|
CustomNetworkRefs []CustomNetworkRef `json:"customNetworkRefs,omitempty"`
|
||||||
|
// vaild keys:
|
||||||
|
// + IstioStableSubsetName
|
||||||
|
// + IstioCanarySubsetName
|
||||||
|
AdditionalParams map[string]string `json:"additionalParams,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IngressTrafficRouting configuration for ingress controller to control traffic routing
|
// IngressTrafficRouting configuration for ingress controller to control traffic routing
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,11 @@ limitations under the License.
|
||||||
|
|
||||||
package v1beta1
|
package v1beta1
|
||||||
|
|
||||||
|
const (
|
||||||
|
IstioStableSubsetName = "istio.destinationRule.stableSubsetName"
|
||||||
|
IstioCanarySubsetName = "istio.destinationRule.canarySubsetName"
|
||||||
|
)
|
||||||
|
|
||||||
// TrafficRoutingRef hosts all the different configuration for supported service meshes to enable more fine-grained traffic routing
|
// TrafficRoutingRef hosts all the different configuration for supported service meshes to enable more fine-grained traffic routing
|
||||||
type TrafficRoutingRef struct {
|
type TrafficRoutingRef struct {
|
||||||
// Service holds the name of a service which selects pods with stable version and don't select any pods with canary version.
|
// Service holds the name of a service which selects pods with stable version and don't select any pods with canary version.
|
||||||
|
|
@ -29,6 +34,10 @@ type TrafficRoutingRef struct {
|
||||||
Gateway *GatewayTrafficRouting `json:"gateway,omitempty"`
|
Gateway *GatewayTrafficRouting `json:"gateway,omitempty"`
|
||||||
// CustomNetworkRefs hold a list of custom providers to route traffic
|
// CustomNetworkRefs hold a list of custom providers to route traffic
|
||||||
CustomNetworkRefs []ObjectRef `json:"customNetworkRefs,omitempty"`
|
CustomNetworkRefs []ObjectRef `json:"customNetworkRefs,omitempty"`
|
||||||
|
// vaild keys:
|
||||||
|
// + IstioStableSubsetName
|
||||||
|
// + IstioCanarySubsetName
|
||||||
|
AdditionalParams map[string]string `json:"additionalParams,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IngressTrafficRouting configuration for ingress controller to control traffic routing
|
// IngressTrafficRouting configuration for ingress controller to control traffic routing
|
||||||
|
|
|
||||||
|
|
@ -344,6 +344,11 @@ spec:
|
||||||
for supported service meshes to enable more fine-grained
|
for supported service meshes to enable more fine-grained
|
||||||
traffic routing
|
traffic routing
|
||||||
properties:
|
properties:
|
||||||
|
additionalParams:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: 'vaild keys:'
|
||||||
|
type: object
|
||||||
customNetworkRefs:
|
customNetworkRefs:
|
||||||
description: CustomNetworkRefs hold a list of custom
|
description: CustomNetworkRefs hold a list of custom
|
||||||
providers to route traffic
|
providers to route traffic
|
||||||
|
|
@ -834,6 +839,11 @@ spec:
|
||||||
for supported service meshes to enable more fine-grained
|
for supported service meshes to enable more fine-grained
|
||||||
traffic routing
|
traffic routing
|
||||||
properties:
|
properties:
|
||||||
|
additionalParams:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: 'vaild keys:'
|
||||||
|
type: object
|
||||||
customNetworkRefs:
|
customNetworkRefs:
|
||||||
description: CustomNetworkRefs hold a list of custom
|
description: CustomNetworkRefs hold a list of custom
|
||||||
providers to route traffic
|
providers to route traffic
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,11 @@ spec:
|
||||||
for supported service meshes to enable more fine-grained traffic
|
for supported service meshes to enable more fine-grained traffic
|
||||||
routing
|
routing
|
||||||
properties:
|
properties:
|
||||||
|
additionalParams:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: 'vaild keys:'
|
||||||
|
type: object
|
||||||
customNetworkRefs:
|
customNetworkRefs:
|
||||||
description: CustomNetworkRefs hold a list of custom providers
|
description: CustomNetworkRefs hold a list of custom providers
|
||||||
to route traffic
|
to route traffic
|
||||||
|
|
|
||||||
|
|
@ -100,11 +100,14 @@ func objectToTable(path string) error {
|
||||||
Annotations: testCase.Original.GetAnnotations(),
|
Annotations: testCase.Original.GetAnnotations(),
|
||||||
Spec: testCase.Original.Object["spec"],
|
Spec: testCase.Original.Object["spec"],
|
||||||
},
|
},
|
||||||
Matches: step.TrafficRoutingStrategy.Matches,
|
Matches: step.TrafficRoutingStrategy.Matches,
|
||||||
CanaryWeight: *weight,
|
CanaryWeight: *weight,
|
||||||
StableWeight: 100 - *weight,
|
StableWeight: 100 - *weight,
|
||||||
CanaryService: canaryService,
|
CanaryService: canaryService,
|
||||||
StableService: stableService,
|
StableService: stableService,
|
||||||
|
StableRevision: "podtemplatehash-v1",
|
||||||
|
CanaryRevision: "podtemplatehash-v2",
|
||||||
|
RevisionLabelKey: "pod-template-hash",
|
||||||
}
|
}
|
||||||
uList[fmt.Sprintf("step_%d", i)] = data
|
uList[fmt.Sprintf("step_%d", i)] = data
|
||||||
}
|
}
|
||||||
|
|
@ -128,11 +131,14 @@ func objectToTable(path string) error {
|
||||||
Annotations: testCase.Original.GetAnnotations(),
|
Annotations: testCase.Original.GetAnnotations(),
|
||||||
Spec: testCase.Original.Object["spec"],
|
Spec: testCase.Original.Object["spec"],
|
||||||
},
|
},
|
||||||
Matches: matches,
|
Matches: matches,
|
||||||
CanaryWeight: *weight,
|
CanaryWeight: *weight,
|
||||||
StableWeight: 100 - *weight,
|
StableWeight: 100 - *weight,
|
||||||
CanaryService: canaryService,
|
CanaryService: canaryService,
|
||||||
StableService: stableService,
|
StableService: stableService,
|
||||||
|
StableRevision: "podtemplatehash-v1",
|
||||||
|
CanaryRevision: "podtemplatehash-v2",
|
||||||
|
RevisionLabelKey: "pod-template-hash",
|
||||||
}
|
}
|
||||||
uList["steps_0"] = data
|
uList["steps_0"] = data
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@ trafficRouting:
|
||||||
- apiVersion: networking.istio.io/v1beta1
|
- apiVersion: networking.istio.io/v1beta1
|
||||||
kind: DestinationRule
|
kind: DestinationRule
|
||||||
name: ds-demo
|
name: ds-demo
|
||||||
|
additionalParams:
|
||||||
|
istio.destinationRule.stableSubsetName: "version-base"
|
||||||
|
istio.destinationRule.canarySubsetName: "canary"
|
||||||
original:
|
original:
|
||||||
apiVersion: networking.istio.io/v1beta1
|
apiVersion: networking.istio.io/v1beta1
|
||||||
kind: DestinationRule
|
kind: DestinationRule
|
||||||
|
|
@ -27,9 +30,7 @@ original:
|
||||||
loadBalancer:
|
loadBalancer:
|
||||||
simple: ROUND_ROBIN
|
simple: ROUND_ROBIN
|
||||||
subsets:
|
subsets:
|
||||||
- labels:
|
- name: version-base
|
||||||
version: base
|
|
||||||
name: version-base
|
|
||||||
expected:
|
expected:
|
||||||
- apiVersion: networking.istio.io/v1beta1
|
- apiVersion: networking.istio.io/v1beta1
|
||||||
kind: DestinationRule
|
kind: DestinationRule
|
||||||
|
|
@ -42,8 +43,8 @@ expected:
|
||||||
simple: ROUND_ROBIN
|
simple: ROUND_ROBIN
|
||||||
subsets:
|
subsets:
|
||||||
- labels:
|
- labels:
|
||||||
version: base
|
pod-template-hash: "podtemplatehash-v1"
|
||||||
name: version-base
|
name: version-base
|
||||||
- labels:
|
- labels:
|
||||||
istio.service.tag: gray
|
pod-template-hash: "podtemplatehash-v2"
|
||||||
name: canary
|
name: canary
|
||||||
|
|
@ -1,8 +1,51 @@
|
||||||
local spec = obj.data.spec
|
local spec = obj.data.spec
|
||||||
|
local podLabelKey = obj.revisionLabelKey
|
||||||
|
|
||||||
|
if spec.subsets == nil then
|
||||||
|
spec.subsets = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- selector lables might come from pod-template-hash and patchPodTemplateMetadata
|
||||||
|
-- now we only support pod-template-hash
|
||||||
|
local stableLabels = {}
|
||||||
|
if obj.stableRevision ~= nil and obj.stableRevision ~= "" then
|
||||||
|
stableLabels[podLabelKey] = obj.stableRevision
|
||||||
|
end
|
||||||
|
local canaryLabels = {}
|
||||||
|
if obj.canaryRevision ~= nil and obj.canaryRevision ~= "" then
|
||||||
|
canaryLabels[podLabelKey] = obj.canaryRevision
|
||||||
|
end
|
||||||
|
local StableNameAlreadyExist = false
|
||||||
|
|
||||||
|
-- if stableName already exists, just appened the lables
|
||||||
|
for _, subset in ipairs(spec.subsets) do
|
||||||
|
if subset.name == obj.stableName then
|
||||||
|
StableNameAlreadyExist = true
|
||||||
|
if next(stableLabels) ~= nil then
|
||||||
|
subset.labels = subset.labels or {}
|
||||||
|
for key, value in pairs(stableLabels) do
|
||||||
|
subset.labels[key] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- if stableName doesn't exist, create it and its labels
|
||||||
|
if not StableNameAlreadyExist then
|
||||||
|
local stable = {}
|
||||||
|
stable.name = obj.stableName
|
||||||
|
if next(stableLabels) ~= nil then
|
||||||
|
stable.labels = stableLabels
|
||||||
|
end
|
||||||
|
table.insert(spec.subsets, stable)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Aussue the canaryName never exist, create it and its labels
|
||||||
local canary = {}
|
local canary = {}
|
||||||
canary.labels = {}
|
canary.name = obj.canaryName
|
||||||
canary.name = "canary"
|
if next(canaryLabels) ~= nil then
|
||||||
local podLabelKey = "istio.service.tag"
|
canary.labels = canaryLabels
|
||||||
canary.labels[podLabelKey] = "gray"
|
end
|
||||||
table.insert(spec.subsets, canary)
|
table.insert(spec.subsets, canary)
|
||||||
|
|
||||||
|
|
||||||
return obj.data
|
return obj.data
|
||||||
|
|
@ -19,6 +19,9 @@ trafficRouting:
|
||||||
- apiVersion: networking.istio.io/v1alpha3
|
- apiVersion: networking.istio.io/v1alpha3
|
||||||
kind: VirtualService
|
kind: VirtualService
|
||||||
name: vs-demo
|
name: vs-demo
|
||||||
|
additionalParams:
|
||||||
|
istio.destinationRule.stableSubsetName: "base"
|
||||||
|
istio.destinationRule.canarySubsetName: "canary"
|
||||||
original:
|
original:
|
||||||
apiVersion: networking.istio.io/v1alpha3
|
apiVersion: networking.istio.io/v1alpha3
|
||||||
kind: VirtualService
|
kind: VirtualService
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,9 @@ trafficRouting:
|
||||||
- apiVersion: networking.istio.io/v1alpha3
|
- apiVersion: networking.istio.io/v1alpha3
|
||||||
kind: VirtualService
|
kind: VirtualService
|
||||||
name: vs-demo
|
name: vs-demo
|
||||||
|
additionalParams:
|
||||||
|
istio.destinationRule.stableSubsetName: "base"
|
||||||
|
istio.destinationRule.canarySubsetName: "canary"
|
||||||
original:
|
original:
|
||||||
apiVersion: networking.istio.io/v1alpha3
|
apiVersion: networking.istio.io/v1alpha3
|
||||||
kind: VirtualService
|
kind: VirtualService
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@ trafficRouting:
|
||||||
- apiVersion: networking.istio.io/v1alpha3
|
- apiVersion: networking.istio.io/v1alpha3
|
||||||
kind: VirtualService
|
kind: VirtualService
|
||||||
name: vs-demo
|
name: vs-demo
|
||||||
|
additionalParams:
|
||||||
|
istio.destinationRule.stableSubsetName: "base"
|
||||||
|
istio.destinationRule.canarySubsetName: "canary"
|
||||||
original:
|
original:
|
||||||
apiVersion: networking.istio.io/v1alpha3
|
apiVersion: networking.istio.io/v1alpha3
|
||||||
kind: VirtualService
|
kind: VirtualService
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ function GenerateRoutesWithMatches(spec, matches, stableService, canaryService)
|
||||||
-- stableService == canaryService indicates DestinationRule exists and subset is set to be canary by default
|
-- stableService == canaryService indicates DestinationRule exists and subset is set to be canary by default
|
||||||
if stableService == canaryService then
|
if stableService == canaryService then
|
||||||
route.route[1].destination.host = stableService
|
route.route[1].destination.host = stableService
|
||||||
route.route[1].destination.subset = "canary"
|
route.route[1].destination.subset = obj.canaryName
|
||||||
else
|
else
|
||||||
route.route[1].destination.host = canaryService
|
route.route[1].destination.host = canaryService
|
||||||
end
|
end
|
||||||
|
|
@ -99,7 +99,7 @@ function GenerateRoutes(spec, stableService, canaryService, stableWeight, canary
|
||||||
canary = {
|
canary = {
|
||||||
destination = {
|
destination = {
|
||||||
host = stableService,
|
host = stableService,
|
||||||
subset = "canary",
|
subset = obj.canaryName,
|
||||||
},
|
},
|
||||||
weight = canaryWeight,
|
weight = canaryWeight,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -250,14 +250,14 @@ func (m *canaryReleaseManager) doCanaryFinalising(c *RolloutContext) (bool, erro
|
||||||
if err != nil || !done {
|
if err != nil || !done {
|
||||||
return done, err
|
return done, err
|
||||||
}
|
}
|
||||||
// 3. set workload.pause=false; set workload.partition=0
|
// 3. modify network api(ingress or gateway api) configuration, and route 100% traffic to stable pods.
|
||||||
done, err = m.finalizingBatchRelease(c)
|
done, err = m.trafficRoutingManager.FinalisingTrafficRouting(tr, false)
|
||||||
|
c.NewStatus.CanaryStatus.LastUpdateTime = tr.LastUpdateTime
|
||||||
if err != nil || !done {
|
if err != nil || !done {
|
||||||
return done, err
|
return done, err
|
||||||
}
|
}
|
||||||
// 4. modify network api(ingress or gateway api) configuration, and route 100% traffic to stable pods.
|
// 4. set workload.pause=false; set workload.partition=0
|
||||||
done, err = m.trafficRoutingManager.FinalisingTrafficRouting(tr, false)
|
done, err = m.finalizingBatchRelease(c)
|
||||||
c.NewStatus.CanaryStatus.LastUpdateTime = tr.LastUpdateTime
|
|
||||||
if err != nil || !done {
|
if err != nil || !done {
|
||||||
return done, err
|
return done, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -278,14 +278,16 @@ func newNetworkProvider(c client.Client, con *TrafficRoutingContext, sService, c
|
||||||
trafficRouting := con.ObjectRef[0]
|
trafficRouting := con.ObjectRef[0]
|
||||||
if trafficRouting.CustomNetworkRefs != nil {
|
if trafficRouting.CustomNetworkRefs != nil {
|
||||||
return custom.NewCustomController(c, custom.Config{
|
return custom.NewCustomController(c, custom.Config{
|
||||||
Key: con.Key,
|
Key: con.Key,
|
||||||
RolloutNs: con.Namespace,
|
RolloutNs: con.Namespace,
|
||||||
CanaryService: cService,
|
CanaryService: cService,
|
||||||
StableService: sService,
|
StableService: sService,
|
||||||
TrafficConf: trafficRouting.CustomNetworkRefs,
|
TrafficConf: trafficRouting.CustomNetworkRefs,
|
||||||
OwnerRef: con.OwnerRef,
|
OwnerRef: con.OwnerRef,
|
||||||
//only set for CustomController, never work for Ingress and Gateway
|
AdditionalParams: trafficRouting.AdditionalParams,
|
||||||
DisableGenerateCanaryService: con.DisableGenerateCanaryService,
|
RevisionLabelKey: con.RevisionLabelKey,
|
||||||
|
StableRevision: con.StableRevision,
|
||||||
|
CanaryRevision: con.CanaryRevision,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if trafficRouting.Ingress != nil {
|
if trafficRouting.Ingress != nil {
|
||||||
|
|
|
||||||
|
|
@ -319,12 +319,12 @@ var (
|
||||||
Data: map[string]string{
|
Data: map[string]string{
|
||||||
"lua.traffic.routing.VirtualService.networking.istio.io": `
|
"lua.traffic.routing.VirtualService.networking.istio.io": `
|
||||||
spec = obj.data.spec
|
spec = obj.data.spec
|
||||||
|
|
||||||
if obj.canaryWeight == -1 then
|
if obj.canaryWeight == -1 then
|
||||||
obj.canaryWeight = 100
|
obj.canaryWeight = 100
|
||||||
obj.stableWeight = 0
|
obj.stableWeight = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
function GetHost(destination)
|
function GetHost(destination)
|
||||||
local host = destination.destination.host
|
local host = destination.destination.host
|
||||||
dot_position = string.find(host, ".", 1, true)
|
dot_position = string.find(host, ".", 1, true)
|
||||||
|
|
@ -333,7 +333,7 @@ var (
|
||||||
end
|
end
|
||||||
return host
|
return host
|
||||||
end
|
end
|
||||||
|
|
||||||
-- find routes of VirtualService with stableService
|
-- find routes of VirtualService with stableService
|
||||||
function GetRulesToPatch(spec, stableService, protocol)
|
function GetRulesToPatch(spec, stableService, protocol)
|
||||||
local matchedRoutes = {}
|
local matchedRoutes = {}
|
||||||
|
|
@ -351,7 +351,7 @@ var (
|
||||||
end
|
end
|
||||||
return matchedRoutes
|
return matchedRoutes
|
||||||
end
|
end
|
||||||
|
|
||||||
function CalculateWeight(route, stableWeight, n)
|
function CalculateWeight(route, stableWeight, n)
|
||||||
local weight
|
local weight
|
||||||
if (route.weight) then
|
if (route.weight) then
|
||||||
|
|
@ -361,7 +361,7 @@ var (
|
||||||
end
|
end
|
||||||
return weight
|
return weight
|
||||||
end
|
end
|
||||||
|
|
||||||
-- generate routes with matches, insert a rule before other rules, only support http headers, cookies etc.
|
-- generate routes with matches, insert a rule before other rules, only support http headers, cookies etc.
|
||||||
function GenerateRoutesWithMatches(spec, matches, stableService, canaryService)
|
function GenerateRoutesWithMatches(spec, matches, stableService, canaryService)
|
||||||
for _, match in ipairs(matches) do
|
for _, match in ipairs(matches) do
|
||||||
|
|
@ -395,14 +395,14 @@ var (
|
||||||
-- stableService == canaryService indicates DestinationRule exists and subset is set to be canary by default
|
-- stableService == canaryService indicates DestinationRule exists and subset is set to be canary by default
|
||||||
if stableService == canaryService then
|
if stableService == canaryService then
|
||||||
route.route[1].destination.host = stableService
|
route.route[1].destination.host = stableService
|
||||||
route.route[1].destination.subset = "canary"
|
route.route[1].destination.subset = obj.canaryName
|
||||||
else
|
else
|
||||||
route.route[1].destination.host = canaryService
|
route.route[1].destination.host = canaryService
|
||||||
end
|
end
|
||||||
table.insert(spec.http, 1, route)
|
table.insert(spec.http, 1, route)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- generate routes without matches, change every rule whose host is stableService
|
-- generate routes without matches, change every rule whose host is stableService
|
||||||
function GenerateRoutes(spec, stableService, canaryService, stableWeight, canaryWeight, protocol)
|
function GenerateRoutes(spec, stableService, canaryService, stableWeight, canaryWeight, protocol)
|
||||||
local matchedRules = GetRulesToPatch(spec, stableService, protocol)
|
local matchedRules = GetRulesToPatch(spec, stableService, protocol)
|
||||||
|
|
@ -419,12 +419,12 @@ var (
|
||||||
canary = {
|
canary = {
|
||||||
destination = {
|
destination = {
|
||||||
host = stableService,
|
host = stableService,
|
||||||
subset = "canary",
|
subset = obj.canaryName,
|
||||||
},
|
},
|
||||||
weight = canaryWeight,
|
weight = canaryWeight,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- incase there are multiple versions traffic already, do a for-loop
|
-- incase there are multiple versions traffic already, do a for-loop
|
||||||
for _, route in ipairs(rule.route) do
|
for _, route in ipairs(rule.route) do
|
||||||
-- update stable service weight
|
-- update stable service weight
|
||||||
|
|
@ -433,7 +433,7 @@ var (
|
||||||
table.insert(rule.route, canary)
|
table.insert(rule.route, canary)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (obj.matches and next(obj.matches) ~= nil)
|
if (obj.matches and next(obj.matches) ~= nil)
|
||||||
then
|
then
|
||||||
GenerateRoutesWithMatches(spec, obj.matches, obj.stableService, obj.canaryService)
|
GenerateRoutesWithMatches(spec, obj.matches, obj.stableService, obj.canaryService)
|
||||||
|
|
@ -443,22 +443,66 @@ var (
|
||||||
GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "tls")
|
GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "tls")
|
||||||
end
|
end
|
||||||
return obj.data
|
return obj.data
|
||||||
|
|
||||||
|
|
||||||
`,
|
`,
|
||||||
"lua.traffic.routing.DestinationRule.networking.istio.io": `
|
"lua.traffic.routing.DestinationRule.networking.istio.io": `
|
||||||
local spec = obj.data.spec
|
local spec = obj.data.spec
|
||||||
|
local podLabelKey = obj.revisionLabelKey
|
||||||
|
|
||||||
|
if spec.subsets == nil then
|
||||||
|
spec.subsets = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- selector lables might come from pod-template-hash and patchPodTemplateMetadata
|
||||||
|
-- now we only support pod-template-hash
|
||||||
|
local stableLabels = {}
|
||||||
|
if obj.stableRevision ~= nil and obj.stableRevision ~= "" then
|
||||||
|
stableLabels[podLabelKey] = obj.stableRevision
|
||||||
|
end
|
||||||
|
local canaryLabels = {}
|
||||||
|
if obj.canaryRevision ~= nil and obj.canaryRevision ~= "" then
|
||||||
|
canaryLabels[podLabelKey] = obj.canaryRevision
|
||||||
|
end
|
||||||
|
local StableNameAlreadyExist = false
|
||||||
|
|
||||||
|
-- if stableName already exists, just appened the lables
|
||||||
|
for _, subset in ipairs(spec.subsets) do
|
||||||
|
if subset.name == obj.stableName then
|
||||||
|
StableNameAlreadyExist = true
|
||||||
|
if next(stableLabels) ~= nil then
|
||||||
|
subset.labels = subset.labels or {}
|
||||||
|
for key, value in pairs(stableLabels) do
|
||||||
|
subset.labels[key] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- if stableName doesn't exist, create it and its labels
|
||||||
|
if not StableNameAlreadyExist then
|
||||||
|
local stable = {}
|
||||||
|
stable.name = obj.stableName
|
||||||
|
if next(stableLabels) ~= nil then
|
||||||
|
stable.labels = stableLabels
|
||||||
|
end
|
||||||
|
table.insert(spec.subsets, stable)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Aussue the canaryName never exist, create it and its labels
|
||||||
local canary = {}
|
local canary = {}
|
||||||
canary.labels = {}
|
canary.name = obj.canaryName
|
||||||
canary.name = "canary"
|
if next(canaryLabels) ~= nil then
|
||||||
local podLabelKey = "istio.service.tag"
|
canary.labels = canaryLabels
|
||||||
canary.labels[podLabelKey] = "gray"
|
end
|
||||||
table.insert(spec.subsets, canary)
|
table.insert(spec.subsets, canary)
|
||||||
|
|
||||||
|
|
||||||
return obj.data
|
return obj.data
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
virtualServiceDemo = `
|
virtualServiceDemo1 = `
|
||||||
{
|
{
|
||||||
"apiVersion": "networking.istio.io/v1alpha3",
|
"apiVersion": "networking.istio.io/v1alpha3",
|
||||||
"kind": "VirtualService",
|
"kind": "VirtualService",
|
||||||
|
|
@ -486,7 +530,54 @@ var (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
destinationRuleDemo = `
|
destinationRuleDemo1 = `
|
||||||
|
{
|
||||||
|
"apiVersion": "networking.istio.io/v1alpha3",
|
||||||
|
"kind": "DestinationRule",
|
||||||
|
"metadata": {
|
||||||
|
"name": "dr-demo"
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"host": "echoserver",
|
||||||
|
"trafficPolicy": {
|
||||||
|
"loadBalancer": {
|
||||||
|
"simple": "ROUND_ROBIN"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
virtualServiceDemo2 = `
|
||||||
|
{
|
||||||
|
"apiVersion": "networking.istio.io/v1alpha3",
|
||||||
|
"kind": "VirtualService",
|
||||||
|
"metadata": {
|
||||||
|
"name": "echoserver",
|
||||||
|
"annotations": {
|
||||||
|
"virtual": "test"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"hosts": [
|
||||||
|
"echoserver.example.com"
|
||||||
|
],
|
||||||
|
"http": [
|
||||||
|
{
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"destination": {
|
||||||
|
"host": "echoserver",
|
||||||
|
"subset": "hello"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
destinationRuleDemo2 = `
|
||||||
{
|
{
|
||||||
"apiVersion": "networking.istio.io/v1alpha3",
|
"apiVersion": "networking.istio.io/v1alpha3",
|
||||||
"kind": "DestinationRule",
|
"kind": "DestinationRule",
|
||||||
|
|
@ -497,10 +588,7 @@ var (
|
||||||
"host": "echoserver",
|
"host": "echoserver",
|
||||||
"subsets": [
|
"subsets": [
|
||||||
{
|
{
|
||||||
"labels": {
|
"name":"hello"
|
||||||
"version": "base"
|
|
||||||
},
|
|
||||||
"name": "version-base"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"trafficPolicy": {
|
"trafficPolicy": {
|
||||||
|
|
@ -757,12 +845,12 @@ func TestDoTrafficRoutingWithIstio(t *testing.T) {
|
||||||
getUnstructureds: func() []*unstructured.Unstructured {
|
getUnstructureds: func() []*unstructured.Unstructured {
|
||||||
objects := make([]*unstructured.Unstructured, 0)
|
objects := make([]*unstructured.Unstructured, 0)
|
||||||
u := &unstructured.Unstructured{}
|
u := &unstructured.Unstructured{}
|
||||||
_ = u.UnmarshalJSON([]byte(virtualServiceDemo))
|
_ = u.UnmarshalJSON([]byte(virtualServiceDemo1))
|
||||||
u.SetAPIVersion("networking.istio.io/v1alpha3")
|
u.SetAPIVersion("networking.istio.io/v1alpha3")
|
||||||
objects = append(objects, u)
|
objects = append(objects, u)
|
||||||
|
|
||||||
u = &unstructured.Unstructured{}
|
u = &unstructured.Unstructured{}
|
||||||
_ = u.UnmarshalJSON([]byte(destinationRuleDemo))
|
_ = u.UnmarshalJSON([]byte(destinationRuleDemo1))
|
||||||
u.SetAPIVersion("networking.istio.io/v1alpha3")
|
u.SetAPIVersion("networking.istio.io/v1alpha3")
|
||||||
objects = append(objects, u)
|
objects = append(objects, u)
|
||||||
return objects
|
return objects
|
||||||
|
|
@ -770,12 +858,17 @@ func TestDoTrafficRoutingWithIstio(t *testing.T) {
|
||||||
getRollout: func() (*v1beta1.Rollout, *util.Workload) {
|
getRollout: func() (*v1beta1.Rollout, *util.Workload) {
|
||||||
obj := demoIstioRollout.DeepCopy()
|
obj := demoIstioRollout.DeepCopy()
|
||||||
obj.Status.CanaryStatus.LastUpdateTime = &metav1.Time{Time: time.Now().Add(-10 * time.Second)}
|
obj.Status.CanaryStatus.LastUpdateTime = &metav1.Time{Time: time.Now().Add(-10 * time.Second)}
|
||||||
|
obj.Spec.Strategy.Canary.TrafficRoutings[0].AdditionalParams = map[string]string{
|
||||||
|
// map is empty, thus the subset names will be default value: stable and canary
|
||||||
|
// v1beta1.IstioStableSubsetName: "version-base",
|
||||||
|
// v1beta1.IstioCanarySubsetName: "canary",
|
||||||
|
}
|
||||||
return obj, &util.Workload{RevisionLabelKey: apps.DefaultDeploymentUniqueLabelKey}
|
return obj, &util.Workload{RevisionLabelKey: apps.DefaultDeploymentUniqueLabelKey}
|
||||||
},
|
},
|
||||||
expectUnstructureds: func() []*unstructured.Unstructured {
|
expectUnstructureds: func() []*unstructured.Unstructured {
|
||||||
objects := make([]*unstructured.Unstructured, 0)
|
objects := make([]*unstructured.Unstructured, 0)
|
||||||
u := &unstructured.Unstructured{}
|
u := &unstructured.Unstructured{}
|
||||||
_ = u.UnmarshalJSON([]byte(virtualServiceDemo))
|
_ = u.UnmarshalJSON([]byte(virtualServiceDemo1))
|
||||||
annotations := map[string]string{
|
annotations := map[string]string{
|
||||||
OriginalSpecAnnotation: `{"spec":{"hosts":["echoserver.example.com"],"http":[{"route":[{"destination":{"host":"echoserver"}}]}]},"annotations":{"virtual":"test"}}`,
|
OriginalSpecAnnotation: `{"spec":{"hosts":["echoserver.example.com"],"http":[{"route":[{"destination":{"host":"echoserver"}}]}]},"annotations":{"virtual":"test"}}`,
|
||||||
"virtual": "test",
|
"virtual": "test",
|
||||||
|
|
@ -788,12 +881,12 @@ func TestDoTrafficRoutingWithIstio(t *testing.T) {
|
||||||
objects = append(objects, u)
|
objects = append(objects, u)
|
||||||
|
|
||||||
u = &unstructured.Unstructured{}
|
u = &unstructured.Unstructured{}
|
||||||
_ = u.UnmarshalJSON([]byte(destinationRuleDemo))
|
_ = u.UnmarshalJSON([]byte(destinationRuleDemo1))
|
||||||
annotations = map[string]string{
|
annotations = map[string]string{
|
||||||
OriginalSpecAnnotation: `{"spec":{"host":"echoserver","subsets":[{"labels":{"version":"base"},"name":"version-base"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}}`,
|
OriginalSpecAnnotation: `{"spec":{"host":"echoserver","trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}}`,
|
||||||
}
|
}
|
||||||
u.SetAnnotations(annotations)
|
u.SetAnnotations(annotations)
|
||||||
specStr = `{"host":"echoserver","subsets":[{"labels":{"version":"base"},"name":"version-base"},{"labels":{"istio.service.tag":"gray"},"name":"canary"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}`
|
specStr = `{"host":"echoserver","subsets":[{"labels":{"pod-template-hash":"podtemplatehash-v1"},"name":"stable"},{"labels":{"pod-template-hash":"podtemplatehash-v2"},"name":"canary"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}`
|
||||||
_ = json.Unmarshal([]byte(specStr), &spec)
|
_ = json.Unmarshal([]byte(specStr), &spec)
|
||||||
u.Object["spec"] = spec
|
u.Object["spec"] = spec
|
||||||
objects = append(objects, u)
|
objects = append(objects, u)
|
||||||
|
|
@ -815,12 +908,12 @@ func TestDoTrafficRoutingWithIstio(t *testing.T) {
|
||||||
getUnstructureds: func() []*unstructured.Unstructured {
|
getUnstructureds: func() []*unstructured.Unstructured {
|
||||||
objects := make([]*unstructured.Unstructured, 0)
|
objects := make([]*unstructured.Unstructured, 0)
|
||||||
u := &unstructured.Unstructured{}
|
u := &unstructured.Unstructured{}
|
||||||
_ = u.UnmarshalJSON([]byte(virtualServiceDemo))
|
_ = u.UnmarshalJSON([]byte(virtualServiceDemo2))
|
||||||
u.SetAPIVersion("networking.istio.io/v1alpha3")
|
u.SetAPIVersion("networking.istio.io/v1alpha3")
|
||||||
objects = append(objects, u)
|
objects = append(objects, u)
|
||||||
|
|
||||||
u = &unstructured.Unstructured{}
|
u = &unstructured.Unstructured{}
|
||||||
_ = u.UnmarshalJSON([]byte(destinationRuleDemo))
|
_ = u.UnmarshalJSON([]byte(destinationRuleDemo2))
|
||||||
u.SetAPIVersion("networking.istio.io/v1alpha3")
|
u.SetAPIVersion("networking.istio.io/v1alpha3")
|
||||||
objects = append(objects, u)
|
objects = append(objects, u)
|
||||||
return objects
|
return objects
|
||||||
|
|
@ -830,30 +923,34 @@ func TestDoTrafficRoutingWithIstio(t *testing.T) {
|
||||||
// set DisableGenerateCanaryService as true
|
// set DisableGenerateCanaryService as true
|
||||||
obj.Spec.Strategy.Canary.DisableGenerateCanaryService = true
|
obj.Spec.Strategy.Canary.DisableGenerateCanaryService = true
|
||||||
obj.Status.CanaryStatus.LastUpdateTime = &metav1.Time{Time: time.Now().Add(-10 * time.Second)}
|
obj.Status.CanaryStatus.LastUpdateTime = &metav1.Time{Time: time.Now().Add(-10 * time.Second)}
|
||||||
|
obj.Spec.Strategy.Canary.TrafficRoutings[0].AdditionalParams = map[string]string{
|
||||||
|
v1beta1.IstioStableSubsetName: "hello",
|
||||||
|
v1beta1.IstioCanarySubsetName: "world",
|
||||||
|
}
|
||||||
return obj, &util.Workload{RevisionLabelKey: apps.DefaultDeploymentUniqueLabelKey}
|
return obj, &util.Workload{RevisionLabelKey: apps.DefaultDeploymentUniqueLabelKey}
|
||||||
},
|
},
|
||||||
expectUnstructureds: func() []*unstructured.Unstructured {
|
expectUnstructureds: func() []*unstructured.Unstructured {
|
||||||
objects := make([]*unstructured.Unstructured, 0)
|
objects := make([]*unstructured.Unstructured, 0)
|
||||||
u := &unstructured.Unstructured{}
|
u := &unstructured.Unstructured{}
|
||||||
_ = u.UnmarshalJSON([]byte(virtualServiceDemo))
|
_ = u.UnmarshalJSON([]byte(virtualServiceDemo2))
|
||||||
annotations := map[string]string{
|
annotations := map[string]string{
|
||||||
OriginalSpecAnnotation: `{"spec":{"hosts":["echoserver.example.com"],"http":[{"route":[{"destination":{"host":"echoserver"}}]}]},"annotations":{"virtual":"test"}}`,
|
OriginalSpecAnnotation: `{"spec":{"hosts":["echoserver.example.com"],"http":[{"route":[{"destination":{"host":"echoserver","subset":"hello"}}]}]},"annotations":{"virtual":"test"}}`,
|
||||||
"virtual": "test",
|
"virtual": "test",
|
||||||
}
|
}
|
||||||
u.SetAnnotations(annotations)
|
u.SetAnnotations(annotations)
|
||||||
specStr := `{"hosts":["echoserver.example.com"],"http":[{"route":[{"destination":{"host":"echoserver"},"weight":95},{"destination":{"host":"echoserver","subset":"canary"},"weight":5}]}]}`
|
specStr := `{"hosts":["echoserver.example.com"],"http":[{"route":[{"destination":{"host":"echoserver","subset":"hello"},"weight":95},{"destination":{"host":"echoserver","subset":"world"},"weight":5}]}]}`
|
||||||
var spec interface{}
|
var spec interface{}
|
||||||
_ = json.Unmarshal([]byte(specStr), &spec)
|
_ = json.Unmarshal([]byte(specStr), &spec)
|
||||||
u.Object["spec"] = spec
|
u.Object["spec"] = spec
|
||||||
objects = append(objects, u)
|
objects = append(objects, u)
|
||||||
|
|
||||||
u = &unstructured.Unstructured{}
|
u = &unstructured.Unstructured{}
|
||||||
_ = u.UnmarshalJSON([]byte(destinationRuleDemo))
|
_ = u.UnmarshalJSON([]byte(destinationRuleDemo2))
|
||||||
annotations = map[string]string{
|
annotations = map[string]string{
|
||||||
OriginalSpecAnnotation: `{"spec":{"host":"echoserver","subsets":[{"labels":{"version":"base"},"name":"version-base"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}}`,
|
OriginalSpecAnnotation: `{"spec":{"host":"echoserver","subsets":[{"name":"hello"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}}`,
|
||||||
}
|
}
|
||||||
u.SetAnnotations(annotations)
|
u.SetAnnotations(annotations)
|
||||||
specStr = `{"host":"echoserver","subsets":[{"labels":{"version":"base"},"name":"version-base"},{"labels":{"istio.service.tag":"gray"},"name":"canary"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}`
|
specStr = `{"host":"echoserver","subsets":[{"labels":{"pod-template-hash":"podtemplatehash-v1"},"name":"hello"},{"labels":{"pod-template-hash":"podtemplatehash-v2"},"name":"world"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}`
|
||||||
_ = json.Unmarshal([]byte(specStr), &spec)
|
_ = json.Unmarshal([]byte(specStr), &spec)
|
||||||
u.Object["spec"] = spec
|
u.Object["spec"] = spec
|
||||||
objects = append(objects, u)
|
objects = append(objects, u)
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,16 @@ type LuaData struct {
|
||||||
Matches []v1beta1.HttpRouteMatch
|
Matches []v1beta1.HttpRouteMatch
|
||||||
CanaryService string
|
CanaryService string
|
||||||
StableService string
|
StableService string
|
||||||
|
// workload.RevisionLabelKey
|
||||||
|
RevisionLabelKey string
|
||||||
|
// status.CanaryStatus.StableRevision
|
||||||
|
StableRevision string
|
||||||
|
// status.CanaryStatus.PodTemplateHash
|
||||||
|
CanaryRevision string
|
||||||
|
// specify the name of subset used as stable subset, default 'stable'; if not found, create a subset named stable
|
||||||
|
StableName string
|
||||||
|
// sepcify the name of canary subset that will be created, default 'canary'
|
||||||
|
CanaryName string
|
||||||
}
|
}
|
||||||
type Data struct {
|
type Data struct {
|
||||||
Spec interface{} `json:"spec,omitempty"`
|
Spec interface{} `json:"spec,omitempty"`
|
||||||
|
|
@ -72,9 +82,16 @@ type Config struct {
|
||||||
CanaryService string
|
CanaryService string
|
||||||
StableService string
|
StableService string
|
||||||
// network providers need to be created
|
// network providers need to be created
|
||||||
TrafficConf []v1beta1.ObjectRef
|
TrafficConf []v1beta1.ObjectRef
|
||||||
OwnerRef metav1.OwnerReference
|
OwnerRef metav1.OwnerReference
|
||||||
DisableGenerateCanaryService bool
|
// DisableGenerateCanaryService bool
|
||||||
|
AdditionalParams map[string]string
|
||||||
|
// workload.RevisionLabelKey
|
||||||
|
RevisionLabelKey string
|
||||||
|
// status.CanaryStatus.StableRevision
|
||||||
|
StableRevision string
|
||||||
|
// status.CanaryStatus.PodTemplateHash
|
||||||
|
CanaryRevision string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCustomController(client client.Client, conf Config) (network.NetworkProvider, error) {
|
func NewCustomController(client client.Client, conf Config) (network.NetworkProvider, error) {
|
||||||
|
|
@ -268,13 +285,27 @@ func (r *customController) executeLuaForCanary(spec Data, strategy *v1beta1.Traf
|
||||||
// so we need to pass weight=-1 to indicate the case where weight is nil.
|
// so we need to pass weight=-1 to indicate the case where weight is nil.
|
||||||
weight = utilpointer.Int32(-1)
|
weight = utilpointer.Int32(-1)
|
||||||
}
|
}
|
||||||
|
// default value
|
||||||
|
stableSubsetName, ok := r.conf.AdditionalParams[v1beta1.IstioStableSubsetName]
|
||||||
|
if !ok {
|
||||||
|
stableSubsetName = "stable" //default value
|
||||||
|
}
|
||||||
|
canarySubsetName, ok := r.conf.AdditionalParams[v1beta1.IstioCanarySubsetName]
|
||||||
|
if !ok {
|
||||||
|
canarySubsetName = "canary" //default value
|
||||||
|
}
|
||||||
data := &LuaData{
|
data := &LuaData{
|
||||||
Data: spec,
|
Data: spec,
|
||||||
CanaryWeight: *weight,
|
CanaryWeight: *weight,
|
||||||
StableWeight: 100 - *weight,
|
StableWeight: 100 - *weight,
|
||||||
Matches: matches,
|
Matches: matches,
|
||||||
CanaryService: r.conf.CanaryService,
|
CanaryService: r.conf.CanaryService,
|
||||||
StableService: r.conf.StableService,
|
StableService: r.conf.StableService,
|
||||||
|
RevisionLabelKey: r.conf.RevisionLabelKey,
|
||||||
|
StableRevision: r.conf.StableRevision,
|
||||||
|
CanaryRevision: r.conf.CanaryRevision,
|
||||||
|
StableName: stableSubsetName,
|
||||||
|
CanaryName: canarySubsetName,
|
||||||
}
|
}
|
||||||
|
|
||||||
unObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(data)
|
unObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(data)
|
||||||
|
|
|
||||||
|
|
@ -89,9 +89,6 @@ var (
|
||||||
"host": "mockb",
|
"host": "mockb",
|
||||||
"subsets": [
|
"subsets": [
|
||||||
{
|
{
|
||||||
"labels": {
|
|
||||||
"version": "base"
|
|
||||||
},
|
|
||||||
"name": "version-base"
|
"name": "version-base"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
@ -281,6 +278,13 @@ func TestEnsureRoutes(t *testing.T) {
|
||||||
Name: "dr-demo",
|
Name: "dr-demo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
AdditionalParams: map[string]string{
|
||||||
|
v1beta1.IstioStableSubsetName: "version-base",
|
||||||
|
v1beta1.IstioCanarySubsetName: "canary",
|
||||||
|
},
|
||||||
|
StableRevision: "podtemplatehash-v1",
|
||||||
|
CanaryRevision: "podtemplatehash-v2",
|
||||||
|
RevisionLabelKey: "pod-template-hash",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
expectUnstructureds: func() []*unstructured.Unstructured {
|
expectUnstructureds: func() []*unstructured.Unstructured {
|
||||||
|
|
@ -301,10 +305,10 @@ func TestEnsureRoutes(t *testing.T) {
|
||||||
u = &unstructured.Unstructured{}
|
u = &unstructured.Unstructured{}
|
||||||
_ = u.UnmarshalJSON([]byte(destinationRuleDemo))
|
_ = u.UnmarshalJSON([]byte(destinationRuleDemo))
|
||||||
annotations = map[string]string{
|
annotations = map[string]string{
|
||||||
OriginalSpecAnnotation: `{"spec":{"host":"mockb","subsets":[{"labels":{"version":"base"},"name":"version-base"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}}`,
|
OriginalSpecAnnotation: `{"spec":{"host":"mockb","subsets":[{"name":"version-base"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}}`,
|
||||||
}
|
}
|
||||||
u.SetAnnotations(annotations)
|
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"}}}`
|
specStr = `{"host":"mockb","subsets":[{"labels":{"pod-template-hash":"podtemplatehash-v1"},"name":"version-base"},{"labels":{"pod-template-hash":"podtemplatehash-v2"},"name":"canary"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}`
|
||||||
_ = json.Unmarshal([]byte(specStr), &spec)
|
_ = json.Unmarshal([]byte(specStr), &spec)
|
||||||
u.Object["spec"] = spec
|
u.Object["spec"] = spec
|
||||||
objects = append(objects, u)
|
objects = append(objects, u)
|
||||||
|
|
@ -540,11 +544,16 @@ func TestLuaScript(t *testing.T) {
|
||||||
Annotations: testCase.Original.GetAnnotations(),
|
Annotations: testCase.Original.GetAnnotations(),
|
||||||
Spec: testCase.Original.Object["spec"],
|
Spec: testCase.Original.Object["spec"],
|
||||||
},
|
},
|
||||||
Matches: step.TrafficRoutingStrategy.Matches,
|
Matches: step.TrafficRoutingStrategy.Matches,
|
||||||
CanaryWeight: *weight,
|
CanaryWeight: *weight,
|
||||||
StableWeight: 100 - *weight,
|
StableWeight: 100 - *weight,
|
||||||
CanaryService: canaryService,
|
CanaryService: canaryService,
|
||||||
StableService: stableService,
|
StableService: stableService,
|
||||||
|
StableRevision: "podtemplatehash-v1",
|
||||||
|
CanaryRevision: "podtemplatehash-v2",
|
||||||
|
RevisionLabelKey: "pod-template-hash",
|
||||||
|
StableName: rollout.Spec.Strategy.Canary.TrafficRoutings[0].AdditionalParams[v1beta1.IstioStableSubsetName],
|
||||||
|
CanaryName: rollout.Spec.Strategy.Canary.TrafficRoutings[0].AdditionalParams[v1beta1.IstioCanarySubsetName],
|
||||||
}
|
}
|
||||||
nSpec, err := executeLua(data, script)
|
nSpec, err := executeLua(data, script)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -580,11 +589,16 @@ func TestLuaScript(t *testing.T) {
|
||||||
Annotations: testCase.Original.GetAnnotations(),
|
Annotations: testCase.Original.GetAnnotations(),
|
||||||
Spec: testCase.Original.Object["spec"],
|
Spec: testCase.Original.Object["spec"],
|
||||||
},
|
},
|
||||||
Matches: matches,
|
Matches: matches,
|
||||||
CanaryWeight: *weight,
|
CanaryWeight: *weight,
|
||||||
StableWeight: 100 - *weight,
|
StableWeight: 100 - *weight,
|
||||||
CanaryService: canaryService,
|
CanaryService: canaryService,
|
||||||
StableService: stableService,
|
StableService: stableService,
|
||||||
|
StableRevision: "podtemplatehash-v1",
|
||||||
|
CanaryRevision: "podtemplatehash-v2",
|
||||||
|
RevisionLabelKey: "pod-template-hash",
|
||||||
|
StableName: trafficRouting.Spec.ObjectRef[0].AdditionalParams[v1beta1.IstioStableSubsetName],
|
||||||
|
CanaryName: trafficRouting.Spec.ObjectRef[0].AdditionalParams[v1beta1.IstioCanarySubsetName],
|
||||||
}
|
}
|
||||||
nSpec, err := executeLua(data, script)
|
nSpec, err := executeLua(data, script)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,51 @@
|
||||||
local spec = obj.data.spec
|
local spec = obj.data.spec
|
||||||
|
local podLabelKey = obj.revisionLabelKey
|
||||||
|
|
||||||
|
if spec.subsets == nil then
|
||||||
|
spec.subsets = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- selector lables might come from pod-template-hash and patchPodTemplateMetadata
|
||||||
|
-- now we only support pod-template-hash
|
||||||
|
local stableLabels = {}
|
||||||
|
if obj.stableRevision ~= nil and obj.stableRevision ~= "" then
|
||||||
|
stableLabels[podLabelKey] = obj.stableRevision
|
||||||
|
end
|
||||||
|
local canaryLabels = {}
|
||||||
|
if obj.canaryRevision ~= nil and obj.canaryRevision ~= "" then
|
||||||
|
canaryLabels[podLabelKey] = obj.canaryRevision
|
||||||
|
end
|
||||||
|
local StableNameAlreadyExist = false
|
||||||
|
|
||||||
|
-- if stableName already exists, just appened the lables
|
||||||
|
for _, subset in ipairs(spec.subsets) do
|
||||||
|
if subset.name == obj.stableName then
|
||||||
|
StableNameAlreadyExist = true
|
||||||
|
if next(stableLabels) ~= nil then
|
||||||
|
subset.labels = subset.labels or {}
|
||||||
|
for key, value in pairs(stableLabels) do
|
||||||
|
subset.labels[key] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- if stableName doesn't exist, create it and its labels
|
||||||
|
if not StableNameAlreadyExist then
|
||||||
|
local stable = {}
|
||||||
|
stable.name = obj.stableName
|
||||||
|
if next(stableLabels) ~= nil then
|
||||||
|
stable.labels = stableLabels
|
||||||
|
end
|
||||||
|
table.insert(spec.subsets, stable)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Aussue the canaryName never exist, create it and its labels
|
||||||
local canary = {}
|
local canary = {}
|
||||||
canary.labels = {}
|
canary.name = obj.canaryName
|
||||||
canary.name = "canary"
|
if next(canaryLabels) ~= nil then
|
||||||
local podLabelKey = "istio.service.tag"
|
canary.labels = canaryLabels
|
||||||
canary.labels[podLabelKey] = "gray"
|
end
|
||||||
table.insert(spec.subsets, canary)
|
table.insert(spec.subsets, canary)
|
||||||
|
|
||||||
|
|
||||||
return obj.data
|
return obj.data
|
||||||
|
|
@ -159,7 +159,7 @@ function GenerateMatchedRoutes(spec, matches, stableService, canaryService, stab
|
||||||
-- if stableService == canaryService, then do e2e release
|
-- if stableService == canaryService, then do e2e release
|
||||||
if stableService == canaryService then
|
if stableService == canaryService then
|
||||||
route.route[1].destination.host = stableService
|
route.route[1].destination.host = stableService
|
||||||
route.route[1].destination.subset = "canary"
|
route.route[1].destination.subset = obj.canaryName
|
||||||
else
|
else
|
||||||
route.route[1].destination.host = canaryService
|
route.route[1].destination.host = canaryService
|
||||||
end
|
end
|
||||||
|
|
@ -189,7 +189,7 @@ function GenerateRoutes(spec, stableService, canaryService, stableWeight, canary
|
||||||
canary = {
|
canary = {
|
||||||
destination = {
|
destination = {
|
||||||
host = stableService,
|
host = stableService,
|
||||||
subset = "canary",
|
subset = obj.canaryName,
|
||||||
},
|
},
|
||||||
weight = canaryWeight,
|
weight = canaryWeight,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue