mirror of
https://github.com/fluxcd/flagger.git
synced 2026-04-15 06:57:34 +00:00
Merge pull request #416 from weaveworks/service-name
Implement service name override
This commit is contained in:
@@ -86,6 +86,8 @@ spec:
|
||||
kind: HorizontalPodAutoscaler
|
||||
name: podinfo
|
||||
service:
|
||||
# service name (optional)
|
||||
name: podinfo
|
||||
# ClusterIP port number
|
||||
port: 9898
|
||||
# container port name or number (optional)
|
||||
|
||||
@@ -115,6 +115,9 @@ spec:
|
||||
type: object
|
||||
required: ["port"]
|
||||
properties:
|
||||
name:
|
||||
description: Kubernetes service name
|
||||
type: string
|
||||
port:
|
||||
description: Container port number
|
||||
type: number
|
||||
|
||||
@@ -116,6 +116,9 @@ spec:
|
||||
type: object
|
||||
required: ['port']
|
||||
properties:
|
||||
name:
|
||||
description: Kubernetes service name
|
||||
type: string
|
||||
port:
|
||||
description: Container port number
|
||||
type: number
|
||||
|
||||
+8
-4
@@ -188,6 +188,8 @@ spec:
|
||||
kind: Deployment
|
||||
name: podinfo
|
||||
service:
|
||||
# service name (optional)
|
||||
name: podinfo
|
||||
# ClusterIP port number (required)
|
||||
port: 9898
|
||||
# container port name or number
|
||||
@@ -196,19 +198,21 @@ spec:
|
||||
portName: http
|
||||
```
|
||||
|
||||
If the `service.name` is not specified, then `targetRef.name` is used for the apex domain and canary/primary services name prefix.
|
||||
You should treat the service name as an immutable field, changing it could result in routing conflicts.
|
||||
|
||||
Based on the canary spec service, Flagger generates the following Kubernetes ClusterIP service:
|
||||
|
||||
* `<targetRef.name>.<namespace>.svc.cluster.local`
|
||||
* `<service.name>.<namespace>.svc.cluster.local`
|
||||
selector `app=<name>-primary`
|
||||
* `<targetRef.name>-primary.<namespace>.svc.cluster.local`
|
||||
* `<service.name>-primary.<namespace>.svc.cluster.local`
|
||||
selector `app=<name>-primary`
|
||||
* `<targetRef.name>-canary.<namespace>.svc.cluster.local`
|
||||
* `<service.name>-canary.<namespace>.svc.cluster.local`
|
||||
selector `app=<name>`
|
||||
|
||||
This ensures that traffic coming from a namespace outside the mesh to `podinfo.test:9898`
|
||||
will be routed to the latest stable release of your app.
|
||||
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
|
||||
@@ -32,6 +32,8 @@ spec:
|
||||
kind: HorizontalPodAutoscaler
|
||||
name: podinfo
|
||||
service:
|
||||
# service name (optional)
|
||||
name: podinfo
|
||||
# ClusterIP port number
|
||||
port: 9898
|
||||
# ClusterIP port name can be http or grpc (default http)
|
||||
|
||||
@@ -15,10 +15,10 @@ require (
|
||||
go.uber.org/multierr v1.1.0 // indirect
|
||||
go.uber.org/zap v1.10.0
|
||||
gopkg.in/h2non/gock.v1 v1.0.14
|
||||
k8s.io/api v0.17.0
|
||||
k8s.io/apimachinery v0.17.1-beta.0
|
||||
k8s.io/client-go v0.17.0
|
||||
k8s.io/code-generator v0.17.0
|
||||
k8s.io/api v0.17.1
|
||||
k8s.io/apimachinery v0.17.1
|
||||
k8s.io/client-go v0.17.1
|
||||
k8s.io/code-generator v0.17.1
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f
|
||||
)
|
||||
|
||||
|
||||
@@ -290,15 +290,14 @@ gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.17.0 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM=
|
||||
k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI=
|
||||
k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
|
||||
k8s.io/apimachinery v0.17.1-beta.0 h1:0Wl/KpAiFOMe9to5h8x2Y6JnjV+BEWJiTcUk1Vx7zdE=
|
||||
k8s.io/apimachinery v0.17.1-beta.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
|
||||
k8s.io/client-go v0.17.0 h1:8QOGvUGdqDMFrm9sD6IUFl256BcffynGoe80sxgTEDg=
|
||||
k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k=
|
||||
k8s.io/code-generator v0.17.0 h1:y+KWtDWNqlJzJu/kUy8goJZO0X71PGIpAHLX8a0JYk0=
|
||||
k8s.io/code-generator v0.17.0/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s=
|
||||
k8s.io/api v0.17.1 h1:i46MidoDOE9tvQ0TTEYggf3ka/pziP1+tHI/GFVeJao=
|
||||
k8s.io/api v0.17.1/go.mod h1:zxiAc5y8Ngn4fmhWUtSxuUlkfz1ixT7j9wESokELzOg=
|
||||
k8s.io/apimachinery v0.17.1 h1:zUjS3szTxoUjTDYNvdFkYt2uMEXLcthcbp+7uZvWhYM=
|
||||
k8s.io/apimachinery v0.17.1/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
|
||||
k8s.io/client-go v0.17.1 h1:LbbuZ5tI7OYx4et5DfRFcJuoojvpYO0c7vps2rgJsHY=
|
||||
k8s.io/client-go v0.17.1/go.mod h1:HZtHJSC/VuSHcETN9QA5QDZky1tXiYrkF/7t7vRpO1A=
|
||||
k8s.io/code-generator v0.17.1 h1:e3B1UqRzRUWygp7WD+QTRT3ZUahPIaRKF0OFa7duQwI=
|
||||
k8s.io/code-generator v0.17.1/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s=
|
||||
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6 h1:4s3/R4+OYYYUKptXPhZKjQ04WJ6EhQQVFdjOFvCazDk=
|
||||
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/gengo v0.0.0-20190822140433-26a664648505 h1:ZY6yclUKVbZ+SdWnkfY+Je5vrMpKOxmGeKRbsXVmqYM=
|
||||
|
||||
@@ -115,6 +115,9 @@ spec:
|
||||
type: object
|
||||
required: ["port"]
|
||||
properties:
|
||||
name:
|
||||
description: Kubernetes service name
|
||||
type: string
|
||||
port:
|
||||
description: Container port number
|
||||
type: number
|
||||
|
||||
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package v1alpha3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
hpav1 "k8s.io/api/autoscaling/v1"
|
||||
@@ -69,7 +70,7 @@ type CanarySpec struct {
|
||||
// virtual service spec
|
||||
Service CanaryService `json:"service"`
|
||||
|
||||
// metrics and thresholds
|
||||
// metrics, thresholds and webhooks spec
|
||||
CanaryAnalysis CanaryAnalysis `json:"canaryAnalysis"`
|
||||
|
||||
// the maximum time in seconds for a canary deployment to make progress
|
||||
@@ -92,8 +93,9 @@ type CanaryList struct {
|
||||
}
|
||||
|
||||
// CanaryService is used to create ClusterIP services
|
||||
// and Istio Virtual Service
|
||||
// and service mesh or ingress routing objects
|
||||
type CanaryService struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Port int32 `json:"port"`
|
||||
PortName string `json:"portName,omitempty"`
|
||||
TargetPort intstr.IntOrString `json:"targetPort,omitempty"`
|
||||
@@ -126,7 +128,7 @@ type CanaryAnalysis struct {
|
||||
Iterations int `json:"iterations,omitempty"`
|
||||
}
|
||||
|
||||
// CanaryMetric holds the reference to Istio metrics used for canary analysis
|
||||
// CanaryMetric holds the reference to metrics used for canary analysis
|
||||
type CanaryMetric struct {
|
||||
Name string `json:"name"`
|
||||
Interval string `json:"interval,omitempty"`
|
||||
@@ -171,6 +173,17 @@ type CanaryWebhookPayload struct {
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// GetServiceNames returns the apex, primary and canary Kubernetes service names
|
||||
func (c *Canary) GetServiceNames() (apexName, primaryName, canaryName string) {
|
||||
apexName = c.Spec.TargetRef.Name
|
||||
if c.Spec.Service.Name != "" {
|
||||
apexName = c.Spec.Service.Name
|
||||
}
|
||||
primaryName = fmt.Sprintf("%s-primary", apexName)
|
||||
canaryName = fmt.Sprintf("%s-canary", apexName)
|
||||
return
|
||||
}
|
||||
|
||||
// GetProgressDeadlineSeconds returns the progress deadline (default 600s)
|
||||
func (c *Canary) GetProgressDeadlineSeconds() int {
|
||||
if c.Spec.ProgressDeadlineSeconds != nil {
|
||||
|
||||
@@ -105,17 +105,25 @@ func NewController(
|
||||
flaggerInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: ctrl.enqueue,
|
||||
UpdateFunc: func(old, new interface{}) {
|
||||
oldRoll, ok := checkCustomResourceType(old, logger)
|
||||
oldCanary, ok := checkCustomResourceType(old, logger)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
newRoll, ok := checkCustomResourceType(new, logger)
|
||||
newCanary, ok := checkCustomResourceType(new, logger)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(newRoll.Spec, oldRoll.Spec); diff != "" {
|
||||
ctrl.logger.Debugf("Diff detected %s.%s %s", oldRoll.Name, oldRoll.Namespace, diff)
|
||||
if diff := cmp.Diff(newCanary.Spec, oldCanary.Spec); diff != "" {
|
||||
ctrl.logger.Debugf("Diff detected %s.%s %s", oldCanary.Name, oldCanary.Namespace, diff)
|
||||
|
||||
// warn about routing conflicts when service name changes
|
||||
if oldCanary.Spec.Service.Name != "" && oldCanary.Spec.Service.Name != newCanary.Spec.Service.Name {
|
||||
ctrl.logger.With("canary", fmt.Sprintf("%s.%s", oldCanary.Name, oldCanary.Namespace)).
|
||||
Warnf("The service name changed to %s, remove %s objects to avoid routing conflicts",
|
||||
newCanary.Spec.Service.Name, oldCanary.Spec.Service.Name)
|
||||
}
|
||||
|
||||
ctrl.enqueue(new)
|
||||
}
|
||||
},
|
||||
|
||||
+19
-21
@@ -33,16 +33,14 @@ func (ar *AppMeshRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
return fmt.Errorf("mesh name cannot be empty")
|
||||
}
|
||||
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
targetHost := fmt.Sprintf("%s.%s", targetName, canary.Namespace)
|
||||
primaryName := fmt.Sprintf("%s-primary", targetName)
|
||||
apexName, primaryName, canaryName := canary.GetServiceNames()
|
||||
targetHost := fmt.Sprintf("%s.%s", apexName, canary.Namespace)
|
||||
primaryHost := fmt.Sprintf("%s.%s", primaryName, canary.Namespace)
|
||||
canaryName := fmt.Sprintf("%s-canary", targetName)
|
||||
canaryHost := fmt.Sprintf("%s.%s", canaryName, canary.Namespace)
|
||||
|
||||
// sync virtual node e.g. app-namespace
|
||||
// DNS app.namespace
|
||||
err := ar.reconcileVirtualNode(canary, targetName, primaryHost)
|
||||
err := ar.reconcileVirtualNode(canary, apexName, primaryHost)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -162,14 +160,14 @@ func (ar *AppMeshRouter) reconcileVirtualNode(canary *flaggerv1.Canary, name str
|
||||
|
||||
// reconcileVirtualService creates or updates a virtual service
|
||||
func (ar *AppMeshRouter) reconcileVirtualService(canary *flaggerv1.Canary, name string, canaryWeight int64) error {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
canaryVirtualNode := fmt.Sprintf("%s-canary", targetName)
|
||||
primaryVirtualNode := fmt.Sprintf("%s-primary", targetName)
|
||||
apexName, _, _ := canary.GetServiceNames()
|
||||
canaryVirtualNode := fmt.Sprintf("%s-canary", apexName)
|
||||
primaryVirtualNode := fmt.Sprintf("%s-primary", apexName)
|
||||
protocol := ar.getProtocol(canary)
|
||||
|
||||
routerName := targetName
|
||||
routerName := apexName
|
||||
if canaryWeight > 0 {
|
||||
routerName = fmt.Sprintf("%s-canary", targetName)
|
||||
routerName = fmt.Sprintf("%s-canary", apexName)
|
||||
}
|
||||
// App Mesh supports only URI prefix
|
||||
routePrefix := "/"
|
||||
@@ -208,7 +206,7 @@ func (ar *AppMeshRouter) reconcileVirtualService(canary *flaggerv1.Canary, name
|
||||
if len(canary.Spec.CanaryAnalysis.Match) > 0 && canaryWeight == 0 {
|
||||
routes = []appmeshv1.Route{
|
||||
{
|
||||
Name: fmt.Sprintf("%s-a", targetName),
|
||||
Name: fmt.Sprintf("%s-a", apexName),
|
||||
Priority: int64p(10),
|
||||
Http: &appmeshv1.HttpRoute{
|
||||
Match: appmeshv1.HttpRouteMatch{
|
||||
@@ -231,7 +229,7 @@ func (ar *AppMeshRouter) reconcileVirtualService(canary *flaggerv1.Canary, name
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: fmt.Sprintf("%s-b", targetName),
|
||||
Name: fmt.Sprintf("%s-b", apexName),
|
||||
Priority: int64p(20),
|
||||
Http: &appmeshv1.HttpRoute{
|
||||
Match: appmeshv1.HttpRouteMatch{
|
||||
@@ -341,8 +339,8 @@ func (ar *AppMeshRouter) GetRoutes(canary *flaggerv1.Canary) (
|
||||
mirrored bool,
|
||||
err error,
|
||||
) {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
vsName := fmt.Sprintf("%s.%s", targetName, canary.Namespace)
|
||||
apexName, _, _ := canary.GetServiceNames()
|
||||
vsName := fmt.Sprintf("%s.%s", apexName, canary.Namespace)
|
||||
vs, err := ar.appmeshClient.AppmeshV1beta1().VirtualServices(canary.Namespace).Get(vsName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
@@ -360,17 +358,17 @@ func (ar *AppMeshRouter) GetRoutes(canary *flaggerv1.Canary) (
|
||||
|
||||
targets := vs.Spec.Routes[0].Http.Action.WeightedTargets
|
||||
for _, t := range targets {
|
||||
if t.VirtualNodeName == fmt.Sprintf("%s-canary", targetName) {
|
||||
if t.VirtualNodeName == fmt.Sprintf("%s-canary", apexName) {
|
||||
canaryWeight = int(t.Weight)
|
||||
}
|
||||
if t.VirtualNodeName == fmt.Sprintf("%s-primary", targetName) {
|
||||
if t.VirtualNodeName == fmt.Sprintf("%s-primary", apexName) {
|
||||
primaryWeight = int(t.Weight)
|
||||
}
|
||||
}
|
||||
|
||||
if primaryWeight == 0 && canaryWeight == 0 {
|
||||
err = fmt.Errorf("VirtualService %s does not contain routes for %s-primary and %s-canary",
|
||||
vsName, targetName, targetName)
|
||||
vsName, apexName, apexName)
|
||||
}
|
||||
|
||||
mirrored = false
|
||||
@@ -385,8 +383,8 @@ func (ar *AppMeshRouter) SetRoutes(
|
||||
canaryWeight int,
|
||||
mirrored bool,
|
||||
) error {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
vsName := fmt.Sprintf("%s.%s", targetName, canary.Namespace)
|
||||
apexName, _, _ := canary.GetServiceNames()
|
||||
vsName := fmt.Sprintf("%s.%s", apexName, canary.Namespace)
|
||||
vs, err := ar.appmeshClient.AppmeshV1beta1().VirtualServices(canary.Namespace).Get(vsName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
@@ -399,11 +397,11 @@ func (ar *AppMeshRouter) SetRoutes(
|
||||
vsClone.Spec.Routes[0].Http.Action = appmeshv1.HttpRouteAction{
|
||||
WeightedTargets: []appmeshv1.WeightedTarget{
|
||||
{
|
||||
VirtualNodeName: fmt.Sprintf("%s-canary", targetName),
|
||||
VirtualNodeName: fmt.Sprintf("%s-canary", apexName),
|
||||
Weight: int64(canaryWeight),
|
||||
},
|
||||
{
|
||||
VirtualNodeName: fmt.Sprintf("%s-primary", targetName),
|
||||
VirtualNodeName: fmt.Sprintf("%s-primary", apexName),
|
||||
Weight: int64(primaryWeight),
|
||||
},
|
||||
},
|
||||
|
||||
+17
-22
@@ -26,9 +26,7 @@ type ContourRouter struct {
|
||||
|
||||
// Reconcile creates or updates the HTTP proxy
|
||||
func (cr *ContourRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
primaryName := fmt.Sprintf("%s-primary", targetName)
|
||||
canaryName := fmt.Sprintf("%s-canary", targetName)
|
||||
apexName, primaryName, canaryName := canary.GetServiceNames()
|
||||
|
||||
newSpec := contourv1.HTTPProxySpec{
|
||||
Routes: []contourv1.Route{
|
||||
@@ -131,11 +129,11 @@ func (cr *ContourRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
}
|
||||
}
|
||||
|
||||
proxy, err := cr.contourClient.ProjectcontourV1().HTTPProxies(canary.Namespace).Get(targetName, metav1.GetOptions{})
|
||||
proxy, err := cr.contourClient.ProjectcontourV1().HTTPProxies(canary.Namespace).Get(apexName, metav1.GetOptions{})
|
||||
if errors.IsNotFound(err) {
|
||||
proxy = &contourv1.HTTPProxy{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: targetName,
|
||||
Name: apexName,
|
||||
Namespace: canary.Namespace,
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
*metav1.NewControllerRef(canary, schema.GroupVersionKind{
|
||||
@@ -154,7 +152,7 @@ func (cr *ContourRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
|
||||
_, err = cr.contourClient.ProjectcontourV1().HTTPProxies(canary.Namespace).Create(proxy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("HTTPProxy %s.%s create error %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("HTTPProxy %s.%s create error %v", apexName, canary.Namespace, err)
|
||||
}
|
||||
cr.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
|
||||
Infof("HTTPProxy %s.%s created", proxy.GetName(), canary.Namespace)
|
||||
@@ -162,7 +160,7 @@ func (cr *ContourRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("HTTPProxy %s.%s query error %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("HTTPProxy %s.%s query error %v", apexName, canary.Namespace, err)
|
||||
}
|
||||
|
||||
// update HTTPProxy but keep the original destination weights
|
||||
@@ -177,7 +175,7 @@ func (cr *ContourRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
|
||||
_, err = cr.contourClient.ProjectcontourV1().HTTPProxies(canary.Namespace).Update(clone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("HTTPProxy %s.%s update error %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("HTTPProxy %s.%s update error %v", apexName, canary.Namespace, err)
|
||||
}
|
||||
cr.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
|
||||
Infof("HTTPProxy %s.%s updated", proxy.GetName(), canary.Namespace)
|
||||
@@ -194,21 +192,20 @@ func (cr *ContourRouter) GetRoutes(canary *flaggerv1.Canary) (
|
||||
mirrored bool,
|
||||
err error,
|
||||
) {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
primaryName := fmt.Sprintf("%s-primary", targetName)
|
||||
apexName, primaryName, _ := canary.GetServiceNames()
|
||||
|
||||
proxy, err := cr.contourClient.ProjectcontourV1().HTTPProxies(canary.Namespace).Get(targetName, metav1.GetOptions{})
|
||||
proxy, err := cr.contourClient.ProjectcontourV1().HTTPProxies(canary.Namespace).Get(apexName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
err = fmt.Errorf("HTTPProxy %s.%s not found", targetName, canary.Namespace)
|
||||
err = fmt.Errorf("HTTPProxy %s.%s not found", apexName, canary.Namespace)
|
||||
return
|
||||
}
|
||||
err = fmt.Errorf("HTTPProxy %s.%s query error %v", targetName, canary.Namespace, err)
|
||||
err = fmt.Errorf("HTTPProxy %s.%s query error %v", apexName, canary.Namespace, err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(proxy.Spec.Routes) < 1 || len(proxy.Spec.Routes[0].Services) < 2 {
|
||||
err = fmt.Errorf("HTTPProxy %s.%s services not found", targetName, canary.Namespace)
|
||||
err = fmt.Errorf("HTTPProxy %s.%s services not found", apexName, canary.Namespace)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -230,21 +227,19 @@ func (cr *ContourRouter) SetRoutes(
|
||||
canaryWeight int,
|
||||
mirrored bool,
|
||||
) error {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
primaryName := fmt.Sprintf("%s-primary", targetName)
|
||||
canaryName := fmt.Sprintf("%s-canary", targetName)
|
||||
apexName, primaryName, canaryName := canary.GetServiceNames()
|
||||
|
||||
if primaryWeight == 0 && canaryWeight == 0 {
|
||||
return fmt.Errorf("HTTPProxy %s.%s update failed: no valid weights", targetName, canary.Namespace)
|
||||
return fmt.Errorf("HTTPProxy %s.%s update failed: no valid weights", apexName, canary.Namespace)
|
||||
}
|
||||
|
||||
proxy, err := cr.contourClient.ProjectcontourV1().HTTPProxies(canary.Namespace).Get(targetName, metav1.GetOptions{})
|
||||
proxy, err := cr.contourClient.ProjectcontourV1().HTTPProxies(canary.Namespace).Get(apexName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return fmt.Errorf("HTTPProxy %s.%s not found", targetName, canary.Namespace)
|
||||
return fmt.Errorf("HTTPProxy %s.%s not found", apexName, canary.Namespace)
|
||||
|
||||
}
|
||||
return fmt.Errorf("HTTPProxy %s.%s query error %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("HTTPProxy %s.%s query error %v", apexName, canary.Namespace, err)
|
||||
}
|
||||
|
||||
proxy.Spec = contourv1.HTTPProxySpec{
|
||||
@@ -349,7 +344,7 @@ func (cr *ContourRouter) SetRoutes(
|
||||
|
||||
_, err = cr.contourClient.ProjectcontourV1().HTTPProxies(canary.Namespace).Update(proxy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("HTTPProxy %s.%s update error %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("HTTPProxy %s.%s update error %v", apexName, canary.Namespace, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+21
-21
@@ -27,9 +27,9 @@ type GlooRouter struct {
|
||||
|
||||
// Reconcile creates or updates the Istio virtual service
|
||||
func (gr *GlooRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
canaryName := fmt.Sprintf("%s-%s-canary-%v", canary.Namespace, canary.Spec.TargetRef.Name, canary.Spec.Service.Port)
|
||||
primaryName := fmt.Sprintf("%s-%s-primary-%v", canary.Namespace, canary.Spec.TargetRef.Name, canary.Spec.Service.Port)
|
||||
apexName, _, _ := canary.GetServiceNames()
|
||||
canaryName := fmt.Sprintf("%s-%s-canary-%v", canary.Namespace, apexName, canary.Spec.Service.Port)
|
||||
primaryName := fmt.Sprintf("%s-%s-primary-%v", canary.Namespace, apexName, canary.Spec.Service.Port)
|
||||
|
||||
newSpec := gloov1.UpstreamGroupSpec{
|
||||
Destinations: []gloov1.WeightedDestination{
|
||||
@@ -54,11 +54,11 @@ func (gr *GlooRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
},
|
||||
}
|
||||
|
||||
upstreamGroup, err := gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Get(targetName, metav1.GetOptions{})
|
||||
upstreamGroup, err := gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Get(apexName, metav1.GetOptions{})
|
||||
if errors.IsNotFound(err) {
|
||||
upstreamGroup = &gloov1.UpstreamGroup{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: targetName,
|
||||
Name: apexName,
|
||||
Namespace: canary.Namespace,
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
*metav1.NewControllerRef(canary, schema.GroupVersionKind{
|
||||
@@ -73,7 +73,7 @@ func (gr *GlooRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
|
||||
_, err = gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Create(upstreamGroup)
|
||||
if err != nil {
|
||||
return fmt.Errorf("UpstreamGroup %s.%s create error %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("UpstreamGroup %s.%s create error %v", apexName, canary.Namespace, err)
|
||||
}
|
||||
gr.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
|
||||
Infof("UpstreamGroup %s.%s created", upstreamGroup.GetName(), canary.Namespace)
|
||||
@@ -81,7 +81,7 @@ func (gr *GlooRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("UpstreamGroup %s.%s query error %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("UpstreamGroup %s.%s query error %v", apexName, canary.Namespace, err)
|
||||
}
|
||||
|
||||
// update upstreamGroup but keep the original destination weights
|
||||
@@ -96,7 +96,7 @@ func (gr *GlooRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
|
||||
_, err = gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Update(clone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("UpstreamGroup %s.%s update error %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("UpstreamGroup %s.%s update error %v", apexName, canary.Namespace, err)
|
||||
}
|
||||
gr.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
|
||||
Infof("UpstreamGroup %s.%s updated", upstreamGroup.GetName(), canary.Namespace)
|
||||
@@ -113,21 +113,21 @@ func (gr *GlooRouter) GetRoutes(canary *flaggerv1.Canary) (
|
||||
mirrored bool,
|
||||
err error,
|
||||
) {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
apexName := canary.Spec.TargetRef.Name
|
||||
primaryName := fmt.Sprintf("%s-%s-primary-%v", canary.Namespace, canary.Spec.TargetRef.Name, canary.Spec.Service.Port)
|
||||
|
||||
upstreamGroup, err := gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Get(targetName, metav1.GetOptions{})
|
||||
upstreamGroup, err := gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Get(apexName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
err = fmt.Errorf("UpstreamGroup %s.%s not found", targetName, canary.Namespace)
|
||||
err = fmt.Errorf("UpstreamGroup %s.%s not found", apexName, canary.Namespace)
|
||||
return
|
||||
}
|
||||
err = fmt.Errorf("UpstreamGroup %s.%s query error %v", targetName, canary.Namespace, err)
|
||||
err = fmt.Errorf("UpstreamGroup %s.%s query error %v", apexName, canary.Namespace, err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(upstreamGroup.Spec.Destinations) < 2 {
|
||||
err = fmt.Errorf("UpstreamGroup %s.%s destinations not found", targetName, canary.Namespace)
|
||||
err = fmt.Errorf("UpstreamGroup %s.%s destinations not found", apexName, canary.Namespace)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -149,21 +149,21 @@ func (gr *GlooRouter) SetRoutes(
|
||||
canaryWeight int,
|
||||
mirrored bool,
|
||||
) error {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
canaryName := fmt.Sprintf("%s-%s-canary-%v", canary.Namespace, canary.Spec.TargetRef.Name, canary.Spec.Service.Port)
|
||||
primaryName := fmt.Sprintf("%s-%s-primary-%v", canary.Namespace, canary.Spec.TargetRef.Name, canary.Spec.Service.Port)
|
||||
apexName, _, _ := canary.GetServiceNames()
|
||||
canaryName := fmt.Sprintf("%s-%s-canary-%v", canary.Namespace, apexName, canary.Spec.Service.Port)
|
||||
primaryName := fmt.Sprintf("%s-%s-primary-%v", canary.Namespace, apexName, canary.Spec.Service.Port)
|
||||
|
||||
if primaryWeight == 0 && canaryWeight == 0 {
|
||||
return fmt.Errorf("RoutingRule %s.%s update failed: no valid weights", targetName, canary.Namespace)
|
||||
return fmt.Errorf("RoutingRule %s.%s update failed: no valid weights", apexName, canary.Namespace)
|
||||
}
|
||||
|
||||
upstreamGroup, err := gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Get(targetName, metav1.GetOptions{})
|
||||
upstreamGroup, err := gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Get(apexName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return fmt.Errorf("UpstreamGroup %s.%s not found", targetName, canary.Namespace)
|
||||
return fmt.Errorf("UpstreamGroup %s.%s not found", apexName, canary.Namespace)
|
||||
|
||||
}
|
||||
return fmt.Errorf("UpstreamGroup %s.%s query error %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("UpstreamGroup %s.%s query error %v", apexName, canary.Namespace, err)
|
||||
}
|
||||
|
||||
upstreamGroup.Spec = gloov1.UpstreamGroupSpec{
|
||||
@@ -191,7 +191,7 @@ func (gr *GlooRouter) SetRoutes(
|
||||
|
||||
_, err = gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Update(upstreamGroup)
|
||||
if err != nil {
|
||||
return fmt.Errorf("UpstreamGroup %s.%s update error %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("UpstreamGroup %s.%s update error %v", apexName, canary.Namespace, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ func (i *IngressRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
return fmt.Errorf("ingress selector is empty")
|
||||
}
|
||||
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
canaryName := fmt.Sprintf("%s-canary", targetName)
|
||||
apexName, _, _ := canary.GetServiceNames()
|
||||
canaryName := fmt.Sprintf("%s-canary", apexName)
|
||||
canaryIngressName := fmt.Sprintf("%s-canary", canary.Spec.IngressRef.Name)
|
||||
|
||||
ingress, err := i.kubeClient.ExtensionsV1beta1().Ingresses(canary.Namespace).Get(canary.Spec.IngressRef.Name, metav1.GetOptions{})
|
||||
@@ -42,7 +42,7 @@ func (i *IngressRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
backendExists := false
|
||||
for k, v := range ingressClone.Spec.Rules {
|
||||
for x, y := range v.HTTP.Paths {
|
||||
if y.Backend.ServiceName == targetName {
|
||||
if y.Backend.ServiceName == apexName {
|
||||
ingressClone.Spec.Rules[k].HTTP.Paths[x].Backend.ServiceName = canaryName
|
||||
backendExists = true
|
||||
break
|
||||
@@ -51,7 +51,7 @@ func (i *IngressRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
}
|
||||
|
||||
if !backendExists {
|
||||
return fmt.Errorf("backend %s not found in ingress %s", targetName, canary.Spec.IngressRef.Name)
|
||||
return fmt.Errorf("backend %s not found in ingress %s", apexName, canary.Spec.IngressRef.Name)
|
||||
}
|
||||
|
||||
canaryIngress, err := i.kubeClient.ExtensionsV1beta1().Ingresses(canary.Namespace).Get(canaryIngressName, metav1.GetOptions{})
|
||||
|
||||
+22
-27
@@ -26,8 +26,7 @@ type IstioRouter struct {
|
||||
|
||||
// Reconcile creates or updates the Istio virtual service and destination rules
|
||||
func (ir *IstioRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
canaryName := fmt.Sprintf("%s-canary", canary.Spec.TargetRef.Name)
|
||||
primaryName := fmt.Sprintf("%s-primary", canary.Spec.TargetRef.Name)
|
||||
_, primaryName, canaryName := canary.GetServiceNames()
|
||||
|
||||
err := ir.reconcileDestinationRule(canary, canaryName)
|
||||
if err != nil {
|
||||
@@ -101,19 +100,19 @@ func (ir *IstioRouter) reconcileDestinationRule(canary *flaggerv1.Canary, name s
|
||||
}
|
||||
|
||||
func (ir *IstioRouter) reconcileVirtualService(canary *flaggerv1.Canary) error {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
apexName, primaryName, canaryName := canary.GetServiceNames()
|
||||
|
||||
// set hosts and add the ClusterIP service host if it doesn't exists
|
||||
hosts := canary.Spec.Service.Hosts
|
||||
var hasServiceHost bool
|
||||
for _, h := range hosts {
|
||||
if h == targetName || h == "*" {
|
||||
if h == apexName || h == "*" {
|
||||
hasServiceHost = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasServiceHost {
|
||||
hosts = append(hosts, targetName)
|
||||
hosts = append(hosts, apexName)
|
||||
}
|
||||
|
||||
// set gateways and add the mesh gateway if it doesn't exists
|
||||
@@ -132,8 +131,6 @@ func (ir *IstioRouter) reconcileVirtualService(canary *flaggerv1.Canary) error {
|
||||
}
|
||||
|
||||
// create destinations with primary weight 100% and canary weight 0%
|
||||
primaryName := fmt.Sprintf("%s-primary", targetName)
|
||||
canaryName := fmt.Sprintf("%s-canary", targetName)
|
||||
canaryRoute := []istiov1alpha3.DestinationWeight{
|
||||
makeDestination(canary, primaryName, 100),
|
||||
makeDestination(canary, canaryName, 0),
|
||||
@@ -181,12 +178,12 @@ func (ir *IstioRouter) reconcileVirtualService(canary *flaggerv1.Canary) error {
|
||||
}
|
||||
}
|
||||
|
||||
virtualService, err := ir.istioClient.NetworkingV1alpha3().VirtualServices(canary.Namespace).Get(targetName, metav1.GetOptions{})
|
||||
virtualService, err := ir.istioClient.NetworkingV1alpha3().VirtualServices(canary.Namespace).Get(apexName, metav1.GetOptions{})
|
||||
// insert
|
||||
if errors.IsNotFound(err) {
|
||||
virtualService = &istiov1alpha3.VirtualService{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: targetName,
|
||||
Name: apexName,
|
||||
Namespace: canary.Namespace,
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
*metav1.NewControllerRef(canary, schema.GroupVersionKind{
|
||||
@@ -200,7 +197,7 @@ func (ir *IstioRouter) reconcileVirtualService(canary *flaggerv1.Canary) error {
|
||||
}
|
||||
_, err = ir.istioClient.NetworkingV1alpha3().VirtualServices(canary.Namespace).Create(virtualService)
|
||||
if err != nil {
|
||||
return fmt.Errorf("VirtualService %s.%s create error %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("VirtualService %s.%s create error %v", apexName, canary.Namespace, err)
|
||||
}
|
||||
ir.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
|
||||
Infof("VirtualService %s.%s created", virtualService.GetName(), canary.Namespace)
|
||||
@@ -208,7 +205,7 @@ func (ir *IstioRouter) reconcileVirtualService(canary *flaggerv1.Canary) error {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("VirtualService %s.%s query error %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("VirtualService %s.%s query error %v", apexName, canary.Namespace, err)
|
||||
}
|
||||
|
||||
// update service but keep the original destination weights and mirror
|
||||
@@ -224,7 +221,7 @@ func (ir *IstioRouter) reconcileVirtualService(canary *flaggerv1.Canary) error {
|
||||
|
||||
_, err = ir.istioClient.NetworkingV1alpha3().VirtualServices(canary.Namespace).Update(vtClone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("VirtualService %s.%s update error %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("VirtualService %s.%s update error %v", apexName, canary.Namespace, err)
|
||||
}
|
||||
ir.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
|
||||
Infof("VirtualService %s.%s updated", virtualService.GetName(), canary.Namespace)
|
||||
@@ -241,22 +238,22 @@ func (ir *IstioRouter) GetRoutes(canary *flaggerv1.Canary) (
|
||||
mirrored bool,
|
||||
err error,
|
||||
) {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
apexName, primaryName, canaryName := canary.GetServiceNames()
|
||||
vs := &istiov1alpha3.VirtualService{}
|
||||
vs, err = ir.istioClient.NetworkingV1alpha3().VirtualServices(canary.Namespace).Get(targetName, metav1.GetOptions{})
|
||||
vs, err = ir.istioClient.NetworkingV1alpha3().VirtualServices(canary.Namespace).Get(apexName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
err = fmt.Errorf("VirtualService %s.%s not found", targetName, canary.Namespace)
|
||||
err = fmt.Errorf("VirtualService %s.%s not found", apexName, canary.Namespace)
|
||||
return
|
||||
}
|
||||
err = fmt.Errorf("VirtualService %s.%s query error %v", targetName, canary.Namespace, err)
|
||||
err = fmt.Errorf("VirtualService %s.%s query error %v", apexName, canary.Namespace, err)
|
||||
return
|
||||
}
|
||||
|
||||
var httpRoute istiov1alpha3.HTTPRoute
|
||||
for _, http := range vs.Spec.Http {
|
||||
for _, r := range http.Route {
|
||||
if r.Destination.Host == fmt.Sprintf("%s-canary", targetName) {
|
||||
if r.Destination.Host == canaryName {
|
||||
httpRoute = http
|
||||
break
|
||||
}
|
||||
@@ -264,10 +261,10 @@ func (ir *IstioRouter) GetRoutes(canary *flaggerv1.Canary) (
|
||||
}
|
||||
|
||||
for _, route := range httpRoute.Route {
|
||||
if route.Destination.Host == fmt.Sprintf("%s-primary", targetName) {
|
||||
if route.Destination.Host == primaryName {
|
||||
primaryWeight = route.Weight
|
||||
}
|
||||
if route.Destination.Host == fmt.Sprintf("%s-canary", targetName) {
|
||||
if route.Destination.Host == canaryName {
|
||||
canaryWeight = route.Weight
|
||||
}
|
||||
}
|
||||
@@ -277,7 +274,7 @@ func (ir *IstioRouter) GetRoutes(canary *flaggerv1.Canary) (
|
||||
|
||||
if primaryWeight == 0 && canaryWeight == 0 {
|
||||
err = fmt.Errorf("VirtualService %s.%s does not contain routes for %s-primary and %s-canary",
|
||||
targetName, canary.Namespace, targetName, targetName)
|
||||
apexName, canary.Namespace, apexName, apexName)
|
||||
}
|
||||
|
||||
return
|
||||
@@ -290,17 +287,15 @@ func (ir *IstioRouter) SetRoutes(
|
||||
canaryWeight int,
|
||||
mirrored bool,
|
||||
) error {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
primaryName := fmt.Sprintf("%s-primary", targetName)
|
||||
canaryName := fmt.Sprintf("%s-canary", targetName)
|
||||
apexName, primaryName, canaryName := canary.GetServiceNames()
|
||||
|
||||
vs, err := ir.istioClient.NetworkingV1alpha3().VirtualServices(canary.Namespace).Get(targetName, metav1.GetOptions{})
|
||||
vs, err := ir.istioClient.NetworkingV1alpha3().VirtualServices(canary.Namespace).Get(apexName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return fmt.Errorf("VirtualService %s.%s not found", targetName, canary.Namespace)
|
||||
return fmt.Errorf("VirtualService %s.%s not found", apexName, canary.Namespace)
|
||||
|
||||
}
|
||||
return fmt.Errorf("VirtualService %s.%s query error %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("VirtualService %s.%s query error %v", apexName, canary.Namespace, err)
|
||||
}
|
||||
|
||||
vsCopy := vs.DeepCopy()
|
||||
@@ -360,7 +355,7 @@ func (ir *IstioRouter) SetRoutes(
|
||||
|
||||
vs, err = ir.istioClient.NetworkingV1alpha3().VirtualServices(canary.Namespace).Update(vsCopy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("VirtualService %s.%s update failed: %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("VirtualService %s.%s update failed: %v", apexName, canary.Namespace, err)
|
||||
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -29,18 +29,16 @@ type KubernetesDeploymentRouter struct {
|
||||
|
||||
// Initialize creates the primary and canary services
|
||||
func (c *KubernetesDeploymentRouter) Initialize(canary *flaggerv1.Canary) error {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
primaryName := fmt.Sprintf("%s-primary", targetName)
|
||||
canaryName := fmt.Sprintf("%s-canary", targetName)
|
||||
_, primaryName, canaryName := canary.GetServiceNames()
|
||||
|
||||
// canary svc
|
||||
err := c.reconcileService(canary, canaryName, targetName)
|
||||
err := c.reconcileService(canary, canaryName, canary.Spec.TargetRef.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// primary svc
|
||||
err = c.reconcileService(canary, primaryName, primaryName)
|
||||
err = c.reconcileService(canary, primaryName, fmt.Sprintf("%s-primary", canary.Spec.TargetRef.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -50,11 +48,10 @@ func (c *KubernetesDeploymentRouter) Initialize(canary *flaggerv1.Canary) error
|
||||
|
||||
// Reconcile creates or updates the main service
|
||||
func (c *KubernetesDeploymentRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
primaryName := fmt.Sprintf("%s-primary", targetName)
|
||||
apexName, _, _ := canary.GetServiceNames()
|
||||
|
||||
// main svc
|
||||
err := c.reconcileService(canary, targetName, primaryName)
|
||||
err := c.reconcileService(canary, apexName, fmt.Sprintf("%s-primary", canary.Spec.TargetRef.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -70,7 +67,7 @@ func (c *KubernetesDeploymentRouter) GetRoutes(canary *flaggerv1.Canary) (primar
|
||||
return 0, 0, nil
|
||||
}
|
||||
|
||||
func (c *KubernetesDeploymentRouter) reconcileService(canary *flaggerv1.Canary, name string, target string) error {
|
||||
func (c *KubernetesDeploymentRouter) reconcileService(canary *flaggerv1.Canary, name string, podSelector string) error {
|
||||
portName := canary.Spec.Service.PortName
|
||||
if portName == "" {
|
||||
portName = "http"
|
||||
@@ -87,7 +84,7 @@ func (c *KubernetesDeploymentRouter) reconcileService(canary *flaggerv1.Canary,
|
||||
|
||||
svcSpec := corev1.ServiceSpec{
|
||||
Type: corev1.ServiceTypeClusterIP,
|
||||
Selector: map[string]string{c.labelSelector: target},
|
||||
Selector: map[string]string{c.labelSelector: podSelector},
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
Name: portName,
|
||||
|
||||
+17
-23
@@ -28,15 +28,13 @@ type SmiRouter struct {
|
||||
|
||||
// Reconcile creates or updates the SMI traffic split
|
||||
func (sr *SmiRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
canaryName := fmt.Sprintf("%s-canary", targetName)
|
||||
primaryName := fmt.Sprintf("%s-primary", targetName)
|
||||
apexName, primaryName, canaryName := canary.GetServiceNames()
|
||||
|
||||
var host string
|
||||
if len(canary.Spec.Service.Hosts) > 0 {
|
||||
host = canary.Spec.Service.Hosts[0]
|
||||
} else {
|
||||
host = targetName
|
||||
host = apexName
|
||||
}
|
||||
|
||||
tsSpec := smiv1.TrafficSplitSpec{
|
||||
@@ -53,12 +51,12 @@ func (sr *SmiRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
},
|
||||
}
|
||||
|
||||
ts, err := sr.smiClient.SplitV1alpha1().TrafficSplits(canary.Namespace).Get(targetName, metav1.GetOptions{})
|
||||
ts, err := sr.smiClient.SplitV1alpha1().TrafficSplits(canary.Namespace).Get(apexName, metav1.GetOptions{})
|
||||
// create traffic split
|
||||
if errors.IsNotFound(err) {
|
||||
t := &smiv1.TrafficSplit{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: targetName,
|
||||
Name: apexName,
|
||||
Namespace: canary.Namespace,
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
*metav1.NewControllerRef(canary, schema.GroupVersionKind{
|
||||
@@ -83,7 +81,7 @@ func (sr *SmiRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("traffic split %s query error %v", targetName, err)
|
||||
return fmt.Errorf("traffic split %s query error %v", apexName, err)
|
||||
}
|
||||
|
||||
// update traffic split
|
||||
@@ -93,11 +91,11 @@ func (sr *SmiRouter) Reconcile(canary *flaggerv1.Canary) error {
|
||||
|
||||
_, err := sr.smiClient.SplitV1alpha1().TrafficSplits(canary.Namespace).Update(tsClone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("TrafficSplit %s update error %v", targetName, err)
|
||||
return fmt.Errorf("TrafficSplit %s update error %v", apexName, err)
|
||||
}
|
||||
|
||||
sr.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
|
||||
Infof("TrafficSplit %s.%s updated", targetName, canary.Namespace)
|
||||
Infof("TrafficSplit %s.%s updated", apexName, canary.Namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -111,16 +109,14 @@ func (sr *SmiRouter) GetRoutes(canary *flaggerv1.Canary) (
|
||||
mirrored bool,
|
||||
err error,
|
||||
) {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
canaryName := fmt.Sprintf("%s-canary", targetName)
|
||||
primaryName := fmt.Sprintf("%s-primary", targetName)
|
||||
ts, err := sr.smiClient.SplitV1alpha1().TrafficSplits(canary.Namespace).Get(targetName, metav1.GetOptions{})
|
||||
apexName, primaryName, canaryName := canary.GetServiceNames()
|
||||
ts, err := sr.smiClient.SplitV1alpha1().TrafficSplits(canary.Namespace).Get(apexName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
err = fmt.Errorf("TrafficSplit %s.%s not found", targetName, canary.Namespace)
|
||||
err = fmt.Errorf("TrafficSplit %s.%s not found", apexName, canary.Namespace)
|
||||
return
|
||||
}
|
||||
err = fmt.Errorf("TrafficSplit %s.%s query error %v", targetName, canary.Namespace, err)
|
||||
err = fmt.Errorf("TrafficSplit %s.%s query error %v", apexName, canary.Namespace, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -136,7 +132,7 @@ func (sr *SmiRouter) GetRoutes(canary *flaggerv1.Canary) (
|
||||
|
||||
if primaryWeight == 0 && canaryWeight == 0 {
|
||||
err = fmt.Errorf("TrafficSplit %s.%s does not contain routes for %s and %s",
|
||||
targetName, canary.Namespace, primaryName, canaryName)
|
||||
apexName, canary.Namespace, primaryName, canaryName)
|
||||
}
|
||||
|
||||
mirrored = false
|
||||
@@ -151,16 +147,14 @@ func (sr *SmiRouter) SetRoutes(
|
||||
canaryWeight int,
|
||||
mirrored bool,
|
||||
) error {
|
||||
targetName := canary.Spec.TargetRef.Name
|
||||
canaryName := fmt.Sprintf("%s-canary", targetName)
|
||||
primaryName := fmt.Sprintf("%s-primary", targetName)
|
||||
ts, err := sr.smiClient.SplitV1alpha1().TrafficSplits(canary.Namespace).Get(targetName, metav1.GetOptions{})
|
||||
apexName, primaryName, canaryName := canary.GetServiceNames()
|
||||
ts, err := sr.smiClient.SplitV1alpha1().TrafficSplits(canary.Namespace).Get(apexName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return fmt.Errorf("TrafficSplit %s.%s not found", targetName, canary.Namespace)
|
||||
return fmt.Errorf("TrafficSplit %s.%s not found", apexName, canary.Namespace)
|
||||
|
||||
}
|
||||
return fmt.Errorf("TrafficSplit %s.%s query error %v", targetName, canary.Namespace, err)
|
||||
return fmt.Errorf("TrafficSplit %s.%s query error %v", apexName, canary.Namespace, err)
|
||||
}
|
||||
|
||||
backends := []smiv1.TrafficSplitBackend{
|
||||
@@ -179,7 +173,7 @@ func (sr *SmiRouter) SetRoutes(
|
||||
|
||||
_, err = sr.smiClient.SplitV1alpha1().TrafficSplits(canary.Namespace).Update(tsClone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("TrafficSplit %s update error %v", targetName, err)
|
||||
return fmt.Errorf("TrafficSplit %s update error %v", apexName, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -33,6 +33,7 @@ spec:
|
||||
service:
|
||||
port: 80
|
||||
targetPort: 9898
|
||||
name: podinfo-svc
|
||||
portDiscovery: true
|
||||
canaryAnalysis:
|
||||
interval: 15s
|
||||
@@ -55,13 +56,13 @@ spec:
|
||||
timeout: 10s
|
||||
metadata:
|
||||
type: bash
|
||||
cmd: "curl -sd 'test' http://podinfo-canary/token | grep token"
|
||||
cmd: "curl -sd 'test' http://podinfo-svc-canary/token | grep token"
|
||||
- name: load-test
|
||||
url: http://flagger-loadtester.test/
|
||||
timeout: 5s
|
||||
metadata:
|
||||
type: cmd
|
||||
cmd: "hey -z 10m -q 10 -c 2 http://podinfo-canary.test/"
|
||||
cmd: "hey -z 10m -q 10 -c 2 http://podinfo-svc-canary.test/"
|
||||
logCmdOutput: "true"
|
||||
EOF
|
||||
|
||||
|
||||
Reference in New Issue
Block a user